IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tutoriel pour apprendre à utiliser le framework Laravel 5.3

Plus loin


précédentsommairesuivant

IV. Les événements

Il y a plusieurs façons de programmer. En général la plus simple et la plus lisible consiste à procéder de façon séquentielle : on a une suite d'instructions (modulables par des conditions) qui sont toujours les mêmes. Le flux est facile à suivre.

Mais on a aussi l'approche événementielle. On va réagir à des événements susceptibles de se produire. On peut mettre ainsi en place un ensemble constitué par une partie qui détecte des événements et une autre qui les gère.

Laravel permet de gérer avec facilité les événements comme on va le voir dans ce chapitre.

IV-A. Le design pattern Observateur

Le design pattern Observateur (observer) établit une relation de type 1:n entre des objets. Si l'objet côté 1 change d'état, il en informe les objets côté n pour qu'ils puissent agir en conséquence. Ça implique une intendance et les objets doivent pouvoir s'inscrire et se mettre à l'écoute des événements du sujet.

Voici une visualisation de ce design pattern :

Image non disponible

On a un sujet et des observateurs. Les observateurs doivent s'inscrire (on dit aussi s'abonner) auprès du sujet. Lorsque le sujet change d'état il notifie tous ses abonnés. Un observateur peut aussi se désinscrire, il ne recevra alors plus les notifications.

Vous pouvez trouver une description détaillée de ce design pattern ici.

IV-B. Organisation du code

Laravel implémente ce design pattern et le rend très simple d'utilisation. On va avoir :

  • des classes Event placées dans le dossier app/Events :
Image non disponible
  • des classes Listener placées dans le dossier app/Listeners :
Image non disponible

Ces dossiers n'existent pas dans l'installation de base, ils sont ajoutés dès que l'on crée la première classe avec Artisan qui dispose de commandes pour le faire :

Image non disponible

IV-B-1. Les événements déjà présents dans Laravel

Mais il n'y a pas que les événements que vous allez créer. Vous pouvez utiliser les événements existants déjà dans le framework qui en propose au niveau de l'authentification :

  • tentative de connexion (login) ;
  • connexion (login) réussie ;
  • déconnexion (logout) réussie.

On trouve aussi des événements avec Eloquent :

  • creating ;
  • created ;
  • updating ;
  • updated ;
  • saving ;
  • saved ;
  • deleting ;
  • deleted ;
  • restoring, restored.

Pour tous ces cas, vous n'avez donc pas à vous inquiéter de l'événement et du déclencheur qui existent déjà, il faudra juste mettre en place une écoute (Listener).

IV-B-2. Le fournisseur de service (service provider)

Il y a un fournisseur de service dédié aux événements :

Image non disponible

Dans l'application d'exemple on a ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
<?php
 
namespace App\Providers;
 
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
 
class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'Illuminate\Auth\Events\Login' => ['App\Listeners\LoginSuccess'],
        'Illuminate\Auth\Events\Logout' => ['App\Listeners\LogoutSuccess'],
        'App\Events\UserAccess' => ['App\Listeners\UserAccess']
    ];
 
    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();
    }
}

On a une propriété listen pour les abonnements. C'est un simple tableau qui prend l'événement (event) comme clé et l'observateur (listener) comme valeur.

On veut savoir quand quelqu'un se connecte ou se déconnecte. On prévoit donc des observateurs dans le provider :

 
Sélectionnez
1.
2.
3.
4.
5.
protected $listen = [
    'Illuminate\Auth\Events\Login' => ['App\Listeners\LoginSuccess'],
    'Illuminate\Auth\Events\Logout' => ['App\Listeners\LogoutSuccess'],
    ...
];

Vous pouvez trouver ces événements dans la documentation.

Laravel prévoit de placer les observateurs (listeners) dans ce dossier en tant que classes :

Image non disponible

IV-C. Le statut de l'utilisateur dans l'application

Pour simplifier la gestion le statut de l'utilisateur (son rôle) est enregistré dans la session. On a trois rôles :

  • Administrateur (admin) : avec tous les droits ;
  • Rédacteur (redac) : avec le droit de gérer des articles ;
  • Utilisateur (user) : avec juste le droit de laisser des commentaires.

Et on ajoute visitor pour un utilisateur non connecté.

IV-C-1. La connexion

Donc dès que quelqu'un se connecte on doit regarder son rôle et le mémoriser dans la session.

Si on regarde l'observateur (listener) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?php
 
namespace App\Listeners;
 
use Illuminate\Auth\Events\Login;
use App\Services\Statut;
 
class LoginSuccess
{
    /**
     * Handle the event.
     *
     * @param  Login  $login
     * @return void
     */
    public function handle(Login $login)
    {
        Statut::setLoginStatut($login);
    }
}

On fait appel à un service avec une méthode statique :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?php
 
namespace App\Services;
 
class Statut
{
    /**
     * Set the login user statut
     *
     * @param  Illuminate\Auth\Events\Login $login
     * @return void
     */
    public static function setLoginStatut($login)
    {
        session(['statut' => $login->user->getStatut()]);
    }
 
    ...
}

Il faut aller voir dans le modèle App\Models\User pour trouver la méthode :

 
Sélectionnez
1.
2.
3.
4.
public function getStatut()
{
    return $this->role->slug;
}

On passe par la relation entre les utilisateurs et les rôles pour aller chercher l'information à mettre dans la session.

IV-C-2. La deconnexion

Et évidemment en cas de déconnexion c'est le même processus avec le listener LogoutSuccess :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?php
 
namespace App\Listeners;
 
use Illuminate\Auth\Events\Logout;
use App\Services\Statut;
 
class LogoutSuccess
{
    /**
     * Handle the event.
     *
     * @param  Logout  $event
     * @return void
     */
    public function handle(Logout $event)
    {
        Statut::setVisitorStatut();
    }
}

On utilise encore le service :

 
Sélectionnez
1.
2.
3.
4.
public static function setVisitorStatut()
{
    session(['statut' => 'visitor']);
}

IV-C-3. Accès à une page

Il faut considérer un dernier cas : lorsque l'utilisateur accède à une page on va vérifier s'il y a un statut mémorisé en session et si ce n'est pas le cas, en créer un.

Cette fois ce n'est pas un événement qui existe comme login ou logout, il nous faut donc le créer.

On a donc cette fois une classe Event :

Image non disponible

Avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<?php
 
namespace App\Events;
 
class UserAccess extends Event
{
    //
}

Oui il n'y a que la classe parce que l'on a rien de particulier à transmettre dans ce cas.

On doit donc déclencher cet événement quand un utilisateur accède à une page.

On va donc passer par un middleware. Regardez dans la classe App\Http\Middleware\App :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
public function handle(Request $request, Closure $next)
{
    event(new UserAccess);
 
    return $next($request);
}

On utilise l'helper event pour déclencher l'événement. Sans l'helper il faudrait utiliser la façade :

 
Sélectionnez
Event::fire(new UserAccess);

Au niveau de l'inscription on a vu que l'on a ceci :

 
Sélectionnez
1.
2.
3.
4.
protected $listen = [
    ...
    'App\Event\UserAccess' => ['App\Listeners\UserAccess']
];

Voici le code du listener :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<?php
 
namespace App\Listeners;
 
use App\Events\UserAccess as UserAccessEvent;
use App\Services\Statut;
use App\Services\Locale;
 
class UserAccess
{
    /**
     * Handle the event.
     *
     * @param  UserAccess  $event
     * @return void
     */
    public function handle(UserAccessEvent $event)
    {
        Statut::setStatut();
 
        Locale::setLocale();
    }
}

On appelle encore la méthode dans le service :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
public static function setStatut()
{
    if (!session()->has('statut')) {
        session(['statut' =>  auth()->check() ?  auth()->user()->getStatut() : 'visitor']);
    }
}

On a la logique ici : si on n'a pas de statut dans la session on regarde si l'utilisateur est connecté, si c'est le cas on va chercher son statut, sinon on lui affecte le statut visitor.

Remarquez aussi dans le listener la gestion de la locale que l'on a vue dans un précédent chapitre.

Pour avoir la documentation complète sur ce sujet c'est dans la documentation.

La programmation événementielle en PHP est un certain style de programmation. Elle n'a rien d'obligatoire parce que l'on peut toujours s'en passer si on préfère coder de façon plus classique. Mais il y a de nombreuses situations où elle présente un intérêt certain, en particulier quand un événement possède plusieurs observateurs indépendants les uns des autres. D'autre part Laravel offre des événements précodés, comme on l'a vu dans ce chapitre, qu'il serait dommage de ne pas utiliser.

IV-D. En résumé

  • Laravel comporte un système complet et simple de gestion des événements.
  • Laravel comporte déjà des événements pour l'authentification et la gestion des données avec Eloquent.
  • On doit créer une classe Event et une classe Listener pour mettre en place une gestion événementielle et ensuite définir un déclencheur.

précédentsommairesuivant

Copyright © 2017 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.