ZF2 - ServiceManager与控制器的依赖关系

时间:2012-09-13 19:49:18

标签: php zend-framework2

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

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

module.config.php

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

Module.php

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

现在没有任何事情发生,而且非常令人沮丧......我读了一些关于为每个控制器创建工厂的内容,但我有33个,我发现这非常疯狂和愚蠢......?

我想要注入的东西就像用户抓取/保存用户一样。因此registerAction使用userMapper在数据库中创建用户,当您尝试登录时,使用userMapper检查是否有用户等。

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分: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);
        }
    });
}
有点清洁会让需要依赖的控制器实现一个接口并检查控制器是否是该接口的一个实例然后设置它,而不只是检查该方法是否存在...

答案 2 :(得分:0)

下面是我注入任意类的初始化代码。 在开始时有点棘手 - 在实例化时自动注入控制器你必须在module.config.php的'controllers'部分的'initializer'部分中定义初始化器 - 而不是'service_manager'部分。基本上创建通用的“Aware接口”,对控制器和其他部分都有效 - 相应的初始化密钥对应该完全出现在两个部分......

// 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);
            }
       }
   }

}