Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 05-12-2012 19:31:37

neilime
Membre
Date d'inscription: 28-04-2009
Messages: 42

Conseil d'organisation autour des évenements

Bonjour,

Je suis en train de mettre en place la partie événementielle de mon application, et j'aurai besoin d'avis sur la bonne architecture / gestion à mettre en place.

Voilà un cas concret qui s'axe autour de trois modules : "Utilisateur" (login, inscription des utilisateurs), "Messenger" (envoi de messages internes, par mail, sms...)  et "Logger" (Enregistre les requêtes, erreurs... en bdd, fichiers...)

Le scénario : "Lorsqu'un utilisateur s'inscrit, un mail lui est envoyé (ses identifiants), un log est enregistré en BDD. Si une erreur se produit, on enregistre l'erreur en log, et on envoi cette erreur par mail à l'admin"

Ce que j'ai mis en place :

Le module "Utilisateur" possède un Service utilisateur, et un Modèle utilisateur.
Le module "Messenger" possède un Service message (entre autre).
Le module "Logger" possède un Service log (entre autre).

Lors de l'inscription, le controller appelle la fonction "inscription" du Service qui appelle la fonction "creation" du Modèle.

Donc j'aurai donc un event "creation_utilisateur" qui serai déclenché par le Modèle utilisateur après avoir effectué l'insert en base de données.

Quelle serai la solution la plus pertinente pour que le Service message envoi le mai à cet utilisateur et pour que le service log enregistre cette action.

Merci d'avance pour vos réponses

Hors ligne

 

#2 07-12-2012 00:11:49

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Conseil d'organisation autour des évenements

Salut,

Je n'ai pas encore utilisé de manière extensive les évènements mais, effectivement, l'envoi de mail et la gestion des logs est un cas pertinent.

Qu'est-ce que la fonction Creation du modèle ?

Quant aux évènements, le plus judicieux serait de les regrouper au sein des services. Dans ton scénario, on pourrait très bien coder en dur la séquence directement dns la fonction inscription du service, comme ceci :

Code:

public function inscription($user)
{
    try {
         $mapper->createUserInDatabase($user)
    } catch($e) {
         $log->addError('Problème à l'inscription');
         $mailerService->sendEmail('administrator@administrator.com', 'Problème à l'inscription');
    }

    // Pas d'erreur
    $log->addMessage('Nouvel utilisateur');
    $mailerService->sendEmail($user->getEmail(), 'Merci de ton inscription');
}

Bref, on a codé "en dur" la logique. Mais effectivement ce n'est pas très maintenable. Si tu souhaites réaliser une autre action, tu vas effectivement devoir rajouter une autre action.

L'idée c'est effectivement de lancer des évènements, et de créer des "écouteurs" (des listeners) qui vont réagir à ces évènements. Par exemple, on pourrait réécrire le code précédent ainsi :

Code:

public function inscription($user)
{
    try {
         $mapper->createUserInDatabase($user)
    } catch($e) {
         $this->events->trigger('inscription.error', array('message' => 'Problème', 'user' => $user);
    }

    // Pas d'erreur
    $this->events->trigger('inscription.post', array('message' => 'Ca marche', 'user' => $user);
}

Et tu aurais ton Logger qui va écouter ces évènements et réagir en conséquence. Evidemment, tu voudras surement faire un logger plus ou moins générique qui va assuemer la présence de certaines clés (message par exemple) dans les arguments de l'évènement.

Après, est-ce que les évènements sont bons à utiliser partout, je ne pense pas. Il y a des cas ou tu sais pertinemment que la réponse à une action donnée d'un service ne bougera pas. Dans ces cas là, c'est largement plus simple de juste coder la logique dans le service plutôt que de passer par le gestionnaire d'évènements.

MAis de manière générale, lorsque tu fais un module à vocation générique, tu devras quasiment tout le temps lancer des évènemetns pour permettre aux autres développeurs ou aux autres modules d'avoir des hooks permettant d'ajouter des comportements.

Hors ligne

 

#3 21-12-2012 11:39:49

neilime
Membre
Date d'inscription: 28-04-2009
Messages: 42

Re: Conseil d'organisation autour des évenements

Voilà finalement le chemin que j'ai pris pour mes évenements.
Prenons le cas du Logger qui enregistre les actions d'insert et update.

J'ai étendu la classe "\Zend\Db\TableGateway\TableGateway" pour lui faire implémenter l'interface "\Zend\EventManager\EventsCapableInterface" et donc j'ai implémenter la méthode "getEventManager" :

Code:

[lang=php]
//...
    /**
     * Get EventManager
     * @return \Zend\EventManager\EventManager
     */
    public function getEventManager(){
        return $this->eventManager instanceof \Zend\EventManager\EventManager
            ?$this->eventManager
            :$this->eventManager = new \Zend\EventManager\EventManager(__CLASS__);
    }
//...

J'ai étendu les méthodes "insert" et "update" afin quelle déclenchent un événement :

Code:

[lang=php]
//...
    /**
     * Insert
     * @param  array $aSet
     * @return int
     */
    public function insert($aSet){
        $iEntityId = parent::insert($aSet);
        $this->getEventManager()->trigger('create_entity',$this,array(
            'entity_id' => $iEntityId,
            'entity_table' => $this->table
        ));
        return $iEntityId;
    }
//...

Ensuite dans le module "Logger" :

J'ai créé une classe "LoggerService" qui implémente l'interface "\Zend\EventManager\SharedEventManagerAwareInterface" avec la méthode "getSharedManager" suivante :

Code:

[lang=php]
//...
    /**
     * Get shared collections container
     * @return \Zend\EventManager\SharedEventManagerInterface
     */
    public function getSharedManager(){
        return $this->sharedEventManager instanceof \Zend\EventManager\SharedEventManagerInterface
            ?$this->sharedEventManager
            :$this->sharedEventManager = \Zend\EventManager\StaticEventManager::getInstance();
    }
//...

Ensuite dans le constructeur du service, j'attache les différents Events dont j'ai besoin :

Code:

[lang=php]
//...
    /**
     * Constructor
     */
    private function __construct(){
        $this->getSharedManager()->attach('*', 'create_entity',array($this,'logCreateEntity'));
        $this->getSharedManager()->attach('*', 'update_entity',array($this,'logUpdateEntity'));
        //...
    }
//...

J'ai ensuite appliqué ce principe à tous les autres modules en fonction de leurs interactions.

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages