【问题标题】:ZF2 - ServiceManager dependencies into ControllersZF2 - ServiceManager 依赖于控制器
【发布时间】:2012-09-06 23:32:34
【问题描述】:

我正在尝试将我的测试版 DI 代码转换为 ZF2 的发布版本。 现在我一开始就摔倒了,似乎没有任何关于将东西注入控制器的文档,这让我认为在控制器中有依赖项是不正常的?

现在我只是在做一个var_dump('blah');exit; 只是为了尝试让一些代码运行...... 我已经尝试了很多事情,现在我希望这可以工作:

module.config.php

'controllers' => array(
    'invokables' => array(
        'indexController' => 'Application\Controller\IndexController',
    )
)

模块.php

public function getControllerConfig() {
    return array(
        'factories' => array(
            'indexController'    => function(ControllerManager $cm) {
                var_dump('blah');exit;
            },
        ),
    );
}

现在什么都没有发生,这很令人沮丧……我读过一些关于为每个控制器创建工厂的文章,但我有 33 个,我发现这非常疯狂和愚蠢……?

我要注入的是用于抓取/保存用户的 userMapper 之类的东西。因此 registerAction 使用 userMapper 在数据库中创建一个用户,当您尝试登录时,它使用 userMapper 检查那里是否有用户等。

【问题讨论】:

  • 你有没有找到一个可以接受的答案?我已经用我认为可能的解决方案更新了我的答案。

标签: php zend-framework2


【解决方案1】:

您可以在任何 Module.php 中轻松做到这一点

public function onBootstrap(\Zend\EventManager\EventInterface $e)
{
    $serviceManager = $e->getApplication()->getServiceManager();
    $myDependency = /*something*/;

    $controllerLoader = $serviceManager->get('ControllerLoader');
    $controllerLoader->addInitializer(function ($controller) use ($myDependency) {
        if (method_exists($instance, 'injectMyDependency')) {
            $controller->injectMyDependency($myDependency);
        }
    });
}

让需要依赖的控制器实现一个接口并检查控制器是否是该接口的实例然后设置它,而不只是检查方法是否存在......

【讨论】:

  • 酷,这东西看起来有点老套,而且在任何地方都没有提到......我想要做的不是一般的做事方式吗?就像使用 UserMapper 将新用户写入数据库一样。 $userMapper->register($user);例如
  • 啊,这里说要在你的控制器中添加一个方法来从 ServiceManager 中获取你想要的东西,就像 userMapper 是一个方法:getUserMapper() { $sm = $this->getServiceLocator() ; $this->userMapper = $sm->get('App\Model\UserMapper');} 之类的东西。如此处所述:zf2.readthedocs.org/en/latest/user-guide/…
  • 不应该是那种方式(onBootstrap)。还有一点是 ServiceManager 实际上是一个 ServiceLocator which sometimes is seen as an anti-pattern 或美化注册表。 ZF2 也可以让您避免这种情况。反正我有空的时候如果没人回复我就回来=P
  • @Keyne,这就是原则团队建议将 entityManager 注入控制器的方式...
  • @AndreasLinden 不管怎样,确实,你不应该在你的控制器中使用实体管理器,否则它会更像一个服务而不是一个控制器Controllerspresentation 层 的一部分,如果您遵循良好的做法,它不应该与 model 层 紧密耦合,而是您应该有一个 service-layer 并在那里注入 entity-manager。同样,给定的 service 将被注入到 controllers 中,并且只能使用它的接口。
【解决方案2】:

这里的问题是 'indexController' 被定义为可调用和工厂。我认为它首先检查可调用对象,所以当它找到它正在寻找的东西时,它永远不会尝试在工厂中运行代码。只需删除“invokables”数组中的条目。

我刚刚写了一篇关于这个主题的帖子。您可以使用闭包来完成,而不是为每个控制器创建一个单独的工厂类。如果依赖项是可调用的,或者使用选项数组轻松配置,则更容易,您只需要一个列出可以注入的类的数组即可。查看http://zendblog.shinymayhem.com/2013/09/using-servicemanager-as-inversion-of.html

【讨论】:

    【解决方案3】:

    下面是我注入任意类的初始化程序代码。 一开始很难掌握——要在实例化时自动注入控制器,你必须在 module.config.php 的“controllers”部分的“initializer”部分定义初始化程序——而不是在“service_manager”部分。基本上是为了创建对控制器和其余部分有效的通用“感知接口”——各自的初始化密钥对应该完全出现在这两个部分中......

    // module/SkeletonClassmapGenerator/Item/ImplementedItem/ImplementedItemInitializer.php
    
    namespace SkeletonClassmapGenerator\Item\ImplementedItem;
    
    use Zend\ServiceManager\InitializerInterface;
    use SkeletonClassmapGenerator\Provider\GenericInitializerTrait;
    
    class ImplementedItemInitializer implements InitializerInterface
    {
        static protected $T_NAMESPACE = __NAMESPACE__;
        static protected $T_CLASS = __CLASS__;
        use GenericInitializerTrait; 
    }
    

    那么对于特征(显然在所有初始化器之间共享)...

    // module/SkeletonClassmapGenerator/Provider/GenericInitializerTrait.php
    
    namespace SkeletonClassmapGenerator\Provider;
    
    use Zend\ServiceManager\ServiceLocatorInterface;
    
    trait GenericInitializerTrait
    {
        public function initialize($instance, ServiceLocatorInterface $serviceLocator)
        {       
           if (isset(static::$T_CLASS)&&(isset(static::$T_NAMESPACE))){
           $classname = explode('\\', static::$T_CLASS);        
           $class = end($classname);
           preg_match('/([\w]*)Initializer$/i', $class,$matches);
           $basename = $matches[1];
            if(is_subclass_of($instance,static::$T_NAMESPACE.'\\'.$basename.'AwareInterface')) {
                $sl = (method_exists($serviceLocator,'getServiceLocator'))?
                $serviceLocator->getServiceLocator():$serviceLocator;
                 $dependency  = $sl->get(static::$T_NAMESPACE.'\\'.$basename.'Interface');  // I use 'Interface' as postfix for Service Manager invokable names           
                 $instance->{'set'.$basename}($dependency);
                }
           }
       }
    

    }

    【讨论】:

      猜你喜欢
      • 2016-08-04
      • 2013-09-12
      • 1970-01-01
      • 2014-05-18
      • 2011-11-18
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      • 2013-02-02
      相关资源
      最近更新 更多