13.Zend Framework 2 et 3

13.6.Modèle MVC

13.6.3.MVC: Le contrôleur

13.6.3.5.Passage de paramètres et instanciation

13.6.3.5.1.Introduction

Si nous souhaitons passer des paramètres au contrôleur via le constructeur il faut comprendre comment s'effectue son instanciation.
Pour rappel, la description de la façon dont doit être instancié le contrôleur se fait par l'intermédiaire du tableau désigné par le mot clé controllers du fichier de configuration du framework module.config.php.
  • config
  • module
    • PHPFacile
      • config
        • module.config.php
      • src
      • view

13.6.3.5.2.Contrôleur "invocable"

Dans une approche simpliste comme celle que nous avons vu dans le chapitre sur le routage[où?] avec Zend Framework, le contrôleur n'a pas de constructeur ou son constructeur ne nécessite pas de passage de paramètre. On dit que le contrôleur est (directement) invocable (et donc en V.O dans le texte "invokable"). La façon de décrire ce type d'instanciation varie d'un squelette d'application Zend à l'autre (on peut donc considérer que le standard à changé).
<?php
namespace PHPFacile;

use Zend\ServiceManager\Factory\InvokableFactory;

// Extrait d'un fichier module.config.php limité à la clé "controllers"
return [
  'controllers' => [
    'factories' => [
      Controller\TestController::class => InvokableFactory::class
    ],
  ],
  // Suite de la configuration (masquée)
];
Avec la version 3 du squelette d'application, pour instancier un contrôleur "invocable", c'est dans la clé factories du tableau de configuration que l'on associe au contrôleur la classe Zend\ServiceManager\Factory\InvokableFactory. C'est cette dernière qui va instancier le contrôleur sans passer aucun paramètre au constructeur.
<?php
namespace PHPFacile;

// Extrait d'un fichier module.config.php limité à la clé "controllers"
return array(
  'controllers' => array(
    'invokables' => array(
      'PHPFacile\Controller\Test' => Controller\TestController:class
    ),
  ),
  // Suite de la configuration (masquée)
);
Avec les versions 2.4 et 2.5 du squelette d'application, pour instancier un contrôleur "invocable", c'est dans la clé invokables du tableau de configuration que l'on associe à l'alias du contrôleur le nom (version 2.4) ou la classe du contrôleur à instancier. Le framework s'occupant alors de l'instanciation.
<?php
// Extrait d'un fichier module.config.php limité à la clé "controllers"
return array(
  'controllers' => array(
    'invokables' => array(
      'PHPFacile\Controller\Test' => 'PHPFacile\Controller\TestController'
    ),
  ),
  // Suite de la configuration (masquée)
);
Avec les versions 2.4 et 2.5 du squelette d'application, pour instancier un contrôleur "invocable", c'est dans la clé invokables du tableau de configuration que l'on associe à l'alias du contrôleur le nom (version 2.4) ou la classe du contrôleur à instancier. Le framework s'occupant alors de l'instanciation.

13.6.3.5.3.Instanciation par une fabrique (factory)

Si les dernières bonnes pratiques nous invitent à explicitement faire appel à une "factory" (une "fabrique", autrement dit, une classe qui va instancier l'objet) quitte à ce que cette fabrique soit une simple "InvokableFactory", ce n'était pas l'option retenue dans les versions précédentes. Pour ces versions, nous nous devons, de vous indiquer que le contrôleur peut également être instancié par une "fabrique" en utilisant non plus le mot clé invokables mais factories.
<?php
namespace PHPFacile;

// Extrait d'un fichier module.config.php limité à la clé "controllers"
return [
  'controllers' => [
    'factories' => [
      Controller\TestController::class => Factory\TestControllerFactory::class
    ],
  ],
  // Suite de la configuration (masquée)
];
<?php
namespace PHPFacile;

// Extrait d'un fichier module.config.php limité à la clé "controllers"
return array(
  'controllers' => array(
    'factories' => array(
      'PHPFacile\Controller\Test' => Factory\TestControllerFactory::class
    ),
  ),
  // Suite de la configuration (masquée)
);
<?php
// Extrait d'un fichier module.config.php limité à la clé "controllers"
return array(
  'controllers' => array(
    'factories' => array(
      'PHPFacile\Controller\Test' => 'PHPFacile\Factory\TestControllerFactory'
    ),
  ),
  // Suite de la configuration (masquée)
);
Dans notre cas, via le fichier de configuration, nous avons précisé que pour instancier l'objet PHPFacile\Controller\TestControlleur (ou bien, pour les anciennes versions, lorsqu'il est demandé d'instancier le contrôleur identifié par l'alias PHPFacile\Controller\Test), il faut faire appel à la classe "personnalisée" PHPFacile\Factory\TestControllerFactory.
Il va de soit que pour que cela fonctionne, cette classe doit implémenter une interface donnée: en l'occurrence Zend\ServiceManager\FactoryInterface.
Pour respecter cette interface, la classe "factory" doit simplement implémenter la méthode createService(Zend\ServiceManager\ServiceLocatorInterface) qui doit retourner l'objet attendu (ici, le contrôleur). On aura donc quelque chose ressemblant à
<?php
namespace PHPFacile\Factory;

use PHPFacile\Controller\TestController;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class TestControllerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocatorInterface)
    {
        return new TestController();
    }
}
  • config
  • module
    • PHPFacile
      • config
      • src
        • Controller
          • TestController.php
        • Factory
          • TestControllerFactory.php
        • Model
      • view
  • config
  • module
    • PHPFacile
      • config
      • src
        • PHPFacile
          • Controller
            • TestController.php
          • Factory
            • TestControllerFactory.php
          • Model
      • view
rem
  • Là encore, comme dans les exemples des chapitres précédents, libre à vous de choisir l'espace de nom qui vous convient. Nous avons choisi de regrouper les classes "factories" dans un espace de nom "Factory" (sous l'espace "PHPFacile").
Puisque c'est nous (par l'intermédiaire de la classe "factory") qui gérons l'instanciation du contrôleur, nous pouvons lui passer des paramètres (même si ce n'est pas le cas dans l'exemple donné).
Mais c'est pas tout, mais c'est pas tout! Comme vous pouvez le voir à partir de l'interface, au moment de l'appel au "factory" le framework va communiquer un objet de type Zend\ServiceManager\ServiceLocatorInterface qui peut être fort utile.
Il peut notamment être utilisé pour faire appel à la configuration de l'application:
<?php
namespace PHPFacile\Factory;

use PHPFacile\Controller\TestController;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class TestControllerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocatorInterface)
    {
        $serviceLocator = $serviceLocatorInterface->getServiceLocator();

        $config = $serviceLocator->get('Config');
        $parametre = $config['masection']['monparametre'];

        return new TestController($parametre);
    }
}
  • config
    • autoload
      • global.php
      • local.php
  • module
    • PHPFacile
      • config
      • src
      • view
Généralement, cette partie de la configuration est stockée (sous forme de tableau) soit dans le fichier config/autoload/global.php soit (généralement de préférence) dans le fichier config/autoload/local.php. Un extrait de contenu de fichier de configuration correspondant à l'exemple donné précédemment ressemblerait à
<?php
return [
    'masection' => ['monparametre' => 'mavaleur']
];
<?php
return array(
    'masection' => array('monparametre' => 'mavaleur')
);
rem
  • Il est tout a fait possible (pour un environnemment de type ZSA 2.5 et inférieur) de déclarer dans le fichier de configuration, que certains contrôleurs sont des "invokables" et d'autres des "factories". Pour cela, il suffit d'avoir les 2 entrées dans le tableau "controllers".