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

Cours pour apprendre à utiliser le framework Laravel 5.5

Plus loin avec Laravel


précédentsommairesuivant

I. Les événements

I-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 .

I-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 qu'on crée la première classe avec « Artisan » qui dispose de commandes pour le faire :

Image non disponible

I-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 existant déjà dans le framework qui en propose au niveau de l'authentification :

  • registered ;
  • attempting ;
  • authenticated ;
  • login ;
  • failed ;
  • logout ;
  • lockout ;
  • passwordReset.

On trouve aussi des événements avec « Eloquent » :

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

Pour tous ces cas, vous n'avez donc pas à vous inquiéter du déclencheur qui existe déjà.

I-B-2. Une application de test

Pour nos essais, créez une nouvelle application Laravel 5.5 :

 
Sélectionnez
composer create-project --prefer-dist laravel/laravel laravel5

Lancez les migrations :

 
Sélectionnez
php artisan migrate

puis ajoutez l'authentification :

 
Sélectionnez
php artisan make:auth

Créez un utilisateur à partir du formulaire d'enregistrement :

Image non disponible

I-B-3. Le fournisseur de service (service provider)

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

Image non disponible

Par défaut, 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.
31.
32.
<?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 = [
        'App\Events\Event' => [
            'App\Listeners\EventListener',
        ],
    ];

    /**
     * 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.

Laravel prévoit de placer les observateurs (listeners) dans un dossier app/isteners (qui n'existe pas au départ) en tant que classes, ainsi que les événements (events) dans le dossier Events (qui n'existe pas au départ).

I-C. On crée une écoute

On va utiliser l'événement intégré à Laravel qui se déclenche lorsqu'un utilisateur se connecte. La classe correspondante est Illuminate\Auth\Events\Login. Puisque l'événement existe, on n'a pas à créer une classe Event. Par contre il nous faut une écoute (Listener) :

 
Sélectionnez
php artisan make:listener Login

La classe Login se crée ainsi que le dossier :

Image non disponible

Voici le code généré :

 
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\Listeners;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class Login
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  object  $event
     * @return void
     */
    public function handle($event)
    {
        //
    }
}

On va établir le lien entre l'événement et l'écoute dans le provider EventServiceProvider :

 
Sélectionnez
protected $listen = [
    'Illuminate\Auth\Events\Login' => ['App\Listeners\Login'],
];

Donc maintenant, dès que l’utilisateur va se connecter, la méthode handle de notre écoute va être appelée. Mais qu'y a-t-il dans la variable $event ? On va faire un petit test :

 
Sélectionnez
1.
2.
3.
4.
public function handle($event)
{
    dd($event);
}

Là, dès qu'on se connecte, on obtient :

 
Sélectionnez
1.
2.
3.
4.
Login {#218 ▼
  +user: User {#224 ...}
  +remember: false
}

une instance de la classe Illuminate/Auth/Events/Login avec deux propriétés : une instance du modèle de l'utilisateur et un booléen pour le remember. On aurait aussi pu trouver ces informations en allant voir directement la classe.

Changez ainsi le code :

 
Sélectionnez
1.
2.
3.
4.
public function handle($event)
{
    dd($event->user->name . " s'est connecté.");
}

Cette fois, à la connexion, on obtient quelque chose dans ce genre :

 
Sélectionnez
"Durand s'est connecté."

On peut donc ici effectuer tous les traitements qu'on veut, comme comptabiliser les connexions.

I-D. On crée un événement

Maintenant, on va créer un événement et aussi son écoute. On va imaginer qu'on veut savoir quand quelqu'un affiche la page d'accueil. C'est un peu idiot, mais avec le peu qu'on a dans l'application par défaut, on ne va pas faire les difficiles, et de toute façon, c'est pour voir le processus de codage.

On crée l'événement :

 
Sélectionnez
php artisan make:event Accueil

On le trouve ici avec la création du dossier :

Image non disponible

avec ce code par défaut :

 
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.
31.
32.
33.
34.
35.
36.
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class Accueil
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

On ne va pas toucher à ce code.

On crée aussi l'écoute :

 
Sélectionnez
php artisan make:listener Accueil

et le lien dans le provider EventServiceProvider :

 
Sélectionnez
protected $listen = [
    'App\Events\Accueil' => ['App\Listeners\Accueil'],
];

Il ne reste plus qu'à déclencher cet événement dans le contrôleur HomeController :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
public function index()
{
    event(new Accueil);
    
    return view('home');
}

Maintenant, chaque fois que la page d'accueil est ouverte, l'événement Accueil est déclenché et donc l'écoute Accueil en est informée.

Si on a des informations à transmettre, il suffit de prévoir des propriétés pour l'événement et ça sera transmis à l'écoute.

I-E. L'application d'exemple

Dans l'application d'exemple, on a deux événements avec leur écoute :

Image non disponible

La liaison entre événement et écoute est réalisée comme vu plus haut dans le provider EventServiceProvider :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
protected $listen = [
    'App\Events\ModelCreated' => [
        'App\Listeners\ModelCreated',
    ],
    'App\Events\PostUpdated' => [
        'App\Listeners\PostUpdated',
    ],
];

I-E-1. Modèle créé

Le premier événement est déclenché quand un modèle est créé. C'est un événement déjà prévu dans Eloquent. Pour le lier avec notre événement, il faut renseigner dans le modèle la propriété $dispatchesEvents. Par exemple pour le modèle Comment :

 
Sélectionnez
protected $dispatchesEvents = [
    'created' => ModelCreated::class,
];

Il suffit donc de prévoir ça pour tous les modèles concernés. Comme il s'agit dans l'application de connaître le nombre de nouveaux contacts, articles, utilisateurs et commentaires, on va le prévoir sur tous les modèles correspondants. J'ai déjà évoqué ce point dans le chapitre sur le polymorphisme. J'ai alors expliqué le code du listener :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
public function handle(EventModelCreated $event)
{
    $event->model->ingoing()->save(new Ingoing);

    Thumb::makeThumb ($event->model);
}

On a vu qu'on mémorisait la nouvelle création dans la table ingoings.

On voit que l'événement transmet une instance du modèle créé (propriété $model) :

 
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.
<?php

namespace App\Events;

use Illuminate\ {
    Queue\SerializesModels,
    Database\Eloquent\Model
};

class ModelCreated
{
    use SerializesModels;

    public $model;

    /**
     * Create a new event instance.
     *
     * @param Model $model
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }
}

On fait autre chose avec la seconde ligne de code dans le listener : on crée une image miniature de celle prévue pour l'article à fin d'affichage dans l'administration :

Image non disponible

En effet, il ne serait pas judicieux de charger les images en haute résolution pour ensuite les afficher en miniature. On crée donc des images réduites :

Image non disponible

C'est la classe App\Services\Thumb qui est chargée de créer ces miniatures. Sous le capot, c'est le superbe package intervention/image qui est utilisé.

I-E-2. Article modifié

Le second événement se déclenche lorsqu'un article est modifié. En effet, il est alors possible que l'image de l'article ait été modifiée et il faut donc régénérer la miniature.

Dans le modèle Post, on trouve donc la déclaration des deux événements :

 
Sélectionnez
1.
2.
3.
4.
protected $dispatchesEvents = [
    'created' => ModelCreated::class,
    'updated' => PostUpdated::class,
];

et dans le listener PostUpdated, on trouve la régénération éventuelle de l'image :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
public function handle(EventPostUpdated $event)
{
    if($event->model->wasChanged ('image')) {
        Thumb::makeThumb ($event->model);
    }
}

Eloquent mémorise les valeurs originales des attributs et la méthode wasChanged permet de savoir si un attribut a été modifié.

I-F. En résumé

  • Laravel permet d'utiliser la programmation événementielle.
  • Laravel comporte des événements préexistants au niveau de l'authentification et d'Eloquent.
  • On peut créer des événements (Events) et des écoutes (Listeners), et les mettre en relation.

précédentsommairesuivant

Copyright © 2018 Maurice Chavelli. 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.