Contrôleurs d'action

Aides d'action (Helper)

Introduction

Les aides d'action permettent aux développeurs d'injecter, en cours d'exécution et/ou à la demande, des fonctionnalités dans tout contrôleur d'action qui étend Zend_Controller_Action. Le but des aides d'action est de minimiser la nécessité d'étendre le contrôleur d'action abstrait en y injectant des fonctionnalités communes de contrôleur d'action.

Il y a de nombreuses manières d'utiliser les aides d'action. Les aides d'action utilisent le système de gestionnaire ("Broker"), similaire aux gestionnaires vus pour les Zend_View_Helper, et les Zend_Controller_Plugin. Les aides d'action (comme les aides de vue Zend_View_Helper) peuvent être chargées et appelées à la demande, ou elles peuvent être instanciées au début de la requête ("bootstrap") ou au moment de la création des contrôleurs d'action ( init()). Pour mieux comprendre ceci, reportez vous à la section d'utilisation ci-dessous.

Initialisation des aides

Une aide peut être initialisée de plusieurs manières différentes, basées sur vos besoins aussi bien que la fonctionnalité de l'aide.

Le gestionnaire d'aide est stocké en tant que membre $_helper du Zend_Controller_Action ; utilisez le gestionnaire pour récupérer ou appeler les aides. Les méthodes pour faire ceci incluent :

  • L'utilisation explicite de getHelper(). Passez lui simplement un nom, et l'objet d'aide est retourné :

    1. $flashMessenger = $this->_helper->getHelper('FlashMessenger');
    2. $message = 'Nous avons fait quelquechose lors de la dernière requête';
    3. $flashMessenger->addMessage($message);
  • L'utilisation de la fonctionnalité __get() du gestionnaire d'aide et récupérez l'aide comme si elle était une propriété membre du gestionnaire :

    1. $flashMessenger = $this->_helper->FlashMessenger;
    2. $message = 'Nous avons fait quelquechose lors de la dernière requête';
    3. $flashMessenger->addMessage($message);
  • Enfin, la plupart des aides d'action implémente la méthode direct() qui va appeler une méthode spécifique par défaut dans l'aide. Dans l'exemple de FlashMessenger, ceci appelle addMessage() :

    1. $message = 'Nous avons fait quelquechose lors de la dernière requête';
    2. $this->_helper->FlashMessenger($message);

Note: Tous les exemples ci-dessus sont équivalents.

Vous pouvez vouloir aussi instancier les aides explicitement. Vous pourriez avoir besoin de ceci si vous utilisez l'aide hors du contexte du contrôleur d'action, ou si vous souhaitez fournir une aide au gestionnaire d'aides à utiliser pour une action quelconque. L'instanciation se fait comme toute autre classe PHP.

Le gestionnaire d'aide (Broker)

Zend_Controller_Action_HelperBroker gère les détails de l'enregistrement des objets d'aide et les chemins de ces aides, ainsi que la récupération des aides à la demande.

Pour enregistrer une aide dans le gestionnaire, utilisez addHelper :

  1. Zend_Controller_Action_HelperBroker::addHelper($helper);

Bien sûr, instancier et fournir des aides au gestionnaire est coûteux en temps et en ressource donc deux méthodes existent pour automatiser les choses légèrement : addPrefix() et addPath().

  • addPrefix() prend un préfixe de classe et l'utilise pour déterminer le chemin des dossiers dans lesquels les classes d'aides ont été définies. Ceci suppose que le préfixe de la classe respecte la convention de nommage de Zend Framework.

    1. // Ajoute les aides préfixées Mes_Action_Helpers dans Mes/Action/Helpers/
    2. Zend_Controller_Action_HelperBroker::addPrefix('Mes_Action_Helpers');
  • addPath() prend un répertoire en premier argument et un préfixe de classe en second (par défaut réglé à "Zend_Controller_Action_Helper"). Ceci vous permet de faire correspondre vos propres préfixes de classe à vos dossiers spécifiques.

    1. // Ajoute les aides préfixées avec Aide dans Plugins/Aides/
    2. Zend_Controller_Action_HelperBroker::addPath('./Plugins/Aides', 'Aide');

Puisque ces méthodes sont statiques, elles peuvent être appelées en tout point du déroulement du contrôleur pour ajouter dynamiquement les aides nécessaires.

En interne, le gestionnaire d'aide utilise une instance de PluginLoaderpour conserver les chemins. Vous pouvez récupérer le PluginLoader en utilisant la méthode statique getPluginLoader(), ou alternativement, injecter une instance personnalisée de PluginLoader en utilisant setPluginLoader().

Pour déterminer si une aide existe dans le gestionnaire d'aide, utilisez hasHelper($name), où $name est le nom raccourci de l'aide (sans le préfixe) :

  1. // Vérifie si l'aide 'redirector' est enregistrée dans le gestionnaire :
  2. if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
  3.     echo 'L\'aide Redirector est enregistrée';
  4. }

Il existe aussi deux méthodes statiques pour récupérer les aides issues du gestionnaire d'aide : getExistingHelper() et getStaticHelper(). getExistingHelper() récupérera une aide seulement si elle a précédemment été invoquée par ou explicitement enregistrée dans le gestionnaire d'aides; la méthode lèvera une exception sinon. getStaticHelper() réalise la même chose que getExistingHelper(), mais tentera d'instancier l'aide si elle n'a pas déjà été enregistrée dans la pile des aides. getStaticHelper() est un bon choix pour récupérer les aides que vous voulez configurer.

Les deux méthodes prennent un unique paramètre, $name, qui est le nom court de l'aide (c'est-à-dire sans le préfixe).

  1. // Vérifie si l'aide 'redirector' est enregistrée dans le gestionnaire,
  2. // et l'extrait :
  3. if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
  4.     $redirector =
  5.         Zend_Controller_Action_HelperBroker::getExistingHelper('redirector');
  6. }
  7.  
  8. // Ou, simplement le récupère, sans se soucier s'il a ou non été
  9. // enregistré précédemment :
  10. $redirector =
  11.     Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
  12. }

Enfin, pour effacer une aide enregistrée du gestionnaire, utilisez removeHelper($name), où $name est le nom raccourci de l'aide (sans le préfixe) :

  1. // Effacement conditionnel de l'aide 'redirector' du gestionnaire :
  2. if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
  3.     Zend_Controller_Action_HelperBroker::removeHelper('redirector')
  4. }

Aides d'action intégrées

Zend Framework inclue plusieurs aides d'action par défaut : AutoComplete pour des réponses automatiques à des auto-complétions AJAX ; ContextSwitch et AjaxContext pour distribuer des formats de réponse alternatifs pour vos actions ; FlashMessenger pour gérer des messages entre les sessions ; Redirector, qui fournit différentes implémentations pour rediriger vers des pages internes ou externes à votre application ; et ViewRenderer pour automatiser le processus de paramétrage de vos objets de vues dans votre contrôleur et du rendu de ces vues.

ActionStack

L'aide ActionStack vous permet d'empiler les requêtes dans le plugin de contrôleur frontal ActionStack, vous aidant effectivement à créer une liste d'actions à exécuter durant la requête. Cette aide vous permet d'ajouter des actions, soit en spécifiant de nouveaux objets de requêtes, soit en paramétrant action / controller / module.

Note: Invoquer l'aide ActionStack initialise le plugin ActionStack
L'appel de l'aide ActionStack enregistre implicitement le plugin ActionStack - ce qui veut dire que vous n'avez pas besoin d'enregistrer explicitement le plugin ActionStack pour utiliser cette fonctionnalité.

Example #1 Ajouter une tâche en utilisant une action, un contrôleur et un module

Souvent, il est plus simple de spécifier l'action, le contrôleur et le module (et optionnellement des paramètres de requêtes), comme vous le feriez en appelant Zend_Controller_Action::_forward() :

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function barAction()
  4.     {
  5.         // Ajoute deux actions à la pile
  6.  
  7.         // Ajoute un appel à /foo/baz/bar/baz (FooController::bazAction()
  8.         // avec une variable de requête bar == baz)
  9.         $this->_helper->actionStack('baz',
  10.                                     'foo',
  11.                                     'default',
  12.                                     array('bar' => 'baz'));
  13.  
  14.         // Ajoute un appel à /bar/bat
  15.         // (BarController::batAction())
  16.         $this->_helper->actionStack('bat', 'bar');
  17.     }
  18. }

Example #2 Ajouter une tâche en utilisant un objet de requête

Parfois la nature OO d'un objet de requête a plus de sens ; vous pouvez alors fournir l'objet à l'aide ActionStack.

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function barAction()
  4.     {
  5.         // Ajoute deux actions à la pile
  6.  
  7.         // Ajoute un appel à /foo/baz/bar/baz (FooController::bazAction()
  8.         // avec une variable de requête bar == baz)
  9.         $request = clone $this->getRequest();
  10.         // sans régler le contrôleur ou le module,
  11.         // utilise les valeurs courantes
  12.         $request->setActionName('baz')
  13.                 ->setParams(array('bar' => 'baz'));
  14.         $this->_helper->actionStack($request);
  15.  
  16.         // Ajoute un appel à /bar/bat
  17.         // (BarController::batAction())
  18.         $request = clone $this->getRequest();
  19.         // sans régler le module, utilise la valeur courante
  20.         $request->setActionName('bat')
  21.                 ->setControllerName('bar');
  22.         $this->_helper->actionStack($request);
  23.     }
  24. }

AutoComplete

Beaucoup de librairies javascript AJAX propose une fonctionnalité dite d'auto-complétion. Une liste de résultats possibles est chargée au fur et à mesure que l'utilisateur saisit. L'aide AutoComplete est destinée à simplifier le retour de ces valeurs vers la librairie Javascript.

Toutes les librairies JS n'implémentant pas l'auto-complétion de la même manière, l'aide AutoComplete propose une solution abstraite, ainsi que des implémentations concrètes pour certaines librairies. Les types de valeur de retour sont en général des tableaux de chaînes JSON, des tableaux de tableaux JSON (avec chaque membre étant un tableau associatif de métadonnées utilisées pour créer la liste de sélection), ou du HTML.

L'utilisation basique ressemble à ceci :

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function barAction()
  4.     {
  5.         // Ici du travail ....
  6.  
  7.         // Encode et envoie la réponse
  8.         $this->_helper->autoCompleteDojo($data);
  9.  
  10.         // Ou :
  11.         $response = $this->_helper
  12.                          ->autoCompleteDojo
  13.                          ->sendAutoCompletion($data);
  14.  
  15.         // Ou alors prépare simplement les données :
  16.         $response = $this->_helper
  17.                          ->autoCompleteDojo
  18.                          ->prepareAutoCompletion($data);
  19.     }
  20. }

Par défaut, l'auto-complétion :

  • Désactive les layouts et le ViewRenderer.

  • Affecte des en-têtes de réponse appropriés.

  • Remplit le corps de la réponse avec les données d'auto-complétion encodées/formatées.

  • Envoie la réponse.

Les méthodes disponibles sont :

  • disableLayouts() est utilisée pour désactiver les layouts et le ViewRenderer. Cette méthode est appelées par prepareAutoCompletion().

  • encodeJson($data, $keepLayouts = false) va encoder les données en JSON. Cette méthode est appelées par prepareAutoCompletion().

  • prepareAutoCompletion($data, $keepLayouts = false) prépare les données dans le format de réponse nécessaire à une implémentation concrète. La valeur de retour va changer en fonction de l'implémentation (de la librairie utilisée).

  • sendAutoCompletion($data, $keepLayouts = false) Va appeler prepareAutoCompletion(), puis envoyer la réponse.

  • direct($data, $sendNow = true, $keepLayouts = false) est une méthode utilisée par le gestionnaire d'aides (helper broker). La valeur de $sendNow va déterminer si c'est sendAutoCompletion() ou prepareAutoCompletion(), qui doit être appelée.

Actuellement, AutoComplete supporte les librairies AJAX Dojo et Scriptaculous.

AutoCompletion avec Dojo

Dojo n'a pas une fonctionnalité d'auto-complétion, mais deux : ComboBox et FilteringSelect. Dans les deux cas, elle demande une structure de données qui implémente QueryReadStore ; voyez la documentation de » dojo.data

Dans Zend Framework, vous pouvez passer un simple tableau indexé à l'aide AutoCompleteDojo, elle retournera une réponse JSON compatible avec la structure de données Dojo :

  1. // à l'intérieur d'une action de contrôleur :
  2. $this->_helper->autoCompleteDojo($data);

Example #3 AutoCompletion avec Dojo en utilisant MVC

L'auto-complétion avec Dojo via MVC requière plusieurs choses : générer un objet formulaire sur le ComboBox sur lequel vous voulez de l'auto-complétion, un contrôleur avec une action pour servir les résultats, la création d'un QueryReadStore à connecter à l'action et la génération du javascript à utiliser pour initialiser l'auto-complétion coté serveur.

Voyons le javascript nécessaire. Dojo est une librairie complète pour la création de javascript OO, un peu comme Zend Framework pour PHP. Il est possible de créer des pseudo-namespaces en utilisant l'arborescence des répertoires. Nous allons créer un répertoire "custom" au même niveau que le répertoire Dojo. A l'intérieur, nous allons créer un fichier javascript, TestNameReadStore.js, avec le contenu suivant :

  1. dojo.provide("custom.TestNameReadStore");
  2. dojo.declare("custom.TestNameReadStore",
  3.              dojox.data.QueryReadStore,
  4.              {
  5.              fetch:function (request) {
  6.                  request.serverQuery = { test:request.query.name };
  7.                  return this.inherited("fetch", arguments);
  8.              }
  9. });

Cette classe est une simple extension de QueryReadStore, qui est une classe abstraite. Nous définissons simplement une méthode de requête, et on lui assigne notre élément "test".

Ensuite, créons le formulaire sur lequel nous souhaitons une auto-complétion :

  1. class TestController extends Zend_Controller_Action
  2. {
  3.     protected $_form;
  4.  
  5.     public function getForm()
  6.     {
  7.         if (null === $this->_form) {
  8.             require_once 'Zend/Form.php';
  9.             $this->_form = new Zend_Form();
  10.             $this->_form->setMethod('get')
  11.                 ->setAction($this->getRequest()->getBaseUrl()
  12.                           . '/test/process')
  13.                 ->addElements(array(
  14.                     'test' => array('type' => 'text', 'options' => array(
  15.                         'filters'        => array('StringTrim'),
  16.                         'dojoType'       => array('dijit.form.ComboBox'),
  17.                         'store'          => 'testStore',
  18.                         'autoComplete'   => 'false',
  19.                         'hasDownArrow'   => 'true',
  20.                         'label' => 'Your input:',
  21.                     )),
  22.                     'go' => array('type' => 'submit',
  23.                                   'options' => array('label' => 'Go!'))
  24.                 ));
  25.         }
  26.         return $this->_form;
  27.     }
  28. }

Ici, nous créons simplement un formulaire avec des méthodes "test" et "go". La méthode "test" ajoute plusieurs attributs Dojo spéciaux : dojoType, store, autoComplete, et hasDownArrow. dojoType est utilisé pour indiquer la création d'une ComboBox, et nous allons la relier au conteneur de données ("store") de "testStore". Mettre "autoComplete" à FALSE dit à Dojo de ne pas sélectionner automatiquement la première valeur, mais de plutôt montrer une liste de valeurs possibles. Enfin, "hasDownArrow" crée une flèche bas comme sur les select box.

Ajoutons une méthode pour afficher le formulaire, et une entrée pour traiter l'auto-complétion :

  1. class TestController extends Zend_Controller_Action
  2. {
  3.     // ...
  4.  
  5.     /**
  6.      * Landing page
  7.      */
  8.     public function indexAction()
  9.     {
  10.         $this->view->form = $this->getForm();
  11.     }
  12.  
  13.     public function autocompleteAction()
  14.     {
  15.         if ('ajax' != $this->_getParam('format', false)) {
  16.             return $this->_helper->redirector('index');
  17.         }
  18.         if ($this->getRequest()->isPost()) {
  19.             return $this->_helper->redirector('index');
  20.         }
  21.  
  22.         $match = trim($this->getRequest()->getQuery('test', ''));
  23.  
  24.         $matches = array();
  25.         foreach ($this->getData() as $datum) {
  26.             if (0 === strpos($datum, $match)) {
  27.                 $matches[] = $datum;
  28.             }
  29.         }
  30.         $this->_helper->autoCompleteDojo($matches);
  31.     }
  32. }

Dans autocompleteAction(), nous vérifions que nous avons bien une requête post, et un paramètre "format" avec la valeur "ajax". Ensuite, nous vérifions la présence d'un paramètre "test", et le comparons avec nos données. ( getData() retourne des données quelconques). Enfin, nous envoyons nos résultats à notre aide AutoCompletion.

