preExecute() dans les controller Symfony2

Contrairement à symfony1.x ou à Zend, Symfony2 ne propose pas par défaut un méthode, qui si elle est définie, permet d'exécuter un morceau de code avant toutes les actions d'un controller.

<?php
/** 
 * prototype d'une telle fonction dans symfony 1.x
 * dans un fichier controller, par exemple :
 * /app/frontend/modules/index/actions/actions.class.php
 * 
 */
class indexActions extends sfActions
    public function preExecute()
    {
        // Le code écrit ici sera executé avant chacune des actions de ce controlleur.
    }
}
?>
 
<?php
/** 
 * prototype d'une telle fonction dans Zend 1.x
 * dans un fichier controller, par exemple :
 * /application/controller/indexController.php
 */
class IndexController extends Zend_Controller_Action
{
    public function init()
    {
        // Le code écrit ici sera executé avant chacune des actions de ce controlleur.
    }
}
?>

Toutefois, Symfony2 propose un mécanisme d'event suffisamment avancé pour reproduire un tel comportement.

Il y a trois étapes pour y arriver :
1. Créer un listner
2. Connecter le listner avec le DIC (Dependecy Injection Controller)
3. Implémenter le preExecute()

1. Créer un listner

Il faut créer un répertoire Listner dans votre bundle et y créer une classe pour votre listner.

<?php
// Dans le fichier /src/MonPath/MonBundle/Listener/ControllerListener
namespace MonPath\MonBundle\Listener; 
use Symfony\Component\HttpKernel\HttpKernelInterface; 
use Symfony\Component\HttpKernel\Event\FilterControllerEvent; 
// Le nom de la classe est à votre discrétion
class ControllerListener 
{	 
    // Le nom de la méthode est également à votre discrétion
    public function onCoreController(FilterControllerEvent $event) 	
    {
        // Récupération de l'event 	
        if(HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) 
        {
            // Récupération du controller    
            $_controller = $event->getController();
            if (isset($_controller[0])) 
            {
                $controller = $_controller[0];
                // On vérifie que le controller implémente la méthode preExecute
                if(method_exists($controller,'preExecute'))
                {
                    $controller->preExecute();
                }
            }
        }
 
    }
}

2. Connecter le listner avec le DIC

Pour cela on va ajouter un service dans le fichier de configuration du projet (/app/config/config.yml).
- On donne le nom que l'on veut au service (ici : controller.pre_execute_listener).
- Ensuite, on lui dit quelle classe utiliser (celle que nous venons de faire).
- Puis on dit que l'on veut le brancher sur un évènement (name: event_listener).
- Et quel évènement en particulier iil faut écouter (event: kernel.controller).
- Enfin on donne la méthode de la classe à exécuter lorsque l'évènement est appelé (method: onCoreController)

#/app/config/config.yml
services:
  controller.pre_execute_listener:
    class: MonPath\MonBundle\Listener\ControllerListener
    tags:
      -  { name: kernel.event_listener, event: kernel.controller, method: onCoreController }

3. Implémenter le preExecute()

Il est maintenant possible de définir dans n'importe quel controller une méthode preExecute() qui sera appelée avant chaque action de ce controller.
Exemple : interdire l'accès à un controller à un utilisateur non loggé

<?php
namespace MonPath\MonBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
class MonController extends Controller
{
    public function preExecute()
    {
        $user = $this->container->get('security.context')->getToken()->getUser();
        if (!is_object($user))
        {
            throw new AccessDeniedException('This user does not have access to this section.');
        }
    }
}

postheadericon Commentaires

  • Betouar Hamza Wednesday 9 May à 17h12

    le listener marche très bien,
    merci pour le partage.