Programmation PHP avec Symfony/Évènement
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
[modifier | modifier le wikicode]composer require symfony/event-dispatcher
Commande
[modifier | modifier le wikicode]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
[modifier | modifier le wikicode]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));
Listener
[modifier | modifier le wikicode]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
[modifier | modifier le wikicode]services:
App\EventListener\MyViewListener:
tags:
- { name: kernel.event_listener, event: kernel.view }
class MyViewListener
{
public function onKernelException(ExceptionEvent $event)
{
echo "Triggered!";
}
}
Subscriber
[modifier | modifier le wikicode]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
[modifier | modifier le wikicode]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');