Voyons maintenant notre script de vue. Nous devons configurer notre entrepôt de données, puis rendre le formulaire, et s'assurer que les librairies Dojo appropriées sont bien chargées (ainsi que notre entrepôt). Voici le script de vue :

  1. <?php // configuration de l'entrepôt de données : ?>
  2. <div dojoType="custom.TestNameReadStore" jsId="testStore"
  3.     url="<?php echo $this->baseUrl() ?>/unit-test/autocomplete/format/ajax"
  4.     requestMethod="get"></div>
  5.  
  6. <?php // rendu du formulaire : ?>
  7. <?php echo $this->form ?>
  8.  
  9. <?php // configuration des CSS de Dojo dans le head HTML : ?>
  10. <?php $this->headStyle()->captureStart() ?>
  11. @import "<?php echo $this->baseUrl()
  12. ?>/javascript/dijit/themes/tundra/tundra.css";
  13. @import "<?php echo $this->baseUrl() ?>/javascript/dojo/resources/dojo.css";
  14. <?php $this->headStyle()->captureEnd() ?>
  15.  
  16. <?php // configuration de javascript pour charger
  17.       // les librairies Dojo dans le head HTML : ?>
  18. <?php $this->headScript()
  19.            ->setAllowArbitraryAttributes(true)
  20.            ->appendFile($this->baseUrl() . '/javascript/dojo/dojo.js',
  21.                         'text/javascript',
  22.                         array('djConfig' => 'parseOnLoad: true'))
  23.            ->captureStart() ?>
  24. djConfig.usePlainJson=true;
  25. dojo.registerModulePath("custom","../custom");
  26. dojo.require("dojo.parser");
  27. dojo.require("dojox.data.QueryReadStore");
  28. dojo.require("dijit.form.ComboBox");
  29. dojo.require("custom.TestNameReadStore");
  30. <?php $this->headScript()->captureEnd() ?>

Notez les appels aux aides de vue comme headStyle et headScript ; celles-ci sont des emplacements réservés, que nous pouvons ensuite utiliser pour effectuer le rendu dans la section "head" du HTML de votre script de layout.

Nous pouvons dès lors faire fonctionner l'auto-complétion Dojo.

AutoCompletion avec Scriptaculous

» Scriptaculous attend une réponse HTML dans un format spécifique.

Utilisez l'aide "AutoCompleteScriptaculous". Passez lui un tableau de données et l'aide créera une réponse HTML compatible avec "Ajax.Autocompleter".

ContextSwitch et AjaxContext

L'aide d'action ContextSwitch est destinée à faciliter le retour de différents formats de réponse à une requête.L'AjaxContext est une aide spécialisée de ContextSwitch qui permet le renvoi de réponses à XmlHttpRequest.

Pour l'activer, vous devez indiquer à votre contrôleur quelles actions répondent à quel contexte. Si une requête d'entrée indique un contexte valide pour une action, alors l'aide d'action en charge :

  • Va désactiver les layouts, si elles sont activées.

  • Va changer le suffixe de la vue à rendre, il faudra donc créer une vue par contexte.

  • Va envoyer les bons en-têtes de réponse en fonction du contexte désiré.

  • Va éventuellement en option appeler des fonctions pour configurer le contexte, ou des fonctions de post-processing.

Comme exemple, prenons le contrôleur suivant :

  1. class NewsController extends Zend_Controller_Action
  2. {
  3.     /**
  4.      * page d'arrivée; forward vers listAction()
  5.      */
  6.     public function indexAction()
  7.     {
  8.         $this->_forward('list');
  9.     }
  10.  
  11.     /**
  12.      * Liste les news
  13.      */
  14.     public function listAction()
  15.     {
  16.     }
  17.  
  18.     /**
  19.      * Affiche une new particulière
  20.      */
  21.     public function viewAction()
  22.     {
  23.     }
  24. }

Imaginons que nous voulions que listAction() soit aussi accessible au format XML. Plutôt que de créer une autre action, nous pouvons lui indiquer qu'elle doit retourner du XML :

  1. class NewsController extends Zend_Controller_Action
  2. {
  3.     public function init()
  4.     {
  5.         $contextSwitch = $this->_helper->getHelper('contextSwitch');
  6.         $contextSwitch->addActionContext('list', 'xml')
  7.                       ->initContext();
  8.     }
  9.  
  10.     // ...
  11. }

Ce code aura pour effet :

  • De changer le "Content-Type" de la réponse en "text/xml".

  • De changer le suffixe de vue vers "xml.phtml" (ou un autre suffixe si vous en utilisez un personnalisé "xml.[votre suffixe]").

Il est donc nécessaire de créer un nouveau script de vue, "news/list.xml.phtml", qui créera et rendra le XML.

Pour savoir si la requête doit utiliser un contexte switch, l'aide vérifie un jeton dans l'objet de requête. Par défaut, l'aide va chercher le paramètre de requête "format", ceci peut être changé. Ceci signifie que dans la plupart des cas, pour changer le contexte d'une réponse, il faut simplement injecter un paramètre "format" à la requête:

  • Via l'URL : /news/list/format/xml (le routeur par défaut utilise les paires clés et valeurs fournies après l'action)

  • Via un paramètre GET : /news/list?format=xml

ContextSwitch vous permet d'écrire des contextes, ceux-ci spécifient le suffixe de vue qui change, les en-têtes de réponse à modifier, et les fonctions de rappel éventuelles.

Contextes inclus par défaut

Par défaut, il existe 2 contextes dans l'aide ContextSwitch : json et xml.

  • JSON. Le contexte JSON met le "Content-Type" de la réponse à "application/json", et le suffixe de la vue est "json.phtml".

    Par défaut cependant, aucun script de vue n'est nécessaire, il va simplement sérialiser en JSON toutes les variables de vues, et les envoyer en tant que réponse.

    Ce comportement peut être désactivé en éteigant le paramètre de sérialisation JSON :

    1. $this->_helper->contextSwitch()->setAutoJsonSerialization(false);
  • XML. Le contexte XML met le "Content-Type" de la réponse à "text/xml", et utilise un suffixe de vue "xml.phtml". Vous devrez créer une nouvelle vue pour ce contexte.

Créer ses propres contextes

Vous pouvez créer vos propres contextes d'action. Par exemple pour retourner du YAML, du PHP sérialisé, ou encore du RSS ou du ATOM. ContextSwitch est là pour cela.

La manière la plus simple d'ajouter un nouveau contexte d'action est la méthode addContext(). Elle prend 2 paramètres : le nom du contexte, et un tableau d'options. Ce tableau d'option doit comporter au moins une des clés suivantes :

  • suffix : Le préfixe qui va s'ajouter au suffixe de vue. Il sera utiliser par le ViewRenderer.

  • headers : un tableau d'en-têtes et de valeurs que vous voulez ajouter à la réponse.

  • callbacks : un tableau dont les clés peuvent être "init" ou "post", et les valeurs représentent des noms de fonctions PHP valides, qui seront utilisées pour initialiser ou traiter la fin du contexte.

    Les fonctions d'initialisation interviennent lorsque le contexte est détecté par ContextSwitch. Par exemple dans le contexte intégré JSON, la fonction désactive le ViewRenderer lorsque la sérialisation automatique JSON est activée.

    Les fonctions de traitement de fin de contexte (Post processing) interviennent durant le processus de postDispatch() de l'action en cours. Par exemple pour le contexte intégré JSON, la fonction de post process regarde si la sérialisation automatique JSON est active, si c'est le cas, elle va sérialiser les variables de la vue en JSON, et envoyer la réponse ; mais dans le cas contraire, elle va réactiver le ViewRenderer.

Voici les méthodes d'interaction avec les contextes :

  • addContext($context, array $spec) : Ajoute un nouveau contexte. Si celui-ci existe déjà, une exception sera lancée.

  • setContext($context, array $spec) : Ajoute un nouveau contexte, mais écrase celui-ci s'il existait déjà. Utilise les mêmes spécifications que addContext().

  • addContexts(array $contexts) : Ajoute plusieurs contextes d'un coup. Le tableau $contexts doit être un tableau de paires contexte et specifications. Si un des contextes existe déjà, une exception est lancée.

  • setContexts(array $contexts) : Ajoute des nouveaux contextes, mais écrase ceux déjà présents éventuellement. Utilise les mêmes spécifications que addContexts().

  • hasContext($context) : retourne TRUE si le contexte existe déjà, FALSE sinon.

  • getContext($context) : retourne un contexte par son nom. Le retour est un tableau qui a la même syntaxe que celui utilisé par addContext().

  • getContexts() : retourne tous les contextes. Le tableau de retour est de la forme contexte => spécifications.

  • removeContext($context) : Supprime un contexte grâce à son nom. Retourne TRUE si réussi, FALSE si le contexte n'a pas été trouvé.

  • clearContexts() : Supprime tous les contextes.

Affecter des contextes par action

Il existe deux mécanismes pour créer et affecter des contextes. Vous pouvez créer des tableaux dans vos contrôleurs, ou utiliser plusieurs méthodes de ContextSwitch pour les assembler.

La méthode principale pour ajouter des contextes à des actions est addActionContext(). Elle attend 2 arguments, l'action et le contexte (ou un tableau de contextes). Par exemple, considérons la classe suivante :

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function listAction()
  4.     {
  5.     }
  6.  
  7.     public function viewAction()
  8.     {
  9.     }
  10.  
  11.     public function commentsAction()
  12.     {
  13.     }
  14.  
  15.     public function updateAction()
  16.     {
  17.     }
  18. }

