2.3. Sous-classement

2.3.1. Introduction

Le Zend_Controller a été pensé dans un soucis permanent d'extensibilité, soit en faisant des sous-classes des classes existantes, soit en écrivant de nouvelles classes qui implémentent les interfaces Zend_Controller_Router_Interface et Zend_Controller_Dispatcher_Interface.

Les raisons possibles pour implémenter un nouveau routeur ou un nouvel aiguilleur peuvent être :

  • Le système existant de routage d'URI ne convient pas, par exemple lors de son intégration dans un site Web existant qui utilise déjà ses propres conventions de routage, qui ne s'accordent pas avec les mécanisme de routage fournis par le Framework Zend.

  • Vous avez besoin d'implémenter un routage pour quelque chose de complètement différent. La classe Zend_Controller_Router ne fonctionne qu'avec des URIs. Il est possible et préférable que vous vouliez utiliser le design pattern MVC pour développer un autre type de programme, comme une application en console. Dans le cas d'une application en console, un routeur personnalisé devrait traiter les arguments de la ligne de commande pour définir la route.

  • Le mécanisme fournit par le Zend_Controller_Dispatcher n'est pas approprié. La configuration par défaut suppose par convention que les contrôleurs sont des classes et les action, des méthodes de ces classes. Cependant, il existe beaucoup d'autres statégies pour le faire. Un exemple serait de faire correspondre un contrôleur à un répertoire, et les actions de ce contrôleur aux fichiers à l'intérieur de ces répertoires, au lieu d'appeller une méthode d'une classe, ceci pourrait permettre d'inclure un fichier d'un répertoire.

  • Vous souhaitez fournir des possibilités aditionnelles qui seront héritées par tous vos contrôleurs. Par exemple Zend_Controller_Action n'intègre pas Zend_View par défaut. Cependant, vous pourriez étendre votre propre contrôleur pour faire cela, et l'utiliser ne nécessiterait pas de modifier ni Zend_Controller_Router ni Zend_Controller_Dispatcher.

Soyez attentifs lorsque vous surchargez une part importante du système, en particulier l'aiguilleur. Un des avantages de Zend_Controller est qu'il établit des conventions communes pour la création d'applications. Si trop de ces comportements par défaut sont modifiés, un certain nombre de ces avantages seront perdus. Cependant, il y a de nombreux besoins différents, et une seule solution ne peut y répondre complètement, d'où la liberté fournie si besoin est.

2.3.2. Conventions

Lors d'un sous-classement d'une des classes du Zend_Controlleur, il est fortement recommandé de suivre ces conventions pour nommer ou enregistrer les fichiers. Suivre cette méthode vous assure qu'un autre développeur familier avec le Framework Zend sera capable de comprendre facilement votre projet.

2.3.2.1. Préfixage

Les classes inclues dans le Framework Zend suivent une convention ou chaque classe est préfixée par "Zend_". C'est le préfixe. Nous recommandons que toutes vos classes soient nommées de la même façon, c'est à dire si le nom de votre entreprise est Widget, Inc., le préfixe pourrait être "Widget_".

2.3.2.2. Arborescence des répertoires

Les classes Zend_Controller sont stockées dans le répertoire library comme ceci :

/library
  /Zend
    /Controller
      Action.php
      Dispatcher.php
      Router.php

En cas de sous-classement de Zend_Controller , il est recommandé que les nouvelles classes soient stockées dans une structure identique avec votre préfixe. Cela facilitera la recherche pour qui est chargé de relire le code de votre projet.

Par exemple, un projet de Widget, Inc. qui implémente uniquement un routeur personnalisé, l'arborescence ressemblerait à ceci :

/library
  /Zend
  /Widget
    /Controller
      Router.php
      README.txt

Veuillez noter que dans cet exemple, le répertoire Widget/Controller/ est la copie conforme du répertoire Zend/Controller/ lorsque c'est possible. Dans le cas présent, il fournit la classe Widget_Controller_Router, qui serait soit une sous-classe, soit un remplacement de Zend_Controller_Router implémentant Zend_Controller_Router_Interface.

Veuillez noter aussi que dans l'exemple ci-dessus, un fichier README.txt a été placé dans Widget/Controller/. Zend vous encourage fortement à documenter vos projets en proposant des tests séparés, et une documentation pour vos clients. Cependant, nous vous conseillons aussi de placer un simple fichier README.txt directement dans le répertoire pour expliquer brièvement vos changements, et leurs fonctionnements.

2.3.3. Interface de Routage

L'interface Zend_Controller_Router_Interface fournie une définition pour une seule méthode :

<?php
				
  /**				
   * @param  Zend_Controller_Dispatcher_Interface
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Dispatcher_Token|boolean
   */
  public function route(Zend_Controller_Dispatcher_Interface $dispatcher);

?>

Le routage n'a lieu qu'une seule fois : lorsque la requête est reçue en premier par le système. Le but de ce routeur est de générer un Zend_Controller_Dispatch_Token qui spécifie un contrôleur et une action qui lui est associée. Ceci est ensuite passé dans l'aiguilleur. S'il n'est pas possible de définir une route pour un jeton d'aiguillage (nonsenical route) alors un bouléen FALSE est retourné.

Certains routeurs peuvent traiter des éléments dynamiques et ont besoin d'un moyen pour déterminer si le jeton d'aiguillage généré est aiguillable avant de le retourner. Pour cette raison, le routeur reçoit un objet gestionnaire de l'aiguilleur comme unique argument de sa méthode route(). L'aiguilleur fournit une méthode de test isDispatchable().

2.3.4. Interface d'aiguillage

Zend_Controller_Front appelera premièrement le routeur pour recevoir le premier jeton d'aiguillage, qu'il passera à l'aiguilleur. L'aiguilleur aiguillera l'action (instancier le contrôleur, appeler son action) et retournera ensuite soit un bouléen, FALSE, soit un autre jeton d'aiguillage.

Zend_Controller_Front apelle l'aiguilleur continuellement, jusqu'à ce qu'un jeton d'aiguillage ne lui soit pas retourné. Ceci s'apelle la boucle d'aiguillage. Elle permet aux actions d'être traitées séquentiellement jusqu'à ce que toutes les tâches soient effectuées.

L'interface Zend_Controller_Dispatcher_Interface fournie des définitions pour les deux méthodes suivantes :

<?php
				
/**
 * @param  Zend_Controller_Dispatcher_Token $route
 * @return boolean
 */
public function isDispatchable(Zend_Controller_Dispatcher_Token $route);

?>

isDispatchable() vérifie si le jeton d'aiguillage est aiguillable. Si c'est le cas, elle retourne TRUE. Dans les autres cas, elle retourne FALSE. La définition de ce qui est aiguillable est laissée à la classe qui implémente l'interface. Dans le cas de l'implémentation par défaut Zend_Controller_Dispatcher, cela veut dire que le fichier contrôleur existe, la classe existe dans ce fichier, et que la méthode d'action existe dans cette classe.

<?php
			
/**
 * @param  Zend_Controller_Dispatcher_Token $route
 * @return Zend_Controller_Dispatcher_Token|boolean
 */
public function dispatch(Zend_Controller_Dispatcher_Token $route);

?>

La méthode dispatch() constitue l'endroit où le vrai travail s'effectue. Cette méthode doit exécuter l'action du contrôleur. Elle doit aussi retourner un jeton d'aiguillage, ou un bouléen, FALSE, pour indiquer qu'il n'y a plus de tâches à effectuer.