简体   繁体   中英

ZF2 - ServiceManager dependencies into Controllers

I'm attempting to convert my beta DI code to the release version of ZF2. Right now I'm falling over at the very start and there doesn't seem to be any sort of documentation about injecting stuff into the controllers which gets me to think that it's not normal to have dependencies in a controller?

Right now I'm just doing a var_dump('blah');exit; just to try and get some code to run... I've tried a number of things and right now I expected this to work:

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

Right now nothing is happening and it's pretty frustrating... I read something about creating Factories for each Controller but I have 33 and I find that quite insane and stupid... ?

What I'm trying to inject is stuff like a userMapper for grabbing/saving users. So the registerAction creates a user in the database using the userMapper and when you try to login it uses the userMapper to check if there is a user there etc.

The problem here is that 'indexController' is defined as both an invokable and a factory. I think it checks invokables first, so when it finds what it is looking for, it never attempts to run the code in the factory. Just remove the entry in the 'invokables' array.

I just wrote a post on this subject. Instead of creating a separate factory class for each controller, you can do it with closures. If the dependencies are invokable, or easily configured with an options array, it is even easier, all you need is an array listing the classes that can be injected. Check out http://zendblog.shinymayhem.com/2013/09/using-servicemanager-as-inversion-of.html

you can easily do it like this in any 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);
        }
    });
}

a bit cleaner would to let the controllers which need the dependency implement an interface and check if the controller is an instance of that interface and then set it, not just check if the method exists...

Below is my Initializer code to inject into an arbitrary class. It was sort of tricky at the beginning to grasp - to automagically inject into controller upon instantiation you have to define initializer in 'initializer' section of 'controllers' section of module.config.php - not in that of 'service_manager' section. Basically to create universal "Aware Interfaces" that will be effective for controllers and the rest - respective initializer keypairs should appear in both sections altogether...

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

Then for the trait (obviously shared among all initializers)...

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM