Zend framework 2 – le gestionnaire d’événements Zend\EventManager

le gestionnaire d’événements Zend\EventManager  (introduction) :

(article en cours de rédaction)

Le gestionnaire d’évènements Zend\EventManager est un composant clé du système MVC de ZF2 . Il permet à des classes de publier des évènement  que d’autres objets vont pouvoir écouter et agir en conséquence.
 
L’EventManger est utilisé par plusieurs composants importants de ZF2 comme le Module Manager et Le système MVC de l’application se base sur l’EM dans le but de pouvoir déclencher des actions à plusieurs moments dans la vie d’une requête utilisateur.
Dès le démarrage, ZF2 instancie (en passant par la fabrique de la classe Application),  le Service Manager qui va fournir les composant essentiels à l’application (à commencer par l’ Event Manager puis le Module Manager). par la suite l’application va se lancer en générant des évènements qui vont se suivre à chaque étape de la vie de la requète (grâce la l’EM). Ce qui va faire s’executer les différents composants de ZF2 dès que les évènement qui les concernent sont déclenchés.

L’Event Manager supprime, ainsi,  l’utilisation des hooks de ZF1 (preDispatch , postDispatch,  etc…) , et à la place ZF2 permet d’attacher des traitements aux évènements de l’application (bootstrap, routage, dispatch, rendu de la vue, fin de la requête ).

 la grande puissance de l’EM est qu’il permet d’étendre les modules ainsi que l’application elle même simplement en enregistrant des callback qui seront exécutés au moment où l’évènement qu’il écoutent est déclenché. on peut aussi par exemple dans le cas d’un module d’authentification générer des évènements (ex : ‘userLogin‘, ‘userLogin.post‘, ‘userLogout‘, ‘authBadPassword‘ etc…). dans ce cas un autre module pourra l’étendre sans surcharger son code : on pourra par exemple avoir un module qui va vérifier les derniers messages si l’événement ‘userLogin.post‘ est enclenché, un autre module pourra vider des caches de messagerie/profile/etc si ‘userLogout‘ est enclenché, un module de sécurité pourrai par exemple comptabiliser les tentatives infructueuses de logins à chaque enclenchement de l’événement ‘authBadPassword‘ et donc agir en conséquence comme par exemple écrire dans une log ou afficher un captcha, etc…comme vous pouvez le comprendre, on peut apporter des fonctionnalités suplémentaire à l’application sans être obligé de modifier l’éxistant, mais plutôt en enclenchant des traitement avant/pendant/après un évènement enclenché par l’application.

Ci dessous la terminologie que l’on utilisera par la suite :

  • EventManager : le gestionnaire d’évènements est l’objet qui stocke des écouteurs pour un ou plusieurs évènements et sert à déclencher ces évènements.
  • event : un évènement est en fait une action ou qqch qui se passe et auquel on donne un nom (que l’objet event portera). il est déclenché via l’EventManager.
  • listener : un écouteur est une fonction appelable qui est enregistré à un/des évènements (fonction php, callback : fonction anonyme, callable : méthode de classe ou d’objet) . il sera exécuté quand l’évènement écouté est déclenché.

le minimum pour commencer :

  • une instance de l’EM ($em = new EventManager )
  • un/des listener(s) enregistré(s) à un/des évènements ( $em->attach(…) )
  • un déclenchement d’évènement ( $em->trigger(…) )

En plus de servir à agréger une collection de listeners ( = écouteurs d’évènements) et d’être utilisé pour déclencher des évènements, l’ EventManager permet aux évènement (sous forme d’objets existants indépendants) de transférer des informations relatives à l’évènement lui-même . :

  • référence à l’endroi dans le code où l’évènement à été déclenché
  • un contexte (en général on utilise le nom de la classe/fonction)
  • des paramètres utiles que les listeners pourront utiliser

un évènement (avec ses paramètres) sera déclenché dans un contexte  donné (pour ainsi éviter les collisions d’évènements) : on peut avoir un évènement ‘refresh_data’ dans le contexte  ‘Messages’ et le même dans le contexte ‘Profile’

