| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- <?xml version="1.0" encoding="utf-8"?>
- <!-- EN-Revision: 15617 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.action">
- <title>Contrôleurs d'action</title>
- <sect2 id="zend.controller.action.introduction">
- <title>Introduction</title>
- <para>
- <classname>Zend_Controller_Action</classname> est une classe abstraite que vous
- pouvez utiliser avec le contrôleur frontal quand vous construisez un site Web basé sur
- le modèle de conception Modèle-Vues-Contrôleurs (MVC).
- </para>
- <para>
- Pour utiliser <classname>Zend_Controller_Action</classname>, vous devez la
- sous-classer dans vos propres classes de contrôleurs d'action (ou la sous-classer pour
- créer votre propre classe de base pour vos contrôleurs d'action). L'opération la plus
- basique est de la sous-classer, et de créer vos méthodes d'action qui correspondent aux
- différentes actions que vous souhaitez gérer. La gestion du routage et de la
- distribution des <classname>Zend_Controller</classname> va rechercher automatiquement
- les méthodes dont le nom termine par 'Action' dans votre classe et les considérer comme
- des actions potentiellement valides de votre contrôleur.
- </para>
- <para>Par exemple, considérons une classe définie comme ceci :</para>
- <programlisting language="php"><![CDATA[
- class FooController extends Zend_Controller_Action
- {
- public function barAction()
- {
- // réalise quelquechose
- }
- public function bazAction()
- {
- // réalise quelquechose
- }
- }
- ]]></programlisting>
- <para>
- La classe <code>FooController</code> (contrôleur <code>foo</code>) définit deux
- actions, <code>bar</code> et <code>baz</code>.
- </para>
- <para>
- Il y a d'autres fonctionnalités qui peuvent être utilisées, comme personnaliser
- l'initialisation des actions, gérer les actions par défaut quand aucune action ou une
- action invalide est fournie, avoir la possibilité de hook ("détournement") en pre et
- post-dispatch, et une variété de méthodes d'aides (helper). Ce chapitre fournit une vue
- d'ensemble des fonctionnalités du contrôleur d'action.
- </para>
- <note>
- <title>Comportement par défaut</title>
- <para>
- Par défaut, le <link linkend="zend.controller.front">contrôleur frontal</link>
- active l'aide d'action
- <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
- Cette aide s'occupe de l'injection automatique de l'objet de vue dans vos
- contrôleurs, ainsi que du rendu de cette vue. Vous pouvez la désactiver au sein de
- vos contrôleurs par l'une ou l'autre des actions suivantes :
- </para>
- <programlisting language="php"><![CDATA[
- class FooController extends Zend_Controller_Action
- {
- public function init()
- {
- // Locale à ce seul contrôleur ; affecte toutes les actions,
- // si chargée dans l'init :
- $this->_helper->viewRenderer->setNoRender(true);
- // Global :
- $this->_helper->removeHelper('viewRenderer');
- // Global aussi, mais doit être réalisé en conjonction avec
- // la version locale pour être propagé dans ce contrôleur:
- Zend_Controller_Front::getInstance()->setParam('noViewRenderer',
- true);
- }
- }
- ]]></programlisting>
- <para>
- Les méthodes <code>initView()</code>, <code>getViewScript()</code>,
- <code>render()</code>, et <code>renderScript()</code> sont affectées chacune au
- <code>ViewRenderer</code> à moins que l'aide ne soit pas chargée dans le
- gestionnaire d'aide (helper broker) ou que l'option <code>noViewRenderer</code>
- n'ait été réglée.
- </para>
- <para>
- Vous pouvez simplement désactiver le rendu pour une vue individuelle grâce à
- la méthode <code>noRender()</code> du <code>ViewRenderer</code> :
- </para>
- <programlisting language="php"><![CDATA[
- class FooController extends Zend_Controller_Action
- {
- public function barAction()
- {
- // désactive le rendu automatique pour cette action seulement :
- $this->_helper->viewRenderer->setNoRender();
- }
- }
- ]]></programlisting>
- <para>
- Les raisons principales de désactiver le <code>ViewRenderer</code> sont
- l'absence de besoin d'objets de vues ou si vous n'effectuez pas de rendu via des
- scripts de vues (par exemple, quand vous utilisez un contrôleur d'action pour
- servir des protocoles de service Web comme SOAP, XML-RPC ou REST). Dans la plupart
- des cas, il n'est pas nécessaire de désactiver globalement le
- <code>ViewRenderer</code>, seulement de manière sélective pour des contrôleurs ou
- actions individuels.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.controller.action.initialization">
- <title>Initialisation d'objet</title>
- <para>
- Même si vous pouvez toujours surcharger le constructeur du contrôleur d'action,
- nous ne vous le recommandons pas.
- <classname>Zend_Controller_Action::__construct()</classname> réalise certaines tâches
- importantes, comme l'enregistrement des objets de requêtes et de réponses, ainsi que
- l'invocation d'arguments personnalisés fourni par le contrôleur frontal. Si vous devez
- surcharger le constructeur, n'oubliez pas d'appeler
- <code>parent::__construct($request, $response, $invokeArgs)</code>.
- </para>
- <para>
- La manière la plus appropriée de personnaliser l'instanciation est d'utiliser la
- méthode <code>init()</code>, qui est appelée en dernière tâche de
- <code>__construct()</code>. Par exemple, si vous voulez vous connecter à une base de
- données à l'instanciation :
- </para>
- <programlisting language="php"><![CDATA[
- class FooController extends Zend_Controller_Action
- {
- public function init()
- {
- $this->db = Zend_Db::factory('Pdo_Mysql', array(
- 'host' => 'myhost',
- 'username' => 'user',
- 'password' => 'XXXXXXX',
- 'dbname' => 'website'
- ));
- }
- }
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.controller.action.prepostdispatch">
- <title>Détournement Pre et Post-Dispatch (Hook)</title>
- <para>
- <classname>Zend_Controller_Action</classname> spécifie deux méthodes qui peuvent
- être appelées juste avant et juste après une action, <code>preDispatch()</code> et
- <code>postDispatch()</code>. Celles-ci peuvent être pratiques dans plusieurs cas :
- vérifier l'authentification et les ACL avant d'exécuter une action (en appelant
- <code>_forward()</code> dans <code>preDispatch()</code>, l'action sera évitée), par
- exemple, ou en plaçant du contenu généré dans une partie du modèle du site
- (<code>postDispatch()</code>).
- </para>
- </sect2>
- <sect2 id="zend.controller.action.accessors">
- <title>Accesseurs</title>
- <para>
- Un certain nombre d'objets et de variables sont enregistrés avec l'objet et chacun
- possède des méthodes accesseurs.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Objet Requête</emphasis> : <code>getRequest()</code> peut être
- utilisé pour récupérer l'objet de requête utilisé pour appeler l'action.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Objet Réponse</emphasis> : <code>getResponse()</code> peut être
- utilisé pour récupérer l'objet de réponse assemblant la réponse finale.
- Quelques appels typiques peuvent ressembler à ceci :
- </para>
- <programlisting language="php"><![CDATA[
- $this->getResponse()->setHeader('Content-Type', 'text/xml');
- $this->getResponse()->appendBody($content);
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- <emphasis>Arguments d'invocation</emphasis> : le contrôleur frontal peut
- transmettre des paramètres au routeur, au distributeur, et au contrôleur
- d'action. Pour récupérer individuellement ceux-ci utilisez
- <code>getInvokeArg($key)</code> ; alternativement, récupérer la liste entière
- en utilisant <code>getInvokeArgs()</code>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Paramètres de requêtes</emphasis> : l'objet de requête
- rassemble les paramètres de requête, comme les paramètres _GET ou _POST, ou les
- paramètres utilisateurs spécifiés dans le chemin d'URL. Pour récupérer ceux-ci
- utilisez <code>_getParam($key)</code> ou <code>_getAllParams()</code>. Vous
- pouvez aussi régler ces paramètres en utilisant <code>_setParam()</code> ;
- ceci est pratique quand vous redirigez vers des actions additionnelles.
- </para>
- <para>
- Pour tester si un paramètre existe ou non (pratique pour les branchements
- logiques), utilisez <code>_hasParam($key)</code>.
- </para>
- <note>
- <para>
- <code>_getParam()</code> peut prendre un second paramètre optionnel
- contenant une valeur par défaut à utiliser si le paramètre n'est pas réglé
- ou qu'il est vide. Utiliser ceci élimine la nécessité d'appeler
- <code>_hasParam()</code> avant de récupérer une valeur :
- </para>
- <programlisting language="php"><![CDATA[
- // Utilise une valeur par défaut de 1 si id n'est pas réglé
- $id = $this->_getParam('id', 1);
- // Au lieu de :
- if ($this->_hasParam('id') {
- $id = $this->_getParam('id');
- } else {
- $id = 1;
- }
- ]]></programlisting>
- </note>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.action.viewintegration">
- <title>Intégration des Vues</title>
- <para>
- <classname>Zend_Controller_Action</classname> fournit un mécanisme rudimentaire
- et flexible pour l'intégration des vues. Deux méthodes accomplissent ceci,
- <code>initView()</code> et <code>render()</code> ; la première méthode charge la
- propriété publique <code>$view</code>, et la dernière effectue le rendu d'une vue basé
- sur l'action courante demandée dans la requête, en utilisant la hiérarchie des
- répertoires pour déterminer le chemin du script.
- </para>
- <sect3 id="zend.controller.action.viewintegration.initview">
- <title>Initialisation des Vues</title>
- <note id="zend.controller.action.viewintegration.viewrenderer">
- <title>
- Par défaut, l'intégration des vues est réalisé via le ViewRenderer
- </title>
- <para>
- Le contenu de cette section n'est valable que si vous avez explicitement
- désactivé le
- <link linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>.
- Sinon, vous pouvez passer à la section suivante.
- </para>
- </note>
- <para>
- <code>initView()</code> initialise l'objet Vue. <code>render()</code> appelle
- <code>initView()</code> dans le but de récupérer l'objet de vue, mais il peut être
- initialisé à tout moment ; par défaut il remplit la propriété
- <code>$view</code> avec un objet <classname>Zend_View</classname>, mais toute
- classe implémentant <classname>Zend_View_Interface</classname> peut être utilisée.
- Si <code>$view</code> est déjà initialisé, il retourne simplement cette
- propriété.
- </para>
- <para>
- La mise en oeuvre par défaut suppose la structure de répertoire suivante :
- </para>
- <programlisting language="php"><![CDATA[
- applicationOrModule/
- controllers/
- IndexController.php
- views/
- scripts/
- index/
- index.phtml
- helpers/
- filters/
- ]]></programlisting>
- <para>
- En d'autres termes, les scripts de vues sont supposés être dans le
- sous-répertoire <code>views/scripts/</code>, et le sous-répertoire
- <code>views</code> est censé contenir les fonctionnalités soeurs (aides [helpers],
- filtres [filters]). En déterminant le script de vue et son chemin, le répertoire
- <code>views/scripts/</code> est utilisé comme chemin de base, avec des dossiers
- nommés par le nom de contrôleur fournissant ainsi la hiérarchie des scripts de
- vues.
- </para>
- </sect3>
- <sect3 id="zend.controller.action.viewintegration.render">
- <title>Effectuer le rendu des Vues</title>
- <para><code>render()</code> a la signature suivante :</para>
- <programlisting language="php"><![CDATA[
- string render(string $action = null,
- string $name = null,
- bool $noController = false);
- ]]></programlisting>
- <para>
- <code>render()</code> effectue le rendu d'un script de vue. Si aucun argument
- n'est fourni, la méthode suppose que le script requêté est
- <code>[controller]/[action].phtml</code> (où <code>.phtml</code> est la valeur de
- la propriété <code>$viewSuffix</code>). Fournir une valeur pour
- <code>$action</code> va effectuer le rendu du script dans le sous-dossier
- <code>[controller]</code>. Pour surcharger l'utilisation du sous-dossier
- <code>[controller]</code>, fournissez la valeur <code>true</code> à
- <code>$noController</code>. Enfin, les scripts sont rendus dans l'objet
- réponse ; si vous souhaitez effectuer le rendu dans un
- <link linkend="zend.controller.response.namedsegments">segment
- nommé</link>spécifique de l'objet réponse, fournissez une valeur à
- <code>$name</code>.
- </para>
- <note>
- <para>
- Puisque le contrôleur et des noms d'action peuvent contenir des
- caractères délimiteurs de mot comme '_', '.' et '-', <code>render()</code>
- normalise ceux-ci à '-' en déterminant le nom du script. En interne, il utilise
- le délimiteur de mot et de chemin du distributeur pour faire cette
- normalisation. Ainsi, une requête pour <code>/foo.bar/baz-bat</code> rendra le
- script <code>foo-bar/baz-bat.phtml</code>. Si votre méthode d'action contient
- des notationsCamel, veuillez vous souvenir que ceci va résulter avec des mots
- séparés par '-' en déterminant le nom de fichier du script de vue.
- </para>
- </note>
- <para>Quelques exemples :</para>
- <programlisting language="php"><![CDATA[
- class MonController extends Zend_Controller_Action
- {
- public function fooAction()
- {
- // Effectue le rendu de mon/foo.phtml
- $this->render();
- // Effectue le rendu de mon/bar.phtml
- $this->render('bar');
- // Effectue le rendu de baz.phtml
- $this->render('baz', null, true);
- // Effectue le rendu de mon/login.phtml vers le segment
- // 'form' de l'objet réponse
- $this->render('login', 'form');
- // Effectue le rendu de site.phtml vers le segment
- // 'page' de l'objet réponse ; sans utiliser
- // le sous-dossier 'mon/'
- $this->render('site', 'page', true);
- }
- public function bazBatAction()
- {
- // Effectue le rendu de mon/baz-bat.phtml
- $this->render();
- }
- }
- ]]></programlisting>
- </sect3>
- </sect2>
- <sect2 id="zend.controller.action.utilmethods">
- <title>Méthodes utiles</title>
- <para>
- En plus de l'accesseur et des méthodes d'intégration de vue,
- <code>Zend_Controller_Action</code> possède plusieurs méthodes utiles pour exécuter
- des tâches communes de l'intérieur de vos méthodes d'action (ou de
- pre-/post-dispatch).
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>_forward($action, $controller = null, $module = null, array $params
- = null)</code> : exécute une autre action. Si appelé dans
- <code>preDispatch()</code>, la requête courante est évitée en faveur de la
- nouvelle. Sinon, après que l'action courante ait été exécutée, l'action
- demandée dans <code>_forward()</code> sera exécutée à son tour.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>_redirect($url, array $options = array())</code> : redirige vers
- une autre page. Cette méthode prend un URL et un jeu d'options optionnel. Par
- défaut, il exécute une redirection de type HTTP 302.
- </para>
- <para>Les options peuvent inclure une ou plusieurs des clés suivantes :</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis></emphasis> : avec ou sans sortie immédiate. Si
- appelée, la méthode fermera proprement toute session ouverte et
- réalisera la redirection.
- </para>
- <para>
- Vous pouvez régler cette option de manière globale dans le
- contrôleur en utilisant l'accesseur
- <code>setRedirectExit()</code>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>prependBase</emphasis> : ajoute ou non l'URL de base
- enregistré dans l'objet requête à l'URL produit.
- </para>
- <para>
- Vous pouvez régler cette option de manière globale dans le
- contrôleur en utilisant l'accesseur
- <code>setRedirectPrependBase()</code>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>code</emphasis> : fournit le code HTTP à utiliser pour
- la redirection. Par défaut, un HTTP 302 est utilisé ; tout code compris
- entre 301 et 306 peut être utilisé.
- </para>
- <para>
- Vous pouvez régler cette option de manière globale dans le
- contrôleur en utilisant l'accesseur
- <code>setRedirectCode()</code>.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.action.subclassing">
- <title>Sous-classer le contrôleur d'action</title>
- <para>
- Par conception, <classname>Zend_Controller_Action</classname> doit être
- sous-classé pour créer un contrôleur d'action. Au minimum, vous devez définir les
- méthodes d'action que le contrôleur d'action peut appeler.
- </para>
- <para>
- En plus de la création de fonctionnalité utile pour vos applications Web, vous
- pouvez aussi constater que vous répétez souvent la même installation ou les mêmes
- méthodes utilitaires dans vos contrôleurs divers ; s'il en est ainsi, créer une classe
- de contrôleur de base commune qui étend <classname>Zend_Controller_Action</classname>
- peut résoudre une telle redondance.
- </para>
- <example id="zend.controller.action.subclassing.example-call">
- <title>Comment gérer des actions non-existantes</title>
- <para>
- Si une requête vers un contrôleur est faite en incluant une méthode d'action
- indéfinie, <classname>Zend_Controller_Action::__call()</classname> sera invoqué.
- <code>__call()</code> est, bien sûr, la méthode magique de PHP pour la surcharge de
- méthode.
- </para>
- <para>
- Par défaut, cette méthode lève une
- <classname>Zend_Controller_Action_Exception</classname> indiquant que la méthode
- requêtée n'a pas été trouvée dans le contrôleur. Si la méthode requêtée se termine
- par "Action", on considère qu'une action était requêté et qu'elle n'existe pas ; un
- telle erreur entraîne une exception ayant un code 404. Tout autre appel de méthode
- entraîne une exception ayant un code 500. Ceci vous permet de facilement
- différencier une page inconnue et une erreur de l'application dans votre
- gestionnaire d'erreur.
- </para>
- <para>
- Vous pouvez surcharger cette fonctionnalité si vous souhaitez exécuter
- d'autres opérations. Par exemple, si vous souhaitez afficher un message d'erreur,
- vous pouvez écrire quelque chose comme ceci :
- </para>
- <programlisting language="php"><![CDATA[
- class MonController extends Zend_Controller_Action
- {
- public function __call($method, $args)
- {
- if ('Action' == substr($method, -6)) {
- // Si une méthode d'action n'est pas trouvée,
- // rendre le script d'erreur
- return $this->render('error');
- }
- // pour toute autre méthode, levée d'une exception
- throw new Exception('Méthode invalide "' . $method . '" appelée',
- 500);
- }
- }
- ]]></programlisting>
- <para>
- Une autre possibilité est de rediriger vers une page de contrôleur par
- défaut :
- </para>
- <programlisting language="php"><![CDATA[
- class MyController extends Zend_Controller_Action
- {
- public function indexAction()
- {
- $this->render();
- }
- public function __call($method, $args)
- {
- if ('Action' == substr($method, -6)) {
- // Si une méthode d'action n'est pas trouvée,
- // rediriger vers l'action index
- return $this->_forward('index');
- }
- // pour tout autre méthode, levée d'une exception
- throw new Exception('Méthode invalide "' . $method . '" appelée',
- 500);
- }
- }
- ]]></programlisting>
- </example>
- <para>
- En plus de la surcharge de <code>__call()</code>, chacune des méthodes
- d'initialisation , utilitaires, d'accesseurs, de vues et de détournement de la
- distribution mentionnées ci-dessus peuvent être surchargées dans le but de
- personnaliser vos contrôleurs. Par exemple, si vous stockez votre objet de vue dans le
- registre, vous pouvez vouloir modifier votre méthode <code>initView()</code> avec une
- code comme celui-ci :
- </para>
- <programlisting language="php"><![CDATA[
- abstract class Ma_Base_Controller extends Zend_Controller_Action
- {
- public function initView()
- {
- if (null === $this->view) {
- if (Zend_Registry::isRegistered('view')) {
- $this->view = Zend_Registry::get('view');
- } else {
- $this->view = new Zend_View();
- $this->view->setBasePath(dirname(__FILE__) . '/../views');
- }
- }
- return $this->view;
- }
- }
- ]]></programlisting>
- <para>
- En espérant que les informations de ce chapitre vous permettent de voir la
- flexibilité de ce composant particulier et comment vous pouvez le modifier suivant les
- besoins de votre application.
- </para>
- </sect2>
- </sect1>
|