| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- <?xml version="1.0" encoding="utf-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.exceptions">
- <title>Exceptions avec MVC</title>
- <sect2 id="zend.controller.exceptions.introduction">
- <title>Introduction</title>
- <para>
- Les composants <acronym>MVC</acronym> de Zend Framework utilisent un contrôleur frontal, ce qui veut
- dire que toute requête envoyée à l'application entre par ce point unique. Ainsi, toutes
- les exceptions sont encapsulées dans le contrôleur frontal, ceci vous permet de toutes
- les traiter dans un seul endroit.
- </para>
- <para>
- Cependant, les exceptions peuvent contenir des messages ou des traces plutôt
- sensibles pour le système, comme des requêtes <acronym>SQL</acronym>, l'emplacement de certains fichiers
- ... Pour vous aider à protéger votre site, par défaut,
- <classname>Zend_Controller_Front</classname> attrape toutes les exceptions et les
- enregistre dans l'objet de réponse ; et bien entendu, par défaut, cet objet de réponse
- n'affiche pas ces exceptions.
- </para>
- </sect2>
- <sect2 id="zend.controller.exceptions.handling">
- <title>Gestion des exceptions</title>
- <para>
- Plusieurs mécanismes vont vous permettre de traiter les exceptions dans le modèle
- <acronym>MVC</acronym> de Zend Framework.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Par défaut, le plugin
- <link linkend="zend.controller.plugins.standard.errorhandler">error
- handler</link>est présent, et activé. Ce plugin a été conçu pour gérer :
- </para>
- <itemizedlist>
- <listitem>
- <para>Les erreurs d'absence de contrôleurs ou d'actions</para>
- </listitem>
- <listitem>
- <para>Erreurs survenant dans un contrôleur</para>
- </listitem>
- </itemizedlist>
- <para>
- <code>ErrorHandler</code> agit dans le <methodname>postDispatch()</methodname>, et
- analyse si une exception a été levée (en gérant son type). Si c'est le cas,
- alors le plugin renvoie un jeton vers un contrôleur de gestion des
- erreurs.
- </para>
- <para>
- Ce contrôleur couvrira la majorité des cas d'utilisation. Il parvient à
- gérer les cas "contrôleur absent", "action absente", ou "autre cas".
- </para>
- </listitem>
- <listitem>
- <para><methodname>Zend_Controller_Front::throwExceptions()</methodname></para>
- <para>
- En passant la valeur <constant>TRUE</constant> à cette méthode, vous indiquez au
- contrôleur frontal que vous souhaitez qu'il vous retourne les exceptions qu'il
- rencontre. Ainsi, il ne les ajoutera pas à la réponse, et il ne fera pas
- intervenir le plugin "<code>Error handler</code>". Exemple :
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- try {
- $front->dispatch();
- } catch (Exception $e) {
- // A vous de gérer ici
- }
- ]]></programlisting>
- <para>
- Cette méthode vous permet d'utiliser une gestion personnalisée des
- exceptions dans votre application, de manière simple.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>Zend_Controller_Response_Abstract::renderExceptions()</methodname>
- </para>
- <para>
- En passant un paramètre <constant>TRUE</constant> à cette méthode, vous indiquez
- à la réponse d'afficher les exceptions qu'elle reçoit (du contrôleur frontal,
- ou du plugin "<code>Error handler</code>", par exemple), lorsque son rendu est
- appelé. Ceci ne devrait être activé qu'en environnement de développement.
- </para>
- </listitem>
- <listitem>
- <para>
- <methodname>Zend_Controller_Front::returnResponse()</methodname> et
- <methodname>Zend_Controller_Response_Abstract::isException()</methodname>.
- </para>
- <para>
- En passant le booléen <constant>TRUE</constant> à
- <methodname>Zend_Controller_Front::returnResponse()</methodname>,
- <methodname>Zend_Controller_Front::dispatch()</methodname> ne commandera pas
- l'affichage de la réponse automatiquement. Au lieu de cela, l'objet de réponse
- sera retourné. Vous pouvez alors tester celui-ci pour voir s'il contient des
- exceptions, ceci grâce à <methodname>isException()</methodname> et
- <methodname>getException()</methodname>. Voyez :
- </para>
- <programlisting language="php"><![CDATA[
- $front->returnResponse(true);
- $response = $front->dispatch();
- if ($response->isException()) {
- $exceptions = $response->getException();
- // Gestion des exceptions ici
- } else {
- $response->sendHeaders();
- $response->outputBody();
- }
- ]]></programlisting>
- <para>
- Par rapport à
- <methodname>Zend_Controller_Front::throwExceptions()</methodname>, cette
- utilisation vous permet de ne rendre la réponse que lorsque vous le décidez,
- selon la présence de telle ou telle exception, ou pas.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.exceptions.internal">
- <title>Différents types d'exceptions que vous pouvez rencontrer</title>
- <para>
- Les composants <acronym>MVC</acronym> sont nombreux, - requête, routeur, distributeur, contrôleur,
- et réponse - chaque objet risque de renvoyer une exception qui lui est propre.
- Certaines peuvent être créées ou dérivées, d'autres par défaut indiquent un problème de
- l'application.
- </para>
- <para>Comme exemples :</para>
- <itemizedlist>
- <listitem>
- <para>
- <methodname>Zend_Controller_Dispatcher::dispatch()</methodname> va envoyer
- une exception, par défaut, si un contrôleur invalide est demandé. Vous pouvez
- jouer sur ce paramètre :
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Initialisez le paramètre
- <code>useDefaultControllerAlways</code>
- </para>
- <para>
- Dans votre contrôleur frontal, ou distributeur, ajoutez la
- directive suivante :
- </para>
- <programlisting language="php"><![CDATA[
- $front->setParam('useDefaultControllerAlways', true);
- // ou
- $dispatcher->setParam('useDefaultControllerAlways', true);
- ]]></programlisting>
- <para>
- Lorsque ceci est injecté, le distributeur utilisera le contrôleur
- par défaut s'il s'aperçoit qu'il ne peut distribuer un contrôleur
- spécifique, plutôt que de renvoyer une exception. Méfiez vous des
- moteurs de recherche qui n'aiment pas que plusieurs <acronym>URI</acronym> pointent sur un
- même contenu. En effet, avec ce paramètre activé, les utilisateurs
- orthographiant mal votre site, seront redirigés vers la page d'accueil
- de celui-ci, ce qui peut aboutir à du "duplicate content" (contenu
- dupliqué).
- </para>
- </listitem>
- <listitem>
- <para>
- L'exception envoyée par <methodname>dispatch()</methodname> est de type
- <classname>Zend_Controller_Dispatcher_Exception</classname> et contient
- le message "Invalid controller specified". Utilisez une méthode comme
- vu dans la
- <link linkend="zend.controller.exceptions.handling">section
- précédente</link>pour attraper celle-ci et rediriger vers une page
- d'erreur générique.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>
- <methodname>Zend_Controller_Action::__call()</methodname> enverra une
- <classname>Zend_Controller_Action_Exception</classname> s'il n'est pas possible
- de distribuer l'action demandée. Il est facile de changer ce
- comportement :
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Dérivez la classe <classname>Zend_Controller_Action</classname>
- en redéfinissant sa méthode <methodname>__call()</methodname>, voyez plutôt :
- </para>
- <programlisting language="php"><![CDATA[
- class My_Controller_Action extends Zend_Controller_Action
- {
- public function __call($method, $args)
- {
- if ('Action' == substr($method, -6)) {
- $controller = $this->getRequest()->getControllerName();
- $url = '/' . $controller . '/index';
- return $this->_redirect($url);
- }
- throw new Exception('Invalid method');
- }
- }
- ]]></programlisting>
- <para>
- Cet exemple intercepte les actions non existantes, et redirige
- vers l'action principale du contrôleur actuel.
- </para>
- </listitem>
- <listitem>
- <para>
- Dérivez <classname>Zend_Controller_Dispatcher</classname> et
- redéfinissez <methodname>getAction()</methodname> pour vérifier si l'action existe
- bien :
- </para>
- <programlisting language="php"><![CDATA[
- class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
- {
- public function getAction($request)
- {
- $action = $request->getActionName();
- if (empty($action)) {
- $action = $this->getDefaultAction();
- $request->setActionName($action);
- $action = $this->formatActionName($action);
- } else {
- $controller = $this->getController();
- $action = $this->formatActionName($action);
- if (!method_exists($controller, $action)) {
- $action = $this->getDefaultAction();
- $request->setActionName($action);
- $action = $this->formatActionName($action);
- }
- }
- return $action;
- }
- }
- ]]></programlisting>
- <para>
- L'exemple précédant vérifie si l'action existe dans le contrôleur
- demandé. Si ce n'est pas le cas, il redéfinit l'action en spécifiant
- celle par défaut.
- </para>
- <para>
- Cette méthode permet de changer l'action avant la distribution.
- Attention une fois encore aux erreurs de syntaxes dans l'URL, qui
- devraient mener vers une page d'erreur quelconque.
- </para>
- </listitem>
- <listitem>
- <para>
- Utilisez
- <methodname>Zend_Controller_Action::preDispatch()</methodname> ou
- <methodname>Zend_Controller_Plugin_Abstract::preDispatch()</methodname>
- pour identifier les actions invalides.
- </para>
- <para>
- En dérivant <classname>Zend_Controller_Action</classname> pour y
- modifier <methodname>preDispatch()</methodname>, vous agissez sur la globalité de
- vos contrôleurs, avant même la distribution de l'action
- demandée.
- </para>
- <para>
- L'utilisation d'un plugin offre une flexibilité supplémentaire :
- Si tous vos contrôleurs n'héritent pas de la même classe, plutôt que de
- dupliquer du code, un plugin va agir indépendamment de vos contrôleurs.
- En <methodname>preDispatch()</methodname>, il agit avant ceux-ci.
- </para>
- <para>Par exemple :</para>
- <programlisting language="php"><![CDATA[
- class My_Controller_PreDispatchPlugin
- extends Zend_Controller_Plugin_Abstract
- {
- public function preDispatch(Zend_Controller_Request_Abstract $request)
- {
- $front = Zend_Controller_Front::getInstance();
- $dispatcher = $front->getDispatcher();
- $class = $dispatcher->getControllerClass($request);
- if (!$class) {
- $class = $dispatcher->getDefaultControllerClass($request);
- }
- $r = new ReflectionClass($class);
- $action = $dispatcher->getActionMethod($request);
- if (!$r->hasMethod($action)) {
- $defaultAction = $dispatcher->getDefaultAction();
- $controllerName = $request->getControllerName();
- $response = $front->getResponse();
- $response->setRedirect('/' . $controllerName
- . '/' . $defaultAction);
- $response->sendHeaders();
- exit;
- }
- }
- }
- ]]></programlisting>
- <para>
- Dans cet exemple, nous vérifions si l'action demandée existe dans
- le contrôleur distribué. Si ce n'est pas le cas, nous exécutons une
- redirection immédiate.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </sect2>
- </sect1>
|