Plugins
    
    Introduction
        
        
            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 que
                    le routeur aie fini de router la
                    requête.
                 
             
            - 
                
                     dispatchLoopStartup() est appelée juste avant que
                    Zend_Controller_Front n'entre en boucle de
                    distribution.
                 
             
            - 
                
                     preDispatch() est appelée avant qu'une action ne soit
                    distribuée par
                    le distributeur. 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 distribution de celle-ci.
                 
             
            - 
                
                     postDispatch() est appelée après qu'une action
                    n'ait été distribuée par
                    le distributeur. 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 une redistribution de celle-ci.
                 
             
            - 
                
                     dispatchLoopShutdown() est appelée par
                    Zend_Controller_Front lorsque celui-ci sort de la boucle
                    de distribution.
                 
             
         
     
    Écrire des plugins
        
        
            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.
         
     
    Utilisation des plugins
        
        
            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("<p>routeStartup() appelée</p>\n");  
    }  
   
    public function routeShutdown(  
                Zend_Controller_Request_Abstract $request)  
    {  
        $this->getResponse()  
             ->appendBody("<p>routeShutdown() appelée</p>\n");  
    }  
   
    public function dispatchLoopStartup(  
                Zend_Controller_Request_Abstract $request)  
    {  
        $this->getResponse()  
             ->appendBody("<p>dispatchLoopStartup() appelée</p>\n");  
    }  
   
    public function preDispatch(  
                Zend_Controller_Request_Abstract $request)  
    {  
        $this->getResponse()  
             ->appendBody("<p>preDispatch() appelée</p>\n");  
    }  
   
    public function postDispatch(  
                Zend_Controller_Request_Abstract $request)  
    {  
        $this->getResponse()  
             ->appendBody("<p>postDispatch() appelée</p>\n");  
    }  
   
    public function dispatchLoopShutdown()  
    {  
        $this->getResponse()  
             ->appendBody("<p>dispatchLoopShutdown() appelée</p>\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 :
         
        <p>routeStartup() appelée</p>  
   
<p>routeShutdown() appelée</p>  
   
<p>dispatchLoopStartup() appelée</p>  
   
<p>preDispatch() appelée</p>  
   
<p>postDispatch() appelée</p>  
   
<p>dispatchLoopShutdown() appelée</p> 
  
        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.
             
          
     
    Récupération et manipulations des plugins
        
        
            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é s'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.
                 
             
         
     
    Plugins inclus dans Zend Framework
        
        Zend Framework possède des plugins dans sa distribution : 
        ActionStack
    
    
        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 distribué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
        distribution.
     
 
        Zend_Controller_Plugin_ErrorHandler
    
    
        Zend_Controller_Plugin_ErrorHandler est un plugin intégré par défaut
        pour gérer les exceptions levées par votre application, 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 aucune route ne correspond 
         
        - 
            
                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
        HTTP 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 distribuer
        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, et relance la dernière exception enregistrée dans l'objet
        de réponse.
     
    Utilisation de ErrorHandler pour gérer les erreurs 404
        
        
            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_ROUTE,
                    indique qu'aucune route correspondante n'a été trouvée.
                 
             
            - 
                
                    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 trois 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_ROUTE:  
            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 error_handler le permet :
         
        public function errorAction()  
{  
        $errors = $this->_getParam('error_handler');  
   
        switch ($errors->type) {  
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:  
            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;  
        }  
} 
  
     
    Gestion des rendus précédants de la réponse
        
        
            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. Ceci peut introduire un mélange entre le rendu attendu et le contenu de
            l'erreur.
         
        
            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(); 
  
     
    Exemples d'utilisation
        
        Example #1 Utilisation standard et désactivation  
            
            $front = Zend_Controller_Front::getInstance();  
$front->registerPlugin(new Zend_Controller_Plugin_ErrorHandler()); 
  
         
        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); 
  
         
     
    Exemple de contrôleur d'erreurs
        
        
            Pour utiliser le plugin de gestion d'erreurs, 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_ROUTE:  
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:  
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:  
                // 404 error -- controller or action not found  
                $this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');  
   
                $content =<<<EOH  
<h1>Erreur !</h1>  
<p>Page introuvable.</p>  
EOH;  
                break;  
            default:  
                // application error  
                $content =<<<EOH  
<h1>Erreur !</h1>  
<p>Une erreur innatendue est survenue</p>  
EOH;  
                break;  
        }  
   
        // Vide le contenu de la réponse  
        $this->getResponse()->clearBody();  
   
        $this->view->content = $content;  
    }  
} 
  
     
 
        Zend_Controller_Plugin_PutHandler
    
    
        Zend_Controller_Plugin_PutHandler fournit un plugin intégré pour
        la gestion du corps des requêtes PUT en tant que paramètres de
        requête, tout comme le corps d'une requête POST. Il va inspecter
        la requête et, s'il s'agit d'une requête PUT, va utiliser la
        fonction parse_str pour découper le contenu brut de la requête PUT
        en un tableau de paramètres qui est ensuite enregistré dans l'objet de requête. Par
        exemple :
     
    PUT /notes/5.xml HTTP/1.1  
   
title=Hello&body=World 
  
    
        Pour recevoir les paramètres "title" et "body" comme des paramètres de requête habituels,
        vous devez enregistrer le plugin :
     
    $front = Zend_Controller_Front::getInstance();  
$front->registerPlugin(new Zend_Controller_Plugin_PutHandler()); 
  
    
        Ensuite vous pouvez accéder aux paramètres du corps de la requête PUT
        par leur nom à l'intérieur de votre contrôleur :
     
    ...  
public function putAction()  
{  
    $title = $this->getRequest()->getParam('title'); // $title = "Hello"  
    $body = $this->getRequest()->getParam('body'); // $body = "World"  
}  
... 
  
 
     
 
         
            
 | 
         
 
  |