PHP     Symfony 2 et 3       AngularJS   Angular2       Cordova/Ionic 2
Daniel G.
Développeur d'applications Web et mobiles - Gironde

TUTORIEL

Utiliser les listener avec le framework Symfony, cela consiste à s'inscrire en tant qu'observateur à des événements de type : Request, Response, Doctrine, Kernel...

Mais aussi, on peut créer son propre évènement pour lui attacher des observateurs. En effet, parfois suite à un événement fonctionnel (inscription d'un utilisateur, validation d'une fiche...) nous voulons exécuter une série d'actions indépendantes les unes des autres comme l'envoi d'un mail à un responsable, effectuer un traitement particulier...

Exécuter une série d'actions métiers indépendantes les unes des autres et de façon non séquentielle (le tout hors du controller)

Le Projet

Lors de la création d'un devis nous voulons informer le service commercial et effectuer un traitement pour mettre à jour les statistiques.
La création du projet Symfony2 :

            symfony new listener_project 2.8
        

UTILISATION

D'abord, l'entité Devis.php :

            namespace AppBundle\Entity;

            use Doctrine\ORM\Mapping as ORM;

            /**
             * Devis
             *
             * @ORM\Table(name="devis")
             */
            class Devis  {
                /**
                 * @var int
                 *
                 * @ORM\Column(name="id", type="integer")
                 * @ORM\Id
                 * @ORM\GeneratedValue(strategy="AUTO")
                 */
                private $id;

                /**
                 * @var string
                 *
                 * @ORM\Column(name="nom", type="string", length=255, nullable=true)
                 */
                private $nom;

                ...   getter et setter  ...
        

L'événement est la création du devis, on va l'appeler : CreateDevisEvent.php et celui-ci va contenir le Devis en question qui sera accessible par les écouteurs.

            namespace AppBundle\Event;

            use Symfony\Component\EventDispatcher\Event;
            use AppBundle\Entity\Devis;


            class CreateDevisEvent extends Event {
                protected $newDevis;

                public function __construct(Devis $newDevis)  {
                    $this->newDevis = $newDevis;
                }

                public function getNewDevis()  {
                    return $this->newDevis;
                }
            }
        

Chaque événement à un nom et la convention est de la déclarer dans une classe finale comme constante :

            namespace AppBundle\Event;

            final class DevisActionEvents  {
                /**
                 * The event affectationServiceCommercial is launched every time a Devis is created
                 * The event traitementStatistique is launched every time a Devis is created
                 *
                 * The event listener get the new Devis
                 *
                 * @var string
                 */
                const CREATE = 'createDevis';
            }
        

La classe CreateDevisEventListener.php contenant les méthodes métier :

            namespace AppBundle\EventListener;

            use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
            use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
            use AppBundle\Event\CreateDevisEvent;


            class CreateDevisEventListener  {
                public function affectationServiceCommercial(CreateDevisEvent $event)  {
                    dump("Affectation au service commercial : " . $event->getNewDevis()->getNom());
                }

                public function traitementStatistique(CreateDevisEvent $event)  {
                    dump("Traitement pour les Statistiques : " . $event->getNewDevis()->getNom());
                }
            }
        


Déclaration du service :
services.yml

                kernel.listener.actionsDevis:
                    class: AppBundle\EventListener\CreateDevisEventListener
                    tags:
                        - { name: kernel.event_listener, event: createDevis, method: affectationServiceCommercial }
                        - { name: kernel.event_listener, event: createDevis, method: traitementStatistique }
        
Remarquez les tags -> event: createDevis qui correspond à la constante : const CREATE = 'createDevis';

Les 2 tags 'createDevis' sont en écoute et font appel respectivement aux méthodes : affectationServiceCommercial et traitementStatistique
de la classe : CreateDevisEventListener.php



Via le service Dispatcher de Symfony, plus qu'à lancer les événements au bon moment c.a.d à la création d'un devis :
DefaultController.php

            /**
             * @Route("/devis", name="devis")
             */
            public function createDevisAction(Request $request)
            {
                $newDevis = new Devis();
                $newDevis->setNom("devis du " . (new \DateTime())->format('Y-m-d H:i:s'));

                // creation de l'évènement et dispatch
                $event = new CreateDevisEvent($newDevis);
                $dispatcher =$this->get('event_dispatcher');

                // sollicitation des écouteurs taggués 'createDevis' avec $event
                $dispatcher->dispatch( DevisActionEvents::CREATE  , $event);

                exit;
            }
        

Ainsi, le code métier est déporté en dehors du controller et chaque action est lancée indépendamment les unes des autres.

Listener/Subscribers

Listener et Subscribers font la même chose sauf qu'un Subscribers est une collection de Listener.

Un Listener peut être réutilisé si besoin pour un autre évènement alors qu'avec le Subscribers on ne peut pas mettre en commun un des listener de la collection. Selon les projets on peut utiliser l'un ou l'autre....