Une pratique courante est d’utiliser un EventManager dans une classe/objet. ( ce que nous verons plus tard) . il arrive aussi que l’on dédie un EventManager à un périmètre logique, ce qui est le cas du système MVC de ZF2 qui a sont propre EM.  on pourra ainsi ajouter/supprimer des listeners (écouteurs) selon un workflow (suite d’opérations) dans notre application que l’on représentera par des noms d’évènement que l’on va enclencher, par exemple, dans un ordre défini (ou libre, si on veut).

Dé/enregistrement un listener :

déclencher un évènement :

exemple de base:

un évènement est enclenché dans un contexte (ou cible) , c’est le paramètre null dans trigger() rencontré précédemment . par défaut il utilise le nom de la fonction ou le nom de la classe dans le cas d’un callable, (on verra cela en utilisant une EventManager dans une classe).

par ailleurs, quand l’évènement est déclenché, les listeners sont appelés à tour de rôle et reçoivent un objet Event en paramètre qui contient la cible ainsi que des paramètres.

utilisation d’un EventManager dans une classe:

L’exemple est assez simple, et peut être amélioré pour créer un vrai outil de gestion de workflow.

il arrive que l’on veuille attacher des évènement à des gestionnaires d’évènements qui n’ont pas encore été instanciés par l’application. d’où l’existence du gestionnaire d’évènement partagé ou SharedEventManager. celui-ci sert à stocker plusieurs EventManager .

le gestionnaire d’évènements partagé (SharedEventManager) est disponible dès le démarrage de l’application et est disponible à partir de n’importe quel gestionnaire de service ($em->getSharedManager()).

la différence avec le gestionnaire d’événement simple est que l’on spécifie un paramètre en plus : un contexte (auquel un EventManager sera attaché) via lequel on pourra attacher/détacher des listeners et déclencher des évènements.
(rappelez-vous que l’on a spécifié le nom de la classe courante comme contexte dans le constructeur de l’EM del’exemple précédent, dans le gestionnaire partagé on le spécifie dans les fonction attach/detach/trigger )

par exemple, quelque part dans un module on voudrai attacher un listener à notre gestionnaire Task (même si la classe n’est pas encore instanciée)

une foi la classe instanciée, ce traitement s’executera, si un évènement continue est déclenché dans la cible Task. par contre si la classe n’est pas instanciée, si l’évènement est déclenché, il ne se passera rien.

Dans l’exemple on on a utilisé un EventManager dédié à une classe. vous avez probablement remarqué qu’au moment de la création de l’EventManager on lui a passé en paramètre le nom de la classe, ainsi qu’une instance. quand on utilise le gestionnaire partagé, on ajoute un paramètre (en première position) pour spécifier un nom de classe (ou nom d’un périmètre) à utiliser pour y déclencher des évènements et attacher/détacher des listener.

Attachement à plusieurs évènements en même temps

on peut avoir besoin d’attacher un listener à plusieurs évènements, voir tous les évènements.
si on utilise un gestionnaire partagé, on peut attacher un listener à plusieurs évènements et dans plusieurs contextes.

Attachement d’un listener à tous les évènement “wildcard Listener” :

avec le gestionnaire partagé:

Attachement de listeners à plusieurs évènements :

Assignation de priorités

on peut attacher un listener pour qu’il s’exécute avant ou après d’autres listeners.
par défaut les listeners sont attaché avec la priorité 1 et seront executé dans l’ordre où ils ont été attachés. on spécifie la priorité via le dernier paramètre:

cours-circuiter un evenement

il est possible de permettre à un listener de cours-circuiter un évènement. ce qui aura pour conséquence d’arrêter la propagation de l’évènement aux autres listeners (qui écoutent le même évènement).

deux manières de faire :

on peut aussi utiliser un callable/calback en dernier paramètre de la conftion trigger.
si cette fonction renvoie true, la propagation de l’évènement est stoppée (les listener en priorité inférieur ne s’exécuteront pas)

Article en cours de rédaction !! suite à venir

D’autres articles :
 

Did you like this? Share it:

Comments are closed.

Open Close