Imaginons que nous voulions ajouter un contexte XML à l'action "list", et deux contextes XML et JSON à l'action "comments". Nous pourrions faire ceci dans la méthode init() :

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function init()
  4.     {
  5.         $this->_helper->contextSwitch()
  6.              ->addActionContext('list', 'xml')
  7.              ->addActionContext('comments', array('xml', 'json'))
  8.              ->initContext();
  9.     }
  10. }

De la même manière, il est aussi possible de simplement définir la propriété $contexts :

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public $contexts = array(
  4.         'list'     => array('xml'),
  5.         'comments' => array('xml', 'json')
  6.     );
  7.  
  8.     public function init()
  9.     {
  10.         $this->_helper->contextSwitch()->initContext();
  11.     }
  12. }

Cette syntaxe est simplement moins pratique et plus prompte aux erreurs.

Pour construire vos contextes, les méthodes suivantes vous seront utiles :

  • addActionContext($action, $context) : Ajoute un ou plusieurs contextes à une action. $context doit donc être une chaîne, ou un tableau de chaînes.

    Passer la valeur TRUE comme contexte marquera tous les contextes comme disponibles pour cette action.

    Une valeur vide pour $context désactivera tous les contextes donnés à cette action.

  • setActionContext($action, $context) : Marque un ou plusieurs contextes comme disponibles pour cette action. Si ceux-ci existent déjà, ils seront remplacés. $context doit être une chaîne ou un tableau de chaînes.

  • addActionContexts(array $contexts) : Ajoute plusieurs paires action et contexte en une fois. $contexts doit être un tableau associatif action et contexte. Cette méthode proxie vers addActionContext().

  • setActionContexts(array $contexts) : agit comme addActionContexts(), mais écrase les paires action et contexte existantes.

  • hasActionContext($action, $context) : détermine si une action possède un contexte donné.

  • getActionContexts($action = null) : Retourne tous les contextes d'une action donnée, si pas d'action passée, retourne alors toutes les paires action et contexte.

  • removeActionContext($action, $context) : Supprime un ou plusieurs contextes pour une action. $context doit être une chaîne ou un tableau de chaînes.

  • clearActionContexts($action = null) : Supprime tous les contextes d'une action. Si aucune action n'est spécifiée, supprime alors tous les contextes de toutes les actions.

Initialiser le Context Switch

Pour initialiser la permutation de contextes (contexte switching), vous devez appeler initContext() dans vos contrôleurs d'action :

  1. class NewsController extends Zend_Controller_Action
  2. {
  3.     public function init()
  4.     {
  5.         $this->_helper->contextSwitch()->initContext();
  6.     }
  7. }

Dans certains cas, vous voudriez forcer un contexte pour une action ; par exemple vous pouvez vouloir seulement le contexte XML si la permutation de contexte est active. Passez le alors à initContext() :

  1. $contextSwitch->initContext('xml');

Fonctionnalités avancées

Voici quelques méthodes qui peuvent être utilisées pour changer le comportement de l'aide ContextSwitch :

  • setAutoJsonSerialization($flag): Par défaut, le contexte JSON va sérialiser toute variable en notation JSON et les retourner en tant que réponse. Si vous voulez créer votre propre réponse, vous voudriez désactiver cet effet. Ceci doit être fait avant l'appel à initContext().

    1. $contextSwitch->setAutoJsonSerialization(false);
    2. $contextSwitch->initContext();

    Pour récupérer la valeur actuelle, utilisez getAutoJsonSerialization().

  • setSuffix($context, $suffix, $prependViewRendererSuffix) : Cette méthode permet de personnaliser le suffixe de vue d'un contexte. Le troisième argument indique si le suffixe actuel du ViewRenderer doit être utilisé comme préfixe de votre suffixe. Par défaut, c'est le cas.

    Passer une valeur vide au suffixe aura pour effet de n'utiliser que le suffixe du ViewRenderer.

  • addHeader($context, $header, $content) : Ajoute un en-tête à la réponse pour un contexte donné. $header est le nom de l'en-tête et $content sa valeur.

    Chaque contexte peut posséder plusieurs en-têtes, addHeader() ajoute des en-têtes dans une pile, pour un contexte donné.

    Si l'en-tête $header spécifié pour le contexte existe déjà, une exception sera alors levée.

  • setHeader($context, $header, $content) : setHeader() agit comme addHeader(), sauf qu'il va écraser un en-tête qui aurait déjà été présent.

  • addHeaders($context, array $headers) : Ajoute plusieurs en-têtes en une seule fois. Proxie vers addHeader().$headers est un tableau de paires header => contexte.

  • setHeaders($context, array $headers.) : comme addHeaders(), sauf que cette méthode proxie vers setHeader(), vous permettant d'écraser des en-têtes déjà présents.

  • getHeader($context, $header) : retourne une valeur d'en-tête pour un contexte. Retourne NULL si non trouvé.

  • removeHeader($context, $header) : supprime un en-tête d'un contexte.

  • clearHeaders($context, $header) : supprime tous les en-têtes d'un contexte.

  • setCallback($context, $trigger, $callback) : affecte une fonction de rappel (callback) pour un contexte. Le déclencheur peut être soit "init" ou "post" (la fonction de rappel sera appelée soit à l'initialisation du contexte, ou à la fin, en postDispatch). $callback doit être un nom de fonction PHP valide.

  • setCallbacks($context, array $callbacks) : affecte plusieurs fonctions de rappel pour un contexte. $callbacks doit être un tableau de paires trigger et callback. Actuellement, seules deux fonctions maximum peuvent être enregistrées car il n'existe que 2 déclencheurs (triggers) : "init" et "post".

  • getCallback($context, $trigger) : retourne un nom de fonction de rappel affectée à un contexte.

  • getCallbacks($context) : retourne un tableau de paires trigger et callback pour un contexte.

  • removeCallback($context, $trigger) : supprime une fonction de rappel d'un contexte.

  • clearCallbacks($context) : supprime toutes les fonctions de rappel d'un contexte.

  • setContextParam($name) : affecte le paramètre de requête à vérifier pour savoir si un contexte a été appelé. La valeur par défaut est "format".

    getContextParam() en retourne la valeur actuelle.

  • setAutoDisableLayout($flag) : Par défaut, les layouts sont désactivées lorsqu'un contexte intervient, ceci provient du fait que les layouts n'ont en théorie pas de signification particulière pour un contexte, mais plutôt pour une réponse 'normale'. Cependant si vous désirez utiliser les layouts pour des contexte, passez alors la valeur FALSE à setAutoDisableLayout(). Ceci devant être fait avant l'appel à initContext().

    Pour récupérer la valeur de ce paramètre, utilisez getAutoDisableLayout().

  • getCurrentContext() est utilisée pour savoir quel contexte a été détecté (si c'est le cas). Cette méthode retourne NULL si aucune permutation de contexte a été détectée, ou si elle est appelée avant initContext().

Fonctionnalité AjaxContext

L'aide AjaxContext étend l'aide de permutation de contexte ContextSwitch, donc toutes les fonctionnalités de ContextSwitch s'y retrouvent. Il y a cependant quelques différences :

Cette aide utilise une propriété de contrôleur d'action différente pour déterminer les contextes, $ajaxable. Vous pouvez avoir différents contextes utilisés avec les requêtes AJAX ou HTTP. Les différentes méthodes ActionContext() de AjaxContext vont écrire dans cette propriété.

De plus, cette aide ne sera déclenchée que si la requête répond au critère isXmlHttpRequest(). Donc même si le paramètre "format" est passée à la requête, il faut nécessairement que celle ci soit une requête XmlHttpRequest, sinon la permutation de contexte n'aura pas lieu.

Enfin, AjaxContext ajoute un contexte, HTML. Dans ce contexte, le suffixe de vue est "ajax.phtml". Il n'y a pas d'en-tête particulier ajouté à la réponse.

Example #4 Autoriser les actions à répondre aux requêtes AJAX

Dans l'exemple qui suit, nous autorisons les actions "view", "form", et "process" à répondre aux requêtes AJAX. Dans les actions, "view" et "form", nous retournerons des portions de HTML ; dans "process", nous retournerons du JSON.

  1. class CommentController extends Zend_Controller_Action
  2. {
  3.     public function init()
  4.     {
  5.         $ajaxContext = $this->_helper->getHelper('AjaxContext');
  6.         $ajaxContext->addActionContext('view', 'html')
  7.                     ->addActionContext('form', 'html')
  8.                     ->addActionContext('process', 'json')
  9.                     ->initContext();
  10.     }
  11.  
  12.     public function viewAction()
  13.     {
  14.         // Voir les commentaires.
  15.         // Quand le AjaxContext est détecté, il utilise le script de vue
  16.         // comment/view.ajax.phtml
  17.     }
  18.  
  19.     public function formAction()
  20.     {
  21.         // Rend les formulaire "ajoutez un commentaire".
  22.         // Lorsque le AjaxContext est détecté, il utilise le script de
  23.         // vue : comment/form.ajax.phtml
  24.     }
  25.  
  26.     public function processAction()
  27.     {
  28.         // Traite un commentaire
  29.         // Retourne les résultats sous forme JSON ; assignez simplement
  30.         // vos résultats comme variables de vues.
  31.     }
  32. }

Coté client, votre bibliothèque AJAX requêtera simplement "/comment/view", "/comment/form", et "/comment/process", en passant le paramètre "format" : "/comment/view/format/html", "/comment/form/format/html", "/comment/process/format/json". (Ceci fonctionne aussi avec "?format=json".)

Il est nécessaire que votre bibliothèque envoie l'en-tête "X-Requested-With: XmlHttpRequest", ce qui est en général le cas.

FlashMessenger

Introduction

L'aide FlashMessenger vous permet de fournir les messages dont l'utilisateur pourrait avoir besoin dans la requête suivante. Pour accomplir ceci, FlashMessenger utilise Zend_Session_Namespace pour stocker les messages à retrouver dans la prochaine requête. C'est généralement une bonne idée si vous planifiez d'utiliser Zend_Session ou Zend_Session_Namespace, que vous initialisez avec Zend_Session::start() dans votre fichier d'amorçage. (Reportez vous à la documentation de Zend_Sessionpour plus de détails sur son utilisation.)

Exemple d'utilisation basique

L'exemple ci-dessous vous montre l'utilisation du flash messenger dans sa forme la plus basique. Quand l'action /some/my est appelée, il ajoute le message "Sauvegarde réalisée !". Une requête suivante vers l'action /some/my-next-request le retrouvera (ainsi que le détruira).

  1. class SomeController extends Zend_Controller_Action
  2. {
  3.     /**
  4.      * FlashMessenger
  5.      *
  6.      * @var Zend_Controller_Action_Helper_FlashMessenger
  7.      */
  8.     protected $_flashMessenger = null;
  9.  
  10.     public function init()
  11.     {
  12.         $this->_flashMessenger = $this->_helper
  13.                                       ->getHelper('FlashMessenger');
  14.         $this->initView();
  15.     }
  16.  
  17.     public function myAction()
  18.     {
  19.         /**
  20.          * Méthode par défaut por obtenir l'instance de
  21.          * Zend_Controller_Action_Helper_FlashMessenger à la demande
  22.          */
  23.         $this->_flashMessenger->addMessage('Sauvegarde réalisée !');
  24.     }
  25.  
  26.     public function myNextRequestAction()
  27.     {
  28.         $this->view->messages = $this->_flashMessenger->getMessages();
  29.         $this->render();
  30.     }
  31. }

JSON

Les réponses JSON sont les réponses de choix dans une architecture de type AJAX qui attend des données structurées. JSON peut être immédiatement interprété du coté du client, ce qui rend la tâche plus simple et plus rapide.

L'aide d'action JSON effectue plusieurs traitements :

  • Désactive les layouts si elles sont activées.

  • Optionnellement, un tableau d'options en second argument de Zend_Json::encode(). Ce tableau d'options permet l'activation des layouts et l'encodage en utilisant Zend_Json_Expr.

    1. $this->_helper->json($data, array('enableJsonExprFinder' => true));
  • Désactive le ViewRenderer s'il est activé.

  • Envoie à la réponse un en-tête 'Content-Type' à application/json.

  • Par défaut, retourne immédiatement la réponse, sans attendre la fin de l'exécution de l'action.

Son utilisation est toute simple, appelez le depuis le gestionnaire d'aides (Broker), ou appelez une de ses méthodes encodeJson() ou sendJson() :

  1. class FooController extends Zend_Controller_Action
  2. {
  3.     public function barAction()
  4.     {
  5.         // Effectue des traitements ici ...
  6.         // Envoie la réponse JSON :
  7.         $this->_helper->json($data);
  8.  
  9.         // ou...
  10.         $this->_helper->json->sendJson($data);
  11.  
  12.         // ou retourne la chaine json:
  13.         $json = $this->_helper->json->encodeJson($data);
  14.     }
  15. }

Note: Conserver les Layouts
Si vous avez besoin des layouts séparés pour les réponses JSON, pour par exemple générer vos réponses JSON dans un contexte particulier, chaque méthode de l'aide JSON accepte un second paramètre booléen. A TRUE, les layouts resteront activées :

  1. $this->_helper->json($data, true);
Optionnellement, vous pouvez fournir un tableau en tant que second paramètre. Ce tableau peut conftenir une variété d'options, incluant l'option keepLayouts :
  1. $this->_helper->json($data, array('keepLayouts' => true);

Note: Activer l'encodage en utilisant Zend_Json_Expr
Zend_Json::encode() permet l'encodage des expressions JSON natives en utilisant des objets Zend_Json_Expr. Cette option est désactivée par défaut. Pour l'activer, fournissez la valeur booléenne TRUE à l'option enableJsonExprFinder :

  1. $this->_helper->json($data, array('enableJsonExprFinder' => true);
Si vous souhaitez faire ceci, vous devez un tableau en tant que second argument. Ceci vous permet aussi de combiner avec les autres options, comme l'option keepLayouts. Toutes ces options sont alors fournies à Zend_Json::encode().
  1. $this->_helper->json($data, array(
  2.     'enableJsonExprFinder' => true,
  3.     'keepLayouts'          => true,
  4. ));

Redirector

Introduction

L'aide Redirector vous permet d'utiliser un objet de redirection qui remplit tous les besoins de votre application, nécessaires à une redirection vers une nouvelle URL. Il fournit de nombreux avantages par rapport à la méthode _redirect(), comme la capacité de préconfigurer le comportement du site dans l'objet Redirector ou d'utiliser l'interface intégrée gotoSimple($action, $controller, $module, $params) similaire à Zend_Controller_Action::_forward().

Redirector possède une certain nombre de méthodes qui peuvent être utilisées pour affecter le comportement de la redirection :

  • setCode() peut être utilisée pour paramétrer le code HTTP de la réponse à utiliser pendant la redirection.

  • setExit() peut être utilisée pour forcer un exit() juste après la redirection. Par défaut ceci vaut TRUE.

  • setGotoSimple() peut être utilisée pour paramétrer l'URL par défaut à utiliser si aucune n'est fournie à gotoSimple(). Elle utilise les API de Zend_Controller_Action::_forward() : setGotoSimple($action, $controller = null, $module = null, array $params = array());

  • setGotoRoute() peut être utilisée pour paramétrer une URL basée sur une route enregistrée. Fournissez un tableau de paires clé/valeur et une route nommée, et elle assemblera une URL suivant le type de la route et sa définition.

  • setGotoUrl() peut être utilisée pour paramétrer l'URL par défaut à utiliser si aucune n'est fournie à gotoUrl(). Accepte une chaîne unique correspondant à une URL.

  • setPrependBase() peut être utilisée pour ajouter une chaîne au début de l'URL de base de l'objet requête pour les URLs spécifiées avec setGotoUrl(), gotoUrl(), ou gotoUrlAndExit().

  • setUseAbsoluteUri() peut être utilisée pour forcer le Redirector à utiliser des URI absolus pour la redirection. Quand cette option est choisie, elle utilise les valeurs de $_SERVER['HTTP_HOST'], $_SERVER['SERVER_PORT'], et $_SERVER['HTTPS'] pour former un URI complet à partir de l'URL spécifiée par une des méthodes de redirection. Cette option est inactive par défaut, mais pourra être activée par défaut dans les prochaines releases.

De plus, il y a une variété de méthodes dans le Redirector pour réaliser les redirections actuelles :

  • gotoSimple() utilise setGotoSimple() (API de type _forward()) pour construire une URL et réaliser une redirection.

  • gotoRoute() utilise setGotoRoute() (assemblage de route) pour construire une URL et réaliser une redirection.

  • gotoUrl() utilise setGotoUrl() (URL sous forme de chaîne) pour construire une URL et réaliser une redirection.

Enfin, vous pouvez déterminer l'URL de la redirection courante à tout moment en utilisant getRedirectUrl().

Exemples d'utilisation basique

Example #5 Options de réglage

Cet exemple surcharge de multiples options, incluant le réglage du code de statut HTTP à utiliser dans la redirection ("303"), le retrait du exit par défaut après la redirection, et la définition d'une URL par défaut à utiliser lors d'une redirection.

  1. class SomeController extends Zend_Controller_Action
  2. {
  3.     /**
  4.      * Redirector - défini pour l'auto-complétion
  5.      *
  6.      * @var Zend_Controller_Action_Helper_Redirector
  7.      */
  8.     protected $_redirector = null;
  9.  
  10.     public function init()
  11.     {
  12.         $this->_redirector = $this->_helper->getHelper('Redirector');
  13.  
  14.         // Régle les options par défaut pour le redirector
  15.         // Puisque l'objet est enregistré dans le gestionnaire d'aide,
  16.         // ceci sera effectif pour toutes les actions réalisées après
  17.         // ce point
  18.         $this->_redirector->setCode(303)
  19.                           ->setExit(false)
  20.                           ->setGotoSimple("this-action", "some-controller");
  21.     }
  22.  
  23.     public function myAction()
  24.     {
  25.         /* Faire quelquechose */
  26.  
  27.         // Redirige vers une URL enregistrée précédemment,
  28.         // et force une sortie pour finir
  29.         $this->_redirector->redirectAndExit();
  30.         return; // jamais atteint
  31.     }
  32. }

Example #6 Utiliser les valeurs par défaut

Cet exemple suppose que vous utilisez les paramètres par défaut, ce qui inclut que toute redirection sera suivie d'un exit() immédiat.

  1. // EXEMPLE ALTERNATIF
  2. class AlternativeController extends Zend_Controller_Action
  3. {
  4.     /**
  5.      * Redirector - défini pour l'auto-complétion
  6.      *
  7.      * @var Zend_Controller_Action_Helper_Redirector
  8.      */
  9.     protected $_redirector = null;
  10.  
  11.     public function init()
  12.     {
  13.         $this->_redirector = $this->_helper->getHelper('Redirector');
  14.     }
  15.  
  16.     public function myAction()
  17.     {
  18.         /* Faire quelquechose */
  19.  
  20.         $url = '/my-controller/my-action/param1/test/param2/test2';
  21.         $this->_redirector->gotoUrl($url);
  22.         return;
  23.         // jamais atteint puisque les paramètres par défaut
  24.         // sont à goto et exit
  25.     }
  26. }

Example #7 Utilisation de l'API _forward() de goto()

L'API de gotoSimple() imite celle de Zend_Controller_Action::_forward(). La différence principale est qu'elle construit une URL à partir des paramètres fournis, et du format de route par défaut :module/:controller/:action/* du routeur. Il réalise alors une redirection au lieu d'enchaîner l'action.

  1. class ForwardController extends Zend_Controller_Action
  2. {
  3.     /**
  4.      * Redirector - défini pour l'auto-complétion
  5.      *
  6.      * @var Zend_Controller_Action_Helper_Redirector
  7.      */
  8.     protected $_redirector = null;
  9.  
  10.     public function init()
  11.     {
  12.         $this->_redirector = $this->_helper->getHelper('Redirector');
  13.     }
  14.  
  15.     public function myAction()
  16.     {
  17.         /* Faire quelquechose */
  18.  
  19.         // Redirige vers 'my-action' de 'my-controller' dans le module
  20.         // courant en utilisant les paramètres :
  21.         // param1 => test et param2 => test2
  22.         $this->_redirector->gotoSimple('my-action',
  23.                                        'my-controller',
  24.                                        null,
  25.                                        array('param1' => 'test',
  26.                                              'param2' => 'test2'));
  27.     }
  28. }

Example #8 Utilisation de l'assemblage de la route avec gotoRoute()

L'exemple suivant utilise la méthode assemble() du routeurpour créer une URL basée sur un tableau associatif de paramètres fournis. Il suppose que la route suivante a été enregistrée :

  1. $route = new Zend_Controller_Router_Route(
  2.     'blog/:year/:month/:day/:id',
  3.     array('controller' => 'archive',
  4.           'module' => 'blog',
  5.           'action' => 'view')
  6. );
  7. $router->addRoute('blogArchive', $route);

En donnant un tableau avec l'année réglée à 2006, le mois à 4, le jour à 24 et l'ID à 42, il construira l'URL /blog/2006/4/24/42.

  1. class BlogAdminController extends Zend_Controller_Action
  2. {
  3.     /**
  4.      * Redirector - défini pour l'auto-complétion
  5.      *
  6.      * @var Zend_Controller_Action_Helper_Redirector
  7.      */
  8.     protected $_redirector = null;
  9.  
  10.     public function init()
  11.     {
  12.         $this->_redirector = $this->_helper->getHelper('Redirector');
  13.     }
  14.  
  15.     public function returnAction()
  16.     {
  17.         /* Faire quelquechose */
  18.  
  19.         // Redirige vers les archives de blog. Construit l'URL suivante:
  20.         // /blog/2006/4/24/42
  21.         $this->_redirector->gotoRoute(
  22.             array('year' => 2006, 'month' => 4, 'day' => 24, 'id' => 42),
  23.             'blogArchive'
  24.         );
  25.     }
  26. }

ViewRenderer

Introduction

L'aide ViewRenderer apporte les comportements suivants :

  • Élimine le besoin d'instancier un objet de vue dans ses contrôleurs. Ceci devient automatique.

  • Configure automatiquement les chemins vers les scripts de vue, les aides, et les filtres, en se basant sur le module actuel et associe le nom du module comme préfixe de classe pour les aides et les filtres.

  • Créer un objet de vue général accessible pour tous les contrôleurs et donc pour toutes les actions disptachées.

  • Autorise le développeur à personnaliser les options de rendu de la vue.

  • Donne la possibilité de rendre automatiquement un script de vue.

  • Donne accès aux paramètres configurant le chemin de base (base path) et le chemin des scripts (script path), de la vue.

Note: Su vous utilisez _forward(), redirect(), ou render() manuellement, le rendu automatique sera annulé car ViewRenderer saura que vous prenez la main.

Note: Le ViewRenderer est activé par défaut dans le contrôleur frontal. Pour le désactiver, utilisez le paramètre noViewRenderer ($front->setParam('noViewRenderer', true)) ou retirez l'objet du gestionnaire d'aides ( Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer')).
Si vous voulez modifier un paramètre du ViewRenderer avant la distribution du contrôleur frontal, il existe deux moyens :

  • Instanciez et enregistrez votre propre objet ViewRenderer et passez le au gestionnaire d'aides :

    1. $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
    2. $viewRenderer->setView($view)
    3.              ->setViewSuffix('php');
    4. Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
  • Initialisez et/ou récupérez l'objet ViewRenderer via le gestionnaire d'aides :

    1. $viewRenderer =
    2.     Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    3. $viewRenderer->setView($view)
    4.              ->setViewSuffix('php');

API

L'usage le plus banal consiste à instancier et passer l'objet ViewRenderer au gestionnaire d'aides. La manière la plus simple est d'utiliser la méthode statique getStaticHelper() du gestionnaire, qui s'occupe de tout ceci en une passe :

  1. Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

La première action demandée instancie ou récupère l'objet de vue. A chaque instanciation de contrôleur, la méthode init() de l'objet ViewRenderer est appelée. Elle va configurer la vue et appeler addScriptPath() avec un chemin relatif au dossier courant. Ceci a pour effet de "namespacer" toutes les aides et les filtres de vue pour le module en cours.

A chaque postDispatch() d'action, render() est appelée.

Voici un exemple :

  1. // Bar controller , module foo :
  2. class Foo_BarController extends Zend_Controller_Action
  3. {
  4.     // Rend bar/index.phtml par défaut; rien à faire c'est automatique
  5.     public function indexAction()
  6.     {
  7.     }
  8.  
  9.     // Rend bar/populate.phtml avec une variable 'foo' à la valeur 'bar'.
  10.     // l'objet de vue est défini dans le preDispatch(), il est donc
  11.     // accessible.
  12.     public function populateAction()
  13.     {
  14.         $this->view->foo = 'bar';
  15.     }
  16. }
  17.  
  18. ...
  19.  
  20. // Dans un des scripts de vue :
  21. $this->foo(); // appelle Foo_View_Helper_Foo::foo()

Le ViewRenderer définit de même des accesseurs pour configurer la vue qu'il encapsule :

  • setView($view) Passage de l'objet de vue. Il devient accessible comme une propriété publique de l'objet : $view.

  • setNeverRender($flag = true) peut être utilisée pour désactiver le rendu automatique de la vue dans tous les contrôleurs. postDispatch() est alors court-circuitée. getNeverRender() retourne ce paramètre.

  • setNoRender($flag = true) peut être utilisée pour désactiver le rendu automatique de la vue dans le contrôleur actuel. postDispatch() est alors court-circuitée, mais preDispatch() réactive le paramètre pour l'action suivante. getNoRender() retourne cette option.

  • setNoController($flag = true) est utilisée pour spécifier à render() de ne pas chercher le script de vue dans le sous répertoire après le contrôleur (correspondant à l'action). Par défaut, cette recherche est effectuée. getNoController() retourne ce paramètre.

  • setNeverController($flag = true) fonctionne de manière similaire à setNoController(), mais pour tous les contrôleurs. getNeverController() est l'autre accesseur.

  • setScriptAction($name) peut être utilisée pour spécifier le script de vue d'une action à rendre. $name doit être le nom de l'action sans le suffixe (et sans le nom du contrôleur sauf si noController a été activé). Si vous n'utilisez pas cette méthode elle cherchera le script de vue correspondant au nom de l'action en cours (issue de l'objet de requête). getScriptAction() retourne la valeur actuelle de ce paramètre.

  • setResponseSegment($name) dit dans quel segment de la réponse rendre le script. Par défaut, la vue est rendue dans le segment par défaut. getResponseSegment() retourne cette valeur.

  • initView($path, $prefix, $options) doit être appelée pour configurer la vue : son "base path", le préfixe de classe pour les filtres et aides, et des options matérialisées par : neverRender, noRender, noController, scriptAction, et responseSegment.

  • setRender($action = null, $name = null, $noController = false) vous permet de spécifier les paramètres scriptAction, responseSegment, et noController en une fois. direct() est un alias qui permet un appel rapide depuis le contrôleur :

    1. // Rend 'foo' au lieu du script correspondant à l'action courante
    2. $this->_helper->viewRenderer('foo');
    3.  
    4. // rend form.phtml dans le segment 'html' de la réponse sans utiliser le
    5. // sous repertoire contrôleur pour chercher le script de vue :
    6. $this->_helper->viewRenderer('form', 'html', true);

    Note: setRender() et direct() ne rendent pas un script de vue à proprement parler, mais elles notifient au postDispatch() de le faire.

Le constructeur de ViewRenderer accepte aussi un objet de vue et un tableau d'options, de la même manière que initView() :

  1. $view    = new Zend_View(array('encoding' => 'UTF-8'));
  2. $options = array('noController' => true, 'neverRender' => true);
  3. $viewRenderer =
  4.     new Zend_Controller_Action_Helper_ViewRenderer($view, $options);

Il est aussi possible de personnaliser les chemins utilisés pour déterminer le base path (chemin de base) de la vue ainsi que le script path (chemin vers les scripts de vue). Des méthodes le permettent, utilisez les options suivantes avec :

  • :moduleDir représente le module courant (par convention le dossier parent au dossier contrôleur).

  • :module pointe vers le module actuel.

  • :controller pointe vers le contrôleur actuel.

  • :action représente l'action actuellement traitée.

  • :suffix est utilisée pour le suffixe du script de vue. setViewSuffix() permet aussi de le modifier.

Toutes ces options s'utilisent avec les méthodes ci-après :

  • setViewBasePathSpec($spec) vous permet de changer le dossier donnant accès aux dossiers de la vue : le base path. Par défaut il s'agit de :moduleDir/views. L'accesseur de récupération est getViewBasePathSpec().

  • setViewScriptPathSpec($spec) : une fois dans le base path, le rendu cherche le script de vue dans le script path, que cette méthode permet de définir. La valeur par défaut est :controller/:action.:suffix et l'autre accesseur est getViewScriptPathSpec().

  • setViewScriptPathNoControllerSpec($spec) Une fois dans le base path, si noController est activé, le rendu cherche le script de vue dans le chemin que cette méthode permet de définir. La valeur par défaut est :action.:suffix et l'autre accesseur est getViewScriptPathNoControllerSpec().

ViewRenderer utilise un inflecteur : Zend_Filter_Inflector, pour résoudre les options de chemin, en chemins réels. Pour une personnalisation maximale, vous pouvez interagir avec cet inflecteur à l'aide des méthodes suivantes :

  • getInflector() retourne l'inflecteur. Si aucun n'existe, ViewRenderer en crée un avec des options par défaut.

    Par défaut, les règles de l'inflecteur sont statiques autant pour le suffixe et le répertoire module, que pour la cible. Ceci permet au ViewRenderer de modifier ces valeurs dynamiquement.

  • setInflector($inflector, $reference) peut être utilisée pour passer son propre inflecteur à ViewRenderer. Si $reference est à TRUE, alors le suffixe, le répertoire du module et la cible seront affectés en fonction des propriétés de ViewRenderer.

Note: Règles de résolution par défaut
Le ViewRenderer utilise certaines règles par défaut pour chercher ses scripts de vue, voyez plutôt :

  • :module : casseMélangée et motsEnNotationCamel qui deviennent des mots séparés par des tirets, et en minuscules. "FooBarBaz" devient "foo-bar-baz".

    En interne, l'inflecteur utilise les filtres Zend_Filter_Word_CamelCaseToDash et Zend_Filter_StringToLower.

  • :controller : casseMélangée et motsEnNotationCamel qui deviennent des mots séparés par des tirets; les tirets bas eux, se transforment en séparateur de dossier et tout est passé en minuscules. "FooBar" devient "foo-bar"; "FooBar_Admin" devient "foo-bar/admin".

    En interne, l'inflecteur utilise les filtres Zend_Filter_Word_CamelCaseToDash, Zend_Filter_Word_UnderscoreToSeparator, et Zend_Filter_StringToLower.

  • :action : casseMélangée et motsEnNotationCamel qui se transforment en mots séparés par des tirets, minuscules. Les caractères non alphanumériques deviennent des tirets. "fooBar" devient "foo-bar"; "foo-barBaz" devient "foo-bar-baz".

    Pour ceci, l'inflecteur interne utilise les filtres Zend_Filter_Word_CamelCaseToDash, Zend_Filter_PregReplace, et Zend_Filter_StringToLower.

Enfin, l'API ViewRenderer vous propose aussi des méthodes pour déterminer les scripts de vue, et rendre la vue. Celles-ci se décomposent en :

  • renderScript($script, $name) va vous permettre de spécifier pleinement le script de vue à rendre, et éventuellement un nom de segment de réponse dans lequel rendre. ViewRenderer s'attend à un paramètre $script représentant un chemin complet vers un script de vue, telle que la méthode de la vue render() l'attend.

    Note: Une fois rendue, la vue utilise noRender pour éviter un double rendu automatisé.

    Note: Par défaut, Zend_Controller_Action::renderScript() est un proxy vers la méthode renderScript() de ViewRenderer.

  • getViewScript($action, $vars) récupère le chemin du script de vue en se basant sur les paramètres $action et $vars. $vars peut contenir "moduleDir", "module", "controller", "action", et "suffix"), sinon les valeurs de la requête actuelle seront utilisées.

    getViewScript() utilisera viewScriptPathSpec ou viewScriptPathNoControllerSpec selon le paramètre noController.

    Les délimiteurs apparaissant dans les modules, contrôleurs ou actions seront remplacés par des tirets ("-"). Ainsi pour un un contrôleur "foo.bar" et une action "baz:bat", il résultera un chemin de vue "foo-bar/baz-bat.phtml".

    Note: Par défaut Zend_Controller_Action::getViewScript() est un proxy vers la méthode getViewScript() de ViewRenderer.

  • render($action, $name, $noController) a beaucoup de responsabilités : d'abord, elle vérifie si $name ou $noController lui ont été passés, si c'est le cas, elle configure correctement les paramètres responseSegment et noController dans le ViewRenderer. Elle passe ensuite $action, si spécifié, à getViewScript(). Enfin, elle passe le script de vue calculé à renderScript().

    Note: Attention aux effets secondaires avec render() : les valeurs segment de réponse, et noController vont persister dans l'objet ViewRenderer. De plus, noRender() va être appelée.

    Note: Par défaut, Zend_Controller_Action::render() est un proxy vers render() de ViewRenderer.

  • renderBySpec($action, $vars, $name) vous fournit le moyen de passer des paramètres de spécification pour le dossier de script de vue. Cette méthode passe $action et $vars à getScriptPath(), pour en déduire un chemin qu'elle envoie alors avec $name à renderScript().

Exemples

Example #9 Usage de base

L'utilisation la plus basique consiste à initialiser ou et enregistrer un objet ViewRenderer dans le gestionnaire d'aides (helper broker), et ensuite lui passer des variables dans vos contrôleurs.

  1. // Dans le fichier de démarrage :
  2. Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
  3.  
  4. ...
  5.  
  6. // 'foo' module, contrôleur 'bar' :
  7. class Foo_BarController extends Zend_Controller_Action
  8. {
  9.     // Rend bar/index.phtml par défaut, rien à faire
  10.     public function indexAction()
  11.     {
  12.     }
  13.  
  14.     // Rend bar/populate.phtml avec la variable 'foo' à la valeur 'bar'.
  15.     // L'objet de vue est rendu disponible en preDispatch().
  16.     public function populateAction()
  17.     {
  18.         $this->view->foo = 'bar';
  19.     }
  20.  
  21.     // Ne rend rien, car on demande un nouveau jeton de distribution
  22.     public function bazAction()
  23.     {
  24.         $this->_forward('index');
  25.     }
  26.  
  27.     // Ne rend rien, une redirection est demandée
  28.     public function batAction()
  29.     {
  30.         $this->_redirect('/index');
  31.     }
  32. }

Note: Conventions de noms : délimiteurs de mots dans les noms de contrôleur et d'action
Si les noms de votre contrôleur ou de votre action sont composés de plusieurs mots, le distributeur s'attend à ce qu'ils soient séparés par des caractères bien définis, dans l'URL. Le ViewRenderer les transforme alors en '/' pour les chemins, ou tirets '-' pour les mots. Ainsi, un appel à /foo.bar/baz.bat distribuera FooBarController::bazBatAction() dans FooBarController.php, et ceci rendra foo-bar/baz-bat.phtml. Un appel à /bar_baz/baz-bat distribuera vers Bar_BazController::bazBatAction() dans Bar/BazController.php (notez la séparation du chemin), et rend bar/baz/baz-bat.phtml.
Notez dans le second exemple, le module est celui par défaut, mais comme un séparateur de chemin (tiret bas ou "_") est donné, alors le contrôleur distribué devient Bar_BazController, dans Bar/BazController.php.

Example #10 Désactivation du rendu automatique

Il peut être nécessaire dans certains cas de désactiver manuellement le rendu automatique de vue effectué par ViewRenderer. Par exemple, si le contrôleur doit retourner une sortie spéciale, comme XML ou JSON. Deux options s'offrent à vous : setNeverRender()) et setNoRender().

  1. // Baz controller class, bar module :
  2. class Bar_BazController extends Zend_Controller_Action
  3. {
  4.     public function fooAction()
  5.     {
  6.         // Ne rend pas automatiquement cette action
  7.         $this->_helper->viewRenderer->setNoRender();
  8.     }
  9. }
  10.  
  11. // Bat controller class, bar module :
  12. class Bar_BatController extends Zend_Controller_Action
  13. {
  14.     public function preDispatch()
  15.     {
  16.         // Ne rend plus aucune action de ce contrôleur
  17.         $this->_helper->viewRenderer->setNoRender();
  18.     }
  19. }

Note: Utiliser setNeverRender()), pour désactiver totalement le rendu automatique de vue vous fera perdre un des avantages majeur de ViewRenderer.

Example #11 Choix d'un script de vue différent

Il peut arriver que vous éprouviez le besoin de rendre un script de vue différent de celui correspondant à l'action en cours de distribution. Par exemple, un contrôleur qui possède deux actions ajout et édition, qui sont susceptibles toutes les deux de rendre le même script de vue. Utilisez alors setScriptAction(), setRender(), ou appelez l'aide ViewRenderer directement :

  1. // Bar controller class, foo module :
  2. class Foo_BarController extends Zend_Controller_Action
  3. {
  4.     public function addAction()
  5.     {
  6.         // Rend 'bar/form.phtml' plutôt que 'bar/add.phtml'
  7.         $this->_helper->viewRenderer('form');
  8.     }
  9.  
  10.     public function editAction()
  11.     {
  12.         // Rend 'bar/form.phtml' au lieu de 'bar/edit.phtml'
  13.         $this->_helper->viewRenderer->setScriptAction('form');
  14.     }
  15.  
  16.     public function processAction()
  17.     {
  18.         // un peu de validation...
  19.         if (!$valid) {
  20.             // Rend 'bar/form.phtml' à la place de 'bar/process.phtml'
  21.             $this->_helper->viewRenderer->setRender('form');
  22.             return;
  23.         }
  24.  
  25.         // continue le processus...
  26.     }
  27. }

Example #12 Modification de l'objet de vue

Si vous désirez modifier l'objet de vue absorbé par ViewRenderer, pour par exemple ajouter un chemin vers des aides spécifique, ou spécifier l'encodage, vous pourriez par exemple récupérer l'objet de vue depuis le ViewRenderer, ou dans un contrôleur.

  1. // Bar controller class, foo module :
  2. class Foo_BarController extends Zend_Controller_Action
  3. {
  4.     public function preDispatch()
  5.     {
  6.         // change l'encodage de la vue
  7.         $this->view->setEncoding('UTF-8');
  8.     }
  9.  
  10.     public function bazAction()
  11.     {
  12.         // Récupère l'objet de vue, et lui passe la fonction
  13.         // d'2chappement 'htmlspecialchars'
  14.         $view = $this->_helper->viewRenderer->view;
  15.         $view->setEscape('htmlspecialchars');
  16.     }
  17. }

Utilisation avancée

Example #13 Changement des spécifications de dossier

Dans certains cas, il peut être nécessaire d'utiliser un chemin absolu, fixe. Par exemple si vous ne donnez accès à vos graphistes qu'à un seul dossier, en utilisant un moteur de template tel que » Smarty.

Pour ceci, imaginons que le base path soit fixé à "/opt/vendor/templates", et que vous voulez que vos scripts de vues soit référencés par ":moduleDir/:controller/:action.:suffix"; si le paramètre noController est activé, vous désirez utiliser le dossier plus haut ":action.:suffix". Enfin, vous désirez un suffixe en "tpl" :

  1. /**
  2. * Dans le fichier de démarrage :
  3. */
  4.  
  5. // Une implémentation personnalisée de la vue
  6. $view = new ZF_Smarty();
  7.  
  8. $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
  9. $viewRenderer->setViewBasePathSpec('/opt/vendor/templates')
  10.              ->setViewScriptPathSpec(':module/:controller/:action.:suffix')
  11.              ->setViewScriptPathNoControllerSpec(':action.:suffix')
  12.              ->setViewSuffix('tpl');
  13. Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

Example #14 Rendu de plusieurs scripts de vue dans une même action

Afin de rendre plusieurs scripts de vue dans une même action, appelez tout simplement plusieurs fois render() :

  1. class SearchController extends Zend_Controller_Action
  2. {
  3.     public function resultsAction()
  4.     {
  5.         // Considérons $this->model comme étant un modèle valide
  6.         $this->view->results = $this->model
  7.                                     ->find($this->_getParam('query', '');
  8.  
  9.         // render() est proxiée vers ViewRenderer
  10.         // Rend d'abord un formulaire, puis un résultat
  11.         $this->render('form');
  12.         $this->render('results');
  13.     }
  14.  
  15.     public function formAction()
  16.     {
  17.         // Rien : ViewRenderer rend automatiquement un script de vue
  18.     }
  19. }

Écrire vos propres aides

Les aides d'action étendent Zend_Controller_Action_Helper_Abstract, une classe abstraite qui fournit l'interface basique et les fonctionnalités requises par le gestionnaire d'aides. Ceci inclue les méthodes suivantes :

  • setActionController() est utilisée pour paramétrer le contrôleur d'action courant.

  • init(), déclenchée par le gestionnaire d'aides à l'instanciation, peut être utilisée pour déclencher l'initialisation dans l'aide ; ceci peut être pratique pour remettre dans l'état initial quand de multiples contrôleurs utilisent la même aide dans des actions enchaînées.

  • preDispatch() est déclenchée avant la distribution d'une action.

  • postDispatch() est déclenchée quand une action a été distribuée - même si un plugin preDispatch() a évité l'action. Principalement utile pour le nettoyage.

  • getRequest() récupère l'objet de requête courant.

  • getResponse() récupère l'objet de réponse courant.

  • getName() récupère le nom de l'aide. Elle récupère la portion du nom de la classe qui suit le dernier tiret bas ("_"), ou le nom de la classe entier sinon. Pour exemple, si la classe est nommée Zend_Controller_Action_Helper_Redirector, elle retourne Redirector ; une classe nommée FooMessage retournera FooMessage.

Vous pouvez optionnellement inclure une méthode direct() dans votre classe d'aide. Si définie, ceci vous permet de traiter l'aide comme une méthode du gestionnaire, dans le but de faciliter un usage unique de l'aide. Pour exemple, l'aide Redirectordéfinit direct() comme un alias de goto(), vous permettant d'utiliser l'aide comme ceci :

  1. // Redirige vers /blog/view/item/id/42
  2. $this->_helper->redirector('item', 'view', 'blog', array('id' => 42));

En interne, la méthode __call() du gestionnaire d'aides cherche une aide nommée redirector, puis vérifie si cette aide possède une méthode direct(), et enfin appelle cette méthode avec les arguments fournis.

Une fois que vous avez créé vos propres classes d'aide, vous pouvez en fournir l'accès comme décrit dans les sections ci-dessus.


Contrôleurs d'action