Spryker Yves DependencyProvider依赖未生效问题排查
Spryker Yves层自定义DependencyProvider依赖装配失效问题排查
在Spryker项目Yves层开发时,自定义DependencyProvider未完成依赖装配,触发如下报错:
Spryker内核异常:Container中不存在被调用的"XXX",可通过在"ModuleNameDependencyProvider"中添加键"XXX"修复该问题。
当前提交的存在问题的DependencyProvider代码如下:
<?php use Pyz\Client\AddressAutocomplete\AddressAutocompleteClient; class ModuleNameDependencyProvider extends AbstractBundleDependencyProvider { public const MODULE_NAME_CLIENT = 'MODULE_NAME_CLIENT'; /** * @param Container $container * * @return Container * @throws FrozenServiceException */ public function provideServiceLayerDependencies(Container $container): Container { $container = $this->provideModuleNameClient($container); return $container; } /** * @throws FrozenServiceException */ public function provideModuleNameClient(Container $container): Container { $container->set(static::MODULE_NAME_CLIENT, function (Container $container) { return new ModuleNameClient(); }); return $container; } }
具体失效原因(按出现概率从高到低排序)
- 依赖注册方法重写错误,Yves层不会触发该方法执行
Spryker不同层的DependencyProvider有固定的注册入口,provideServiceLayerDependencies()是Zed层旧版本业务模型的依赖注册方法,Yves层启动流程完全不会调用该方法,写在这里的服务注册逻辑不会执行。Yves层模块的依赖注册需要重写provideYvesLayerDependencies(Container $container): Container方法,把服务注册逻辑放到该方法中才会被加载。 - 类加载相关配置错误
现有代码存在多处类识别问题:- 未声明当前类的命名空间,Yves模块的DependencyProvider合法命名空间应为
Pyz\Yves\模块名,缺省命名空间会导致类无法被Spryker自动加载逻辑识别 - 未引入依赖的核心类:包括继承用的Yves层抽象基类
Spryker\Yves\Kernel\AbstractBundleDependencyProvider、容器类Spryker\Service\Container\Container、异常类Spryker\Shared\Kernel\Exception\FrozenServiceException,会触发类找不到的致命错误 - 引入类和实际实例化类不匹配:代码use引入的是无关的
AddressAutocompleteClient,实际要实例化的ModuleNameClient没有写对应use语句,运行时会触发类不存在报错
- 未声明当前类的命名空间,Yves模块的DependencyProvider合法命名空间应为
- DependencyProvider未被加入Yves层依赖加载链
新增自定义模块需要满足Spryker的目录结构约定:DependencyProvider文件必须放在模块根目录下,文件名和类名完全一致(即文件名必须为ModuleNameDependencyProvider.php),同时模块要在Yves模块配置中开启,否则依赖扫描逻辑不会识别到该Provider。 - 服务键名不匹配
Container的键名大小写敏感,调用服务时传入的键名必须和注册时使用的self::MODULE_NAME_CLIENT常量值完全一致,大小写、下划线等任何字符不匹配都会触发服务不存在报错。 - 服务调用时机错误
不能在DependencyProvider执行完成前(比如类属性声明阶段、构造方法提前调用阶段)从Container取服务,此时服务还未完成注册,也会报服务不存在错误。
修正后的参考代码
<?php namespace Pyz\Yves\ModuleName; use Pyz\Client\ModuleName\ModuleNameClient; use Spryker\Yves\Kernel\AbstractBundleDependencyProvider; use Spryker\Service\Container\Container; use Spryker\Shared\Kernel\Exception\FrozenServiceException; class ModuleNameDependencyProvider extends AbstractBundleDependencyProvider { public const MODULE_NAME_CLIENT = 'MODULE_NAME_CLIENT'; /** * @param Container $container * * @return Container * @throws FrozenServiceException */ public function provideYvesLayerDependencies(Container $container): Container { $container = parent::provideYvesLayerDependencies($container); $container = $this->addModuleNameClient($container); return $container; } /** * @param Container $container * * @return Container */ protected function addModuleNameClient(Container $container): Container { $container->set(static::MODULE_NAME_CLIENT, function (Container $container) { // 推荐通过locator取客户端,自动完成客户端自身的依赖注入 return $container->getLocator()->moduleName()->client(); // 直接实例化需确保类已正确引入 // return new ModuleNameClient(); }); return $container; } }
内容的提问来源于stack exchange,提问作者Nikulin Vyacheslav
相关产品推荐
相关产品推荐

