Raccourcis : Contenu - rubriques - sous rubriques
EN FR

Jelix propose un système de communication inter-module, basé sur le principe d'événements/écouteurs.

Il est possible d'émettre un événement de n'importe quel endroit dans votre code, et les modules qui "écoutent" cet événement pourront y répondre, et même renvoyer des données. C'est donc en quelque sorte un système de broadcast, avec des clients (les émetteurs) et des serveurs (les listeners).

Il y a donc d'une part un objet jEvent, permettant d'émettre un événement et de récupérer les réponses, et d'autre part, des "listeners", qui sont des classes placées dans les modules, contenant les méthodes "répondant" aux événements.

Émettre un évènement

L'objet jEvent sert à la fois d'émetteur d'événement, et en même temps de conteneur des réponses.

Pour émettre un événement, il faut utiliser la méthode statique notify().

Elle accepte en paramètre un nom d'évènement (qui n'est constitué que de caractères alphanumériques), et un tableau facultatif de paramètres (à utiliser selon l'évènement).

Vous recevez en retour l'objet jEvent instancié pour l'occasion, et contenant les réponses (ne pas confondre avec les objets jResponse, utilisés dans les contrôleurs). Les réponses sont un ensemble de valeurs dont la structure et le nombre dépend de l'événement et du nombre de modules ayant répondu.


   //exemple avec paramètre
   $eventParams = array('user' => $userObject);
   $theEvent = jEvent::notify('authCanLogin', $eventParams);
 
   //exemple sans paramètres
   $theEvent = jEvent::notify('authCanLogin2');

Pour accéder aux données des réponses retournés par les listeners des modules, il faut utiliser la méthode getResponse de l'objet jEvent qui a été retourné par notify:


  $reponses = $theEvent->getResponse();

Le résultat est un tableau des données que chaque module à renvoyé.

Vous avez d'autres méthodes pour manipuler les données retournées :

  • inResponse($responseKey, $value) : indique si il existe une clé avec la valeur donnée dans les données retournées.
  • getResponseByKey($responseKey) : renvoi la liste des données qui correspondent à la clé donnée (renvoi null si il n'y a aucune donnée avec cette clé)
  • allResponsesByKeyAreTrue($responseKey) : indique si toutes les données avec la clé donnée ont la valeur true.
  • allResponsesByKeyAreFalse($responseKey) : indique si toutes les données avec la clé donnée ont la valeur false.

Répondre à un évènement

Il n'y a pas de listener par défaut dans les modules. Aussi, pour qu'un module puisse répondre à un événement, il faut en créer un, et le déclarer dans le fichier events.xml du module. Il n'y a pas de limite du nombre de listener.

Il y a deux choses à faire pour un listener : le créer, puis le déclarer.

Créer le listener

Un listener est une classe stockée dans classes avec un nom spécifique.

Depuis Jelix 1.8.1, cela peut être une classe stockée n'importe où, avec n'importe quel nom, et qui doit être auto-chargeable. Ce qui est beaucoup moins contraignant.

Pour créer un listener dans classes, il faut d'abord lui donner un nom logique. Nous allons utiliser "auth" par exemple. Ensuite il faut créer une classe pour le listener. Son nom est une concatenation du nom logique avec "Listener". Stocker cette classe dans un fichier qui a pour nom nomlogique.listener.php, et donc auth.listener.php pour notre exemple, ce fichier devant être dans le dossier classes du module.

Une classe de listener doit hériter de jEventListener et doit contenir une méthode pour chaque évènement auquel le listener répond. Ces noms de méthodes commencent par on suivi du nom d'événement. Et ces méthodes prennent en paramètre l'objet jEvent correspondant à l'événement. Exemple :


class authListener extends jEventListener {
// ou
// class \MyModule\Listeners\Auth extends \jEventListener {

   function onAuthCanLogin ($event) {

        // recupération d'un paramètre de l'événment
        $user = $event->getParam('user');

        // traitement
        $ok = true;
        if (isset($user->actif)) {
            $ok = ($user->actif == '1');
        }

        $ok = $ok && ($user->password != '');

        // renvoi de donnée en réponse
        $event->add(array('canlogin'=>$ok));
   }
}

Ce listener répond à l'évènement "AuthCanLogin". La méthode récupère le paramètre 'user' de l'évènement. Et ajoute une donnée dans la réponse avec la méthode add. Ce paramètre et cette donnée de réponse dépendent uniquement de l'évènement AuthCanLogin. Pour d'autres évènements, il peut y avoir plusieurs paramètres ou aucun, d'autres types de données de réponses ou aucune réponse.

Pour les évènements dont le nom ne peut correspondre à un nom de méthode, comme un nom comportant des points (ex: foo.bar), vous pouvez indiquer quelle méthode il faut exécuter, dans une propriété eventMapping. Les clés sont les noms d'évènements, les valeurs les noms des méthodes.


class authListener extends jEventListener {

    protected $eventMapping = array(
      'foo.bar' => 'execFooBar'
    );

    function execFooBar ($event) {
        // here process the event.
    }
}

Note : vous pouvez changer la façon dont votre listener traite les évènements (nom des méthodes correspondantes aux évènements etc), en redéfinissant la méthode performEvent() du listener.

Déclarer le listener

il faut ensuite déclarer le listener. Cela se fait dans un fichier events.xml placé à la racine du module. Voici un exemple :


<events xmlns="http://jelix.org/ns/events/1.0">
   <listener name="auth">
       <event name="AuthCanLogin" />
   </listener>
   <!-- or -->
   <listener name="\MyModule\Listeners\Auth">
       <event name="AuthCanLogin" />
   </listener>
</events>

L'attribute name de la balise listener doit contenir le nom logique du listener, si sa classe est stockée dans classes/, ou le nom entier de la classe si elle est auto-chargeable.

Vous pouvez déclarer autant de listener que vous voulez grâce à la balise <listener>. Et dans chacune d'elles vous indiquez tous les évènements que prend en charge le listener, grâce à des balises <event>.

Désactiver des listeners

Il peut arriver que vous vouliez désactiver un listener fourni par un module tiers, pour un tas de raison.

Cela est possible en les indiquant dans la section [disabledListeners] de la configuration principale. Les clés sont les noms d'évènements, les valeurs sont les sélecteurs des listeners ou le nom complet de la classe du sélecteur si elle est autochargeable.


[disabledListeners]
authLogin="aModule~theListener"

Dans cet example, le listener theListener du module "aModule" ne sera pas appelé quand l'évènement authLogin sera émis.

Si vous voulez désactiver plusieurs listener pour un même évènement, utilisez simplement la notation [] pour indiquer un tableau :


[disabledListeners]
authLogin[]="aModule~theListener"
authLogin[]="\MyModule\Listeners\Auth"