I. Prérequis

La version du Zend Framework 2 utilisée pour cet article est la 2.0.0RC02. L'utilisation du Zend Framework 2 nécessite au minimum la version 5.3.3 de PHP.

Zend Framework 2.0 RequirementsZend Framework 2.0 Requirements

II. Le router pour la console

Si le composant de console peut parfaitement gérer les interactions avec le terminal pour l'écriture de script, il peut également gérer votre application depuis le terminal. En effet, un objet de requête et un router sont implémentés pour gérer les interactions avec la console. Il est possible de définir des routes composées d'arguments pour la ligne de commande afin de piloter l'application. Ce nouveau fonctionnement particulièrement souple va permettre aux développeurs d'avoir une API disponible pour gérer ses actions ou tâches automatisées depuis la ligne de commande. Plus besoin de développement spécifique, votre application est prête à fonctionner depuis votre terminal.

Examinons le code de la fabrique du router afin de comprendre comment est gérée en interne la console :

Zend/Mvc/Service/RouterFactory.php

Sélectionnez
public function createService(ServiceLocatorInterface $serviceLocator, $cName = null, $rName = null)
{
    $config = $serviceLocator->get('Configuration';
    if(
         $rName === 'ConsoleRouter' ||
          ($cName === 'router' && Console::isConsole())
    ) {
        if(isset($config['console']) && isset($config['console']['router'])){
            $routerConfig = $config['console']['router'] ;
        } else {
            $routerConfig = array();
        }
        $router = ConsoleRouter::factory($routerConfig;
    } else {
        […]
    }
    return $router ;
}

Lors de la création du router, la fabrique vérifie si nous utilisons la console afin de pouvoir fabriquer le router qui lui correspond, de type Zend\Mvc\Router\Console\SimpleRouteStack. Nous remarquons que les routes correspondant à la console doivent être enregistrées sous la clé « [‘console'][‘routes'] ». Voici un exemple de configuration utilisant les routes pour la console :

module.config.php
Sélectionnez
return array(
    'console' => array(
        'router' => array(
            'routes' => array(
                'catch-all' => array(
                    'type' => 'catchall',
                    'options' => array(
                        'route' => '',
                        'defaults' => array(
                            'controller' => 'Application\Controller\Index',
                            'action'     => 'error',
                        ),
                    ),
                ),
                'cron-application' => array(
                    'type' => 'simple',
                    'options' => array(
                        'route' => '--run-cron-application=value',
                        'defaults' => array(
                            'controller' => 'Application\Controller\Index',
                            'action'     => 'cron',
                        ),
                    ),
                ),
            ),
        ),
    ),;

La configuration des routes utilise les arguments à utiliser lors du lancement du script. Examinons le router pour la console afin de voir comment se construisent les routes :

Zend/Mvc/Router/Console/SimpleRouteStack.php
Sélectionnez
protected function init()
{
    $routes = $this->routePluginManager;    
     foreach(array(
        'catchall' => __NAMESPACE__ . '\Catchall',
        'simple'   => __NAMESPACE__ . '\Simple',
    ) as $name => $class    ) {
        $routes->setInvokableClass($name, $class;
    };
}

L'initialisation du router nous apprend qu'il existe deux types de routes disponibles :

• Le type Simple qui permet de définir des arguments en ligne de commande qui serviront de route ;

• Le type Catchall qui se vérifie à chaque fois. Si vous définissez une route de type Catchall, elle doit être la dernière dans la pile afin de laisser les traitements spécifiques en premier et celle-là s'exécuter si aucun n'est trouvé.

L'ajout des routes depuis un tableau fait en réalité appel au contrôleur de base Zend\Mvc\Router\SimpleRouteStack que nous connaissons. Le seul point qui diffère est que les routes sont, par défaut, de type Simple si aucun type n'est défini:

Zend/Mvc/Router/Console/SimpleRouteStack.php

Sélectionnez
protected function routeFromArray($specs)
{
    […]
    if(!isset($specs['type'])) $specs['type'] = 'simple';
    $route = parent::routeFromArray($specs;
    […]
}

Une fois les routes ajoutées, la correspondance se fera en fonction de la comparaison des arguments : arguments obligatoires présents et nombre d'arguments. Il est donc possible de définir une liste d'arguments obligatoires avec d'autres qui ne le sont pas, par exemple :

Utilisation d'arguments facultatifs

Sélectionnez
return array(
    'console' => array(
        'router' => array(
            'routes' => array(
                'cron-application' => array(
                    'type' => 'simple',
                    'options' => array(
                        'route' => '--run-cron-application=value [--other=value]',
                            'defaults' => array(
                            'controller' => 'Application\Controller\Index',    
                        'action'     => 'cron',
                        ),
                    ),
                ),
            ),
        ),
    ),
    […];

Une fois nos routes configurées, il y a quelques modifications à apporter à nos modules et actions. Tout d'abord, nous pouvons gérer le cas où les arguments en ligne de commande ne correspondent à aucune route depuis l'interface Zend\ModuleManager\Feature\ConsoleUsageProviderInterface qui permet de fournir une méthode décrivant l'utilisation de la console depuis le module correspondant :

module.php

Sélectionnez
class Module implements ConsoleUsageProviderInterface
{
    […]
    public function getConsoleUsage(AdapterInterface $console)
    {
        return 'Use --run-cron-application=value.' . "\n";
    }
    [….]
}

Le descriptif fourni par la méthode « getConsoleUsage() » sera affiché dans le terminal si aucune route ne correspond :

Utilisation de mauvais argument

Sélectionnez
php index.php –unknow-arg
Zend Framework 2.0.0rc2 application.
Usage:
Use --run-cron-application=value.

Attention, pour notre exemple,la route de type Catchall a été supprimée. Si celle-ci est conservée, son couple contrôleur/action sera exécuté.

III. La vue pour la console

Maintenant que nous savons gérer l'aide en ligne de commande, voyons les modifications à apporter à nos actions pour interagir avec la console :

IndexController.php
Sélectionnez
class IndexController extends AbstractActionController
{
    public function cronAction()
    {
        $param = $this->getRequest()->getParam('cron'); // récupération du paramètre
        return new ConsoleModel(array(ConsoleModel::RESULT => 'ok'));
    }
}

Tout d'abord, il est possible de récupérer les valeurs de nos arguments depuis la méthode « getParam() » de l'objet de requête qui est de type Zend\Console\Request. Ensuite, la console utilise une vue de type Zend\View\Model\ConsoleModel. Cette vue est assez particulière car elle n'utilise qu'une variable correspondant à la clé « result » :

Zend/View/Model/ConsoleModel.php

Sélectionnez
class ConsoleModel extends ViewModel
{
    const RESULT = 'result' ;
    […]
    public function setResult($text)
    {
        $this->setVariable(self::RESULT, $text);
        return $this ;
    }
    public function getResult()
    {
        return $this->getVariable(self::RESULT) ;
    }
}

La vue n'utilisera que cette variable pour rendre la vue depuis la méthode « getResult() », comme nous le voyons depuis sa stratégie de rendu :

Zend/Mvc/View/Console/DefaultRenderingStrategy.php
Sélectionnez
public function render(MvcEvent $e)
{
    […]
    $responseText .= $result->getResult();
    $response->setContent(
        $response->getContent() . $responseText
    );
    […]
}

Comme il peut être un peu redondant de toujours créer une instance de l'objet ConsoleModel pour créer sa vue, la console bénéficie aussi de ses écouteurs préparateurs de vues. Pour plus d'informations sur la création et préparation des vues, reportezvous au chapitre consacré aux vues. En effet, ces écouteurs permettent de construire une vue depuis une chaine de caractère :

Zend/Mvc/View/Console.php

Sélectionnez
public function createViewModelFromString(MvcEvent $e)
{
    $result = $e->getResult();
    if (!is_string($result)) {
        return;
    }
    $model = new ConsoleModel ;
    $model->setVariable(ConsoleModel::RESULT, $result;
    $e->setResult($model;
}

Si l'action retourne une chaine de caractères, l'écouteur construit et peuple automatiquement la vue avec la bonne variable. Nous pouvons donc réécrire notre action sous la forme simple :

IndexController.php

Sélectionnez
class IndexController extends AbstractActionController
{
    public function cronAction()
    {
        $param = $this->getRequest()->getParam('cron';
        return ‘ok’ ;
    }
}

La console affichera cette instruction en sortie.

IV. Conclusion et ressources

Nous venons de voir l'utilisation de la console au sein de l'application et toutes les possibilités que celle-ci offre en redéfinissant ses propres écouteurs et types de vues, ainsi que ses propres objets de requête ou encore de router. La maitrise de la console et de ce qui l'entoure permettra aux développeurs d'optimiser la gestion de leurs scripts et tâches automatisées en ligne de commande.


Cet article est tiré en partie du livre "Au cœur de Zend Framework 2"livre "Au cœur de Zend Framework 2" disponible dans le début du quatrième trimestre de l'année 2012.