|
|
L'architecture MVC de Zend Framework propose l'injection de plugins de code, qui vont intervenir à différents niveaux dans le processus complet. Le contrôleur frontal enregistre des plugins, et utilise un gestionnaire de plugins ("plugin broker"), qui va se charger de faire intervenir chaque plugin, à chacun des instants clés à votre disposition.
Les instants clés sont des méthodes événementielles définies dans la classe abstraite
Zend_Controller_Plugin_Abstract, dont tous les plugins doivent hériter :
routeStartup() est appelée avant que Zend_Controller_Front n'appelle
le routeur pour évaluer ses routes et remplir la
requête.
routeShutdown() est appelée après quele
routeur aie fini de router la requête.
dispatchLoopStartup() est appelée juste avant que Zend_Controller_Front
n'entre en boucle de dispatching.
preDispatch() est appelée avant qu'une action ne soit dispatchée par le dispatcheur. Cette méthode permet un filtrage ou un
proxy. En jouant sur la requête à ce niveau là, vous êtes capable de changer le processus, et en vous
aidant de Zend_Controller_Request_Abstract::setDispatched(true)), vous supprimez l'ordre
de dispatching de celle-ci.
postDispatch() est appelée après qu'une action n'ait été dispatchée par le dispatcheur. Cette méthode permet un filtrage ou un
proxy. En jouant sur la requête à ce niveau là, vous êtes capable de changer le processus, et en vous
aidant de Zend_Controller_Request_Abstract::setDispatched(false)), vous ordonnez un redispatching
de celle-ci.
dispatchLoopShutdown() est appelée par Zend_Controller_Front lorsque
celui-ci sort de la boucle de dispatching.
Tous les plugins doivent hériter de Zend_Controller_Plugin_Abstract:
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
// ...
}
Comme aucune des méthodes de Zend_Controller_Plugin_Abstract n'est abstraite, vous n'êtes pas
obligé dans vos plugins de toutes les définir. Vous agissez aux endroits que vous voulez.
Zend_Controller_Plugin_Abstract vous donne aussi accès aux objets de réponse et de requête,
dans vos plugins.getRequest() et getResponse() sont là pour ça. Cependant, l'objet de
requête est de toute façon passé en paramètre à vos méthodes. Veillez à le récupérer dans la définition de vos
méthodes sinon une erreur E_STRICT sera levée.
Les plugins sont enregistrés avec Zend_Controller_Front::registerPlugin(), et peuvent l'être
n'importe quand. Voici un exemple :
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
public function routeStartup(
Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("routeStartup() appelée
\n");
}
public function routeShutdown(
Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("routeShutdown() appelée
\n");
}
public function dispatchLoopStartup(
Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("dispatchLoopStartup() appelée
\n");
}
public function preDispatch(
Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("preDispatch() appelée
\n");
}
public function postDispatch(
Zend_Controller_Request_Abstract $request)
{
$this->getResponse()
->appendBody("postDispatch() appelée
\n");
}
public function dispatchLoopShutdown()
{
$this->getResponse()
->appendBody("dispatchLoopShutdown() appelée
\n");
}
}
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('/path/to/controllers')
->setRouter(new Zend_Controller_Router_Rewrite())
->registerPlugin(new MyPlugin());
$front->dispatch();
Si aucune autre action ne génère une sortie (typiquement, un rendu de vue), alors le résultat suivant devrait s'afficher :
routeStartup() appelée
routeShutdown() appelée
dispatchLoopStartup() appelée
preDispatch() appelée
postDispatch() appelée
dispatchLoopShutdown() appelée
Note:
Enregistrez vos plugins où vous voulez dans votre code, mais faites attention de ne pas leur faire sauter de méthodes, selon l'endroit où vous les enregistrez.
Il peut arriver que vous ayez besoin de récupérer des plugins, ou d'en supprimer. Les méthodes suivantes vous seront alors utiles :
getPlugin($class) vous retourne l'objet de plugin correspondant à la chaîne passée en
paramètre. Si il n'y a pas de correspondance, false est retourné. Un tableau est retourné
si il y a plusieurs plugins de cette classe.
getPlugins() retourne toute la pile de plugins.
unregisterPlugin($plugin) supprime un plugin du processus. Passez un nom de classe,
et tous les plugins de cette classe seront alors enlevés de la pile. Vous pouvez aussi passer un
objet.
Zend Framework possède des plugins dans sa distribution :
Le plugin ActionStack vous permet de gérer une pile de requêtes en opérant en
postDispatch. Si un forward (un appel à une autre action) est détecté, alors le plugin n'agira pas.
Dans le cas contraire cependant, sa pile est analysée (en ordre LIFO : dernier empilé, premier dépilé) et une
nouvelle action est dispatchée. Ce plugin est commandé par l'aide d'action du même nom ActionStack
Vous pouvez récupérer ce plugin grâce à
Zend_Controller_Front::getPlugin('Zend_Controller_Plugin_ActionStack'). Une fois l'objet retourné,
voici les méthodes qui y sont proposées :
getRegistry() et setRegistry(). En interne, ActionStack utilise
Zend_Registry pour stocker sa pile. Vous pouvez manipuler l'instance du registre utilisée grâce
à ces méthodes.
getRegistryKey() et setRegistryKey(). Ces méthodes vous donnent accès à la
clé utilisée dans le registre, pour stocker la pile d'actions de ActionStack. Par défaut, il s'agit de
Zend_Controller_Plugin_ActionStack.
getStack() retourne la pile (entière) d'actions.
pushStack() et popStack() contrôlent la pile. popStack()
supprime l'action la plus haute dans la pile (l'action à venir), et vous la retourne.
pushStack() rajoute une action sur la pile. Vous devez la passer en paramètre donc.
La méthode forward(), elle, est directe : elle attend un objet de requête qu'elle passe
immédiatement au contrôleur frontal en redemandant un jeton de dispatching.
Zend_Controller_Plugin_ErrorHandler est un plugin intégré d'office dans le modèle MVC, il sert à
gérer les exceptions envoyées par l'application, en particulier celles concernant des contrôleurs ou des actions
manquants. C'est une manière rejoignant la section Exceptions
MVC.
Les principaux objectifs de ce plugin sont :
Intercepter les exceptions envoyées si un contrôleur ou une action ne peuvent être trouvés
Intercepte les exceptions envoyées dans les contrôleurs
Globalement, ErrorHandler sert à gérer les erreurs 404 ou 500. Attention, le plugin n'est pas
destiné à intervenir sur les exceptions envoyées dans d'autres plugins. Des effets de bords peuvent apparaître,
veillez à les gérer.
Par défaut, Zend_Controller_Plugin_ErrorHandler redirige vers
ErrorController::errorAction() dans le module par défaut. Vous pouvez passer d'autres valeurs via les
accesseurs du plugin :
setErrorHandlerModule() définit le module à utiliser.
setErrorHandlerController() définit le contrôleur à utiliser.
setErrorHandlerAction() définit l'action à utiliser.
setErrorHandler() est un raccourci des trois précédantes. Passez un tableau avec les clés
"module", "controller", or "action", et leurs valeurs appropriées.
Ce comportement fonctionne aussi avec le constructeur du plugin. Celui-ci agit comme un proxy vers
setErrorHandler().
Zend_Controller_Plugin_ErrorHandler agit en postDispatch() et analyse l'objet de réponse à la recherche d'éventuelles exceptions. Si il y en a,
alors le plugin modifie la requête pour dispatcher le contrôleur et l'action d'erreur.
Si une exception arrive lorsque le plugin agit, alors celui-ci ordonne au contrôleur frontal de renvoyer
l'exception. C'est pour cela qu'il faudrait systématiquement entourer sa méthode dispatch, du
contrôleur frontal; d'un bloc try / catch.
Comme ErrorHandler capture les exceptions relatives à un problème de contrôleur ou action
manquants, vous pouvez donc l'utiliser comme un gestionnaire d'erreurs 404. Pour cela, il faut analyser le type
d'exception ayant mené à l'erreur.
Les exceptions capturées sont enregistrées en tant que paramètre d'action.
Zend_Controller_Action::_getParam('error_handler'):
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
}
}
Une fois que vous possédez l'objet contenant l'exception, inspectez son type avec
$errors->type. Des constantes sont à votre disposition:
Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER, indique un contrôleur
non trouvé.
Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION, indique qu'une action est
absente.
Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER, indique une autre
exception.
Les deux premiers types pourraient mener à une erreur 404 :
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// erreur 404 -- contrôleur ou action introuvable
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');
// ... ici, de l'affichage (du rendu)
break;
default:
// erreur applicative; affiche une page d'erreur, mais sans changer le code de
// retour HTTP
break;
}
}
}
Enfin, il est possible de récupérer l'exception ayant menée au contrôleur d'erreur. Ceci afin de
l'analyser. L'attribut exception de l'objet le permet :
public function errorAction()
{
$errors = $this->_getParam('error_handler');
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// erreur 404 -- contrôleur ou action introuvable
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');
// ... ici, de l'affichage (du rendu)
break;
default:
// erreur applicative; affiche une page d'erreur,
// mais sans changer le code de retour HTTP
// ...
// Sauve l'exception en log:
$exception = $errors->exception;
$log =
new Zend_Log(
new Zend_Log_Writer_Stream(
'/tmp/applicationException.log')
);
$log->debug($exception->getMessage()
. "\n"
. $exception->getTraceAsString());
break;
}
}
Si vous décomposez vos processus en plusieurs actions ou plusieurs appels à render(), il est
possible que la réponse contienne déjà des éléments lorsque ErrorHandler agit.
Si vous désirez rendre votre contrôleur d'erreur dans ce contenu, alors il n'y a rien à faire de spécial. En revanche, il peut aussi être judicieux de vider totalement la réponse afin de rendre le contrôleur d'erreurs. Procédez alors comme suit:
$this->getResponse()->clearBody();
Example #1 Utilisation standard et désactivation
$front = Zend_Controller_Front::getInstance(); $front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler());
Notez bien que l'exemple ci-dessus ne sert pas à grand chose : le plugin ErrorHandler est
actif par défaut, dans le contrôleur frontal. Il est cependant possible de le désactiver, passez un paramètre au
contrôleur frontal :
$front = Zend_Controller_Front::getInstance();
$front->setParam('noErrorHandler',true);
Example #2 Paramétrage du plugin
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(array(
'module' => 'mystuff',
'controller' => 'static',
'action' => 'error'
)));
Example #3 Utilisation des accesseurs
$plugin = new Zend_Controller_Plugin_ErrorHandler();
$plugin->setErrorHandlerModule('mystuff')
->setErrorHandlerController('static')
->setErrorHandlerAction('error');
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin($plugin);
Pour utiliser le plugin ErrorHandler, un contrôleur d'erreurs est requis. En voici un exemple
:
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// erreur 404 -- contrôleur ou action non trouvé
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');
$content =<<Erreur!
Page introuvable.
EOH;
break;
default:
// erreur d'application
$content =<<Erreur!
Une erreur innatendue est survenue
EOH;
break;
}
// Vide la réponse
$this->getResponse()->clearBody();
$this->view->content = $content;
}
}
|
|
Copyright © 2005-2011 Zend Technologies Inc (compiled by mikaelkael with ZFDocumentor - SVN 12579).

