< Programmation PHP < Symfony

Un évènement est une action pouvant en déclencher d'autres qui l'attendaient, à la manière du patron de conception observateur, via un hook.


Installation

Terminal
Logo
composer require symfony/event-dispatcher

Commande

Pour lister les évènements et écouteurs d'un projet (avec leurs priorités) :

 php bin/console debug:event-dispatcher

Ex :

"console.terminate" event
-------------------------

 ------- ----------------------------------------------------------------------------- ----------
  Order   Callable                                                                      Priority
 ------- ----------------------------------------------------------------------------- ----------
  #1      Symfony\Component\Console\EventListener\ErrorListener::onConsoleTerminate()   -128
  #2      Symfony\Bridge\Monolog\Handler\ConsoleHandler::onTerminate()                  -255
 ------- ----------------------------------------------------------------------------- ----------


Event

Pour utiliser ce système, la première étape consiste à déterminer si on souhaite utiliser un évènement existant, ou en créer un nouveau.

  • Pour un existant, son nom est obtenu par le commande ci-dessus.
  • Pour un nouveau, voici un exemple de conception pilotée par le domaine où l'on souhaite qu'une condition du core soit traitée dans des modules en fonction du groupe utilisateur, sans les lister dans le core :
class AddExtraDataEvent
{
    /** @var string */
    private $userGroup;

    public function __construct(string $userGroup)
    {
        $this->userGroup = $userGroup;
    }

    public function getUserGroup(): string
    {
        return $this->usernGroup;
    }

    public function setUserGroup(string $usernGroup): AddExtraDataEvent
    {
        $this->userGroup = $userGroup;

        return $this;
    }
}

Une fois la classe crée, il faut choisir où l'instancier :

use Symfony\Component\EventDispatcher\EventDispatcher;
...
$this->eventDispatcher->dispatch(new AddExtraDataEvent($userGroup));
 le setter permet de transférer un résultat issu des observateurs de l’évènement, à l'endroit qui les dispatch (qu'il peut récupérer via le getter de l'évènement). Une alternative serait d'injecter à la place de EventDispatcher, un tableau des services des modules concernés, définis par un tag.


Listener

Pour exécuter une ou plusieurs classes au moment du dispatch, il faut créer maintenant en créer une qui écoute l'évènement. Elle doit peut être reliée à son évènement, soit dans sa déclaration de service pour un écouter (event listener[1]), soit dans son constructeur pour un souscripteur (event subscriber).

Le listener a donc l'inconvénient de devoir être déclaré avec un tag, alors que le subscriber lui, est chargé à chaque exécution du programme, ce qui alourdit légèrement les performances mais évite de maintenir sa déclaration en autowiring.

Exemple de déclaration YAML

services:
    App\EventListener\MyViewListener:
        tags:
            - { name: kernel.event_listener, event: kernel.view }
class MyViewListener
{
    public function onKernelException(ExceptionEvent $event)
    {
        echo "Triggered!";
    }
}

Subscriber

Un souscripteur doit forcément implémenter EventSubscriberInterface :

class ViewSubscriber implements EventSubscriberInterface
{
    public function getSubscribedEvents(): array
    {
        return [
            KernelEvents::VIEW => ['onView']
        ];
    }

    public function onView(ViewEvent $event): void
    {
        echo "Triggered!";
    }
}

Autre exemple où on veut embarquer dans un évènement maison une information de ses souscripteurs :

class ClientXUserSubscriber implements EventSubscriberInterface
{
    ...
    public static function getSubscribedEvents(): array
    {
        return [
            ClientXEvent::class => 'getProperty',
        ];
    }

    public function getProperty(ClientXUserEvent $event): void
    {
        if ('X' === $this->user->getCompany()) {
            $event->setProperty('XX');
        }
    }
}

Débogage

Les erreurs qui surviennent selon certains évènements ne sont pas faciles à provoquer ou visualiser. Pour les voir sans passer par le profiler, on peut ajouter temporairement dans un contrôleur :

$this->getEventDispatcher()->dispatch('mon_service');

Références

Cet article est issu de Wikibooks. Le texte est sous licence Creative Commons - Attribution - Partage dans les Mêmes. Des conditions supplémentaires peuvent s'appliquer aux fichiers multimédias.