Comprendre le composant EventDispatcher de Symfony

par | Jan 18, 2021 | Web & Mobile

Une des initiatives introduites dans Drupal 8 est le remplacement du mécanisme de hooks par le composant Event dispatcher.

Ceci peut paraître compliqué pour certains développeurs qui ont passé de nombreuses années sur des projets Drupal 7 (ou inférieur) et qui ne maîtrisent pas, forcément, le framework Symfony.

Dans cet article nous allons illustrer ce concept avec des analogies de la vie courante et des exemples de code.

Qu’est ce que l’EventDispatcher?

Ci-dessous une citation (traduite) de la documentation officielle de Symfony.

“Le composant EventDispatcher fournit des outils qui permettent aux composants de votre application de communiquer entre eux en distribuant des événements et en les écoutant.”

Pas très clair… Non ? Pour faire simple, il faut savoir que le système d’Events est constitué des composants suivants :

  • Event: qui désigne l’événement d’origine.
  • Event Listener ou Event Subscriber: Les acteurs qui veulent intercepter l’événement d’origine (Event)
  • Event Dispatcher: le responsable de communication entre les précédents composants.

Maintenant, prenons un exemple de la vie courante. Imaginez qu’après le travail, vous passez au magasin du quartier faire des petites courses. Vous appelez chez vous pour demander si quelqu’un à besoin de quelque chose. Sur le chemin, vous recevez plusieurs SMS et la liste de course s’allonge…

A partir de cet exemple nous pouvons dégager les 3 composants:

  • Event: Faire les courses.
  • Event Listener ou Event Subscriber: Chez vous
  • Event dispatcher: votre smartphone.

Simple ! Non ?

Exemple de code

Maintenant, passons à un exemple un peu plus concret. Le scénario est le suivant : Nous avons un script PHP qui affiche un message. Notre but sera d’intercepter le message et le modifier avant son affichage.

<?php
 
class ContentToOutput
{
   protected $content;
 
   public function __construct(string $content = '')
   {
       $this->content = $content;
   }
 
   public function setContent(string $content)
   {
       $this->content = $content;
   }
 
   public function getContent()
   {
       return $this->content;
   }
}
 
// ============== MAIN PROGRAM ================= //
 
// Initialisation du message
$message = new ContentToOutput('hello');
 
// Interceptor le message ici 
// …
 
// Affichage du message.
echo $message->getContent();

Rien de sorcier, le code ci-dessus ne fait qu’afficher le mot ‘Hello’.

La première étape sera d’installer le composant:

composer require symfony/event-dispatcher

Ensuite il faut créer un Event qu’on appellera BeforeOutputEvent.

// Create an event
class BeforeOutputEvent extends Event
{
   const NAME = 'before.output';
 
   protected $content;
 
   public function __construct(ContentToOutput $content)
   {
       $this->content = $content;
   }
 
   public function getOutputContent()
   {
       return $this->content;
   }
}

Maintenant c’est au tour de l’Event Listener (Qui va intercepter le message avant son affichage)

class OutputListener
{
   public function onBeforeOutput(BeforeOutputEvent $event)
   {
       $content = $event->getOutputContent();
       $out = $content->getContent();
       $content->setContent('Listener (' . $out . ')');
   }
}

Le Listener ci-dessus va intercepter le message Hello et le convertir en Listener ( Hello )

Il ne reste plus qu’à modifier le programme principal comme suit :

// ============== MAIN PROGRAM ================= //
 
// Initialisation du message
$message = new ContentToOutput('hello');
 
// Initialisation de l’event dispatcher
$dispatcher = new EventDispatcher();
// Enregistrer le listener.
$listener = new OutputListener();
$dispatcher->addListener('before.output', [$listener, 'onBeforeOutput']);
 
// Dispatch de l’event.
$dispatcher->dispatch(new BeforeOutputEvent($message), BeforeOutputEvent::NAME);
 
// Affichage du message.
echo $message->getContent();

Vous trouverez les codes complets dans les liens suivants :

Event Listener vs Event Subscriber

Event ListenerEvent Subscriber
Ecoute un seul EventPeut s’inscrire à plusieurs Events
Priorité d’exécution définie dans le dispatcherPriorité d’exécution définie dans l’event Subscriber
* Visuel de couverture par: @benofthenorth