Ajouter un commentaire

Injecter les dépendances dans le constructeur des controleurs

Une petite bafouille pour me rappeler comment on injecte les dépendances dans le constructeur du contrôleur

Fonctionne sur ZF2 2.1.5+

Nous souhaitons avoir des dépendances obligatoires dans notre contrôleur... Pourquoi pas après tout ? Admettons que le contrôleur ne peut pas fonctionner si les dépendances manquent. Mais comment surcharger le constructeur alors que le contrôleur est instancié par l'application MVC ? On pourrait, bien sûr, hacker le code de l'application, mais ce n'est pas ce que nous voulons vraiment, n'est-ce pas ?

Les dépendances sont obligatoires dans notre contrôleur

// module/MyModule/src/MyModule/Controller/IndexController.php
<?php
namespace MyModule\Controller ;
use MyModule\Entity\DependencyAInterface ;
use MyModule\Form\DependencyBInterface ;
use Zend\Mvc\Controller\AbstractActionController ;

class IndexController extends AbstractActionController
{
    protected $dependencyA ;
    protected $dependencyB ;
    
    public function __construct(
        DependencyAInterface $depA,
        DependencyBInterface $debB
        )
    {
        $this->dependencyA = $depA ;
        $this->dependencyB = $depB ;
    }
    
    public function indexAction()
    {
        // just use $this->dependencyA and $this->dependencyB as normal
    }
}

Maintenant, nous avons besoin d'un Factory, pour pouvoir accéder au constructeur du contrôleur.

Créer le controller factory

// module/MyModule/src/MyModule/Factory/IndexControllerFactory.php
<?php
namespace MyModule\Factory ;
use MyModule\Controller\WriteController ;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface ;

class IndexControllerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        // cette ligne est obligatoire, même si elle paraît redondante
        $realServiceLocator = $serviceLocator->getServiceLocator() ;
        $entityDepA = $realServiceLocator->get('DependencyEntity') ;
        $formDepB = $realServiceLocator->get('FormElementManager')->get(DependencyForm') ;
        
        return new IndexController( // voici notre contrôleur
                $entityDepA,
                $formDepB
        ) ;
    }
} 

Et voilaaaa

Et nous avons injecté les dépendances dans le contrôleur sans coup férir.

C'est pas fini, maintenant, au tour du Service Manager

// module/MyModule/Module.php
<?php
// bref, on sait tous ce qu'il y a là
...
    public function getServiceConfig()
    {
        return array(
            'invokables' => array(
                'DependencyForm' => 'MyModule\Form\MyForm',
            ),
            'factories' => array(
                'DependencyEntity' => function($sm) {
                    // n'importe quoi comprenant les injections de dépendances, bien sûr
                    return $entity ;
                },
            ),
        ) ;
    }
...
}

Maintenant, comment dire à l'application qu'elle ne devrait plus utiliser le contrôleur tel quel mais qu'elle devrait utiliser le contrôleur qui a été instancié à partir de notre factory ?

Allez hop, voyons la configuration du module. On se souvient de la clé 'controllers' qui se trouve là et qui nous sert à déclarer nos contrôleurs mmmh ??? oui oui oui, exactement, c'est de ça qu'il s'agit...

La clé 'controllers'

On avait quelquechose comme ça dans cette clé :

// module/MyModule/config/module.config.php
<?php
return array(
    'controllers' => array(
        'invokables' => array(
            'ModuleController\Index' => 'MyModule\Controller\IndexController',
        ),
    ),
);

Maintenant, on veut utiliser la factory à la place

// module/MyModule/config/module.config.php
<?php
return array(
    'controllers' => array(
        'factories' => array(
            'ModuleController\Index' => 'MyModule\Factory\IndexControllerFactory',
        ),
    ),
);

Surtout, il faut bien veiller à réutiliser le même alias (ModuleController\Index). Comme ça, on n'aura pas à changer le routeur également...

Tadaaaa