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 : 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.
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 :
- des classes Listener placées dans le dossier app/Listeners :
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.
- creating,
- created,
- updating,
- updated,
- saving,
- saved,
- deleting,
- deleted,
- restoring, restored.
Le fournisseur de service (service provider)
Il y a un fournisseur de service dédié aux événements : Dans l'application d'exemple on a ce code :<?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 :
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 :
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 3 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.
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) :<?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 :
<?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 :
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.
La deconnexion
Et évidemment en cas de déconnexion c'est le même processus avec le listener LogoutSuccess :<?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 :
public static function setVisitorStatut() { session(['statut' => 'visitor']); }
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 : Avec ce code :<?php namespace App\Events; class UserAccess extends Event { // }Oui il n'y a que la classe parce qu'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 :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 :
Event::fire(new UserAccess);Au niveau de l'inscription on a vu qu'on a ceci :
protected $listen = [ ... 'App\Event\UserAccess' => ['App\Listeners\UserAccess'] ];Voici le code du listener :
<?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 :
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 qu'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 qu'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.
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.
Par bestmomo
Aucun commentaire