9.12. Dispatcheur d'événements, code personnalisé pour certains événements
Le système d'événements permet de construire des systèmes plus complexes avec la capacité de modifier la fonctionnalité en utilisant du code personnalisé pour certains événements. De nombreux hooks de Drupal 7 ont été remplacés par des événements. Cela a permis d'unifier le fonctionnement de nombreuses parties de Drupal et de modules supplémentaires. Le système d'événements lui-même provient de Symfony et se compose des parties suivantes :
Abonnés aux événements (Event Subscribers) - les "abonnés" à des événements spécifiques sont des fonctions ou méthodes qui se déclenchent lors de certains événements. Dans le code, c'est une classe qui implémente l'interface suivante :
\Symfony\Component\EventDispatcher\EventSubscriberInterface
Registre des événements (Event Registry) - collecte et trie selon la séquence de déclenchement les abonnés aux événements. Le registre des abonnés est stocké dans l'objet Event Dispatcher sous forme d'un tableau clé-valeur du nom de l'événement et de la priorité (ordre) de l'événement. Lorsqu'un événement est déclaré en tant que service, l'événement est enregistré comme un dispatcheur disponible globalement.
Dispatcheur d'événements (Event Dispatcher) - le mécanisme dans lequel l'événement est déclenché et qui permet d'appeler les abonnés aux événements au bon moment. En général, au moins une instance du Dispatcheur d'événements est représentée en tant que service. La classe Event Dispatcher implémente :
\Symfony\Component\EventDispatcher\EventDispatcherInterface
Contexte de l'événement (Event Context) - beaucoup d'événements nécessitent un ensemble spécifique de données, qui peut être important pour l'abonné à l'événement. Cela peut être une valeur simple passée à l'abonné, ou bien une classe contenant les données nécessaires. La classe de contexte d'événement étend la classe :
\Symfony\Component\EventDispatcher\Event
Voyons des exemples de travail avec les événements pour mieux comprendre leur fonctionnement.
J'ai ajouté tout le code sur GitHub dans le module drupalbook_examples, vous pouvez télécharger ce module et l'ajouter à votre site :
https://github.com/levmyshkin/drupalbook8
Drupal 8 n'a plus le hook_init() :
https://www.drupal.org/node/2013014
Maintenant, vous pouvez exécuter le code nécessaire lors du chargement de la page en utilisant un Event Subscriber :
modules/custom/drupalbook_examples/drupalbook_examples.services.yml
services:
drupalbook_examples.event_subscriber:
class: Drupal\drupalbook_examples\EventSubscriber\DrupalbookExamplesSubscriber
tags:
- {name: event_subscriber}
Pour connecter un Event Subscriber, vous devez ajouter le service dans le fichier du module *.services.yml. Ici, nous décrivons la classe de l'abonné à l'événement et écrivons le nom event_subscriber dans les tags. Maintenant, il faut créer la classe de l’abonné :
modules/custom/drupalbook_examples/src/EventSubscriber/DrupalbookExamplesSubscriber.php
<?php
namespace Drupal\drupalbook_examples\EventSubscriber;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class DrupalbookExamplesSubscriber implements EventSubscriberInterface {
public function checkForRedirection(GetResponseEvent $event) {
if ($event->getRequest()->query->get('redirect-me')) {
$event->setResponse(new RedirectResponse(\Drupal::url('<front>', [], ['absolute' => TRUE])));
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('checkForRedirection');
return $events;
}
}
Regardons les points principaux de ce code. La classe de notre abonné implémente l’interface EventSubscriberInterface, la méthode principale de cette interface est getSubscribedEvents(), qui détermine à quels événements notre abonné répondra et quelles méthodes seront appelées si l’événement se produit. Dans notre cas, l’événement survient au tout début du fonctionnement de Drupal après le traitement de la requête. Ici, nous appelons la méthode checkForRedirection() si l'événement se produit. Dans la méthode elle-même, si nous recevons le paramètre redirect-me, alors l'utilisateur est redirigé vers example.com.
Ce code fonctionnera à chaque chargement de page, ou presque toujours. En effet, si votre page est mise en cache, elle peut être servie depuis le cache et Drupal n'exécutera pas tout le code, le cache fonctionnera immédiatement.
Dans ce cas, vous pouvez utiliser l'analogue du hook_boot(), qui, comme hook_init(), a été supprimé de Drupal 8 :
https://www.drupal.org/node/1909596
Ajoutons une autre méthode redirectBeforeWithoutCache()
modules/custom/drupalbook_examples/src/EventSubscriber/DrupalbookExamplesSubscriber.php :
<?php
namespace Drupal\drupalbook_examples\EventSubscriber;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class DrupalbookExamplesSubscriber implements EventSubscriberInterface {
public function checkForRedirection(GetResponseEvent $event) {
if ($event->getRequest()->query->get('redirect-me')) {
$event->setResponse(new RedirectResponse(\Drupal::url('<front>', [], ['absolute' => TRUE])));
}
}
public function redirectBeforeWithoutCache(GetResponseEvent $event) {
if ($event->getRequest()->query->get('redirect-me')) {
$event->setResponse(new RedirectResponse(\Drupal::url('<front>', [], ['absolute' => TRUE])));
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('checkForRedirection');
$events[KernelEvents::REQUEST][] = array('redirectBeforeWithoutCache', 300);
return $events;
}
}
Dans la méthode getSubscribedEvents(), nous avons enregistré une réponse au même événement KernelEvents::REQUEST, mais cette fois avec une priorité à 300, ce qui permet à cette méthode de s'exécuter plus tôt que les autres méthodes déclenchées par cet événement ayant une priorité plus faible. Maintenant, la redirection fonctionnera même pour une page en cache.
Il existe de nombreux événements dans Drupal auxquels vous pouvez vous abonner, vous pouvez trouver plus d'exemples dans la documentation officielle :