Il est de plus en plus courant, dans une application web moderne, d'afficher les informations en temps réel à l'utilisateur. On a recours pour cela aux Websockets qui vont permettre la communication direct entre le serveur et le client. Laravel offre pour cela un système de "broadcast" qui va permettre de transmettre les évènements au serveur de websocket par l'intermédiaire de Redis ou Pusher.
Redis, liaison PHP / Websocket
Le principal problème est donc de transmettre un évènement émit depuis PHP vers la partie Websocket. Pour cela Laravel dispose de 2 drivers :
- pusher, qui est un service tiers.
- redis, qui est une base de données mémoire capable de gérer un système de PUBLISH / SUBSCRIBE
Nous allons ici utiliser Redis afin de ne pas dépendre d'un tiers pour le fonctionnement de notre site. Il faudra rajouter une dépendance à notre projet afin de communiquer avec cette nouvelle base :
composer require predis/predis
Vous devrez aussi modifier le fichier de configuration afin de renseigner le type de driver à utiliser. Ceci se fait gràce au fichier config/broadcasting.php
.
Emettre notre premier évènement
Pour "broacast" un évènement il suffit d'implémenter l'interface ShouldBroadcast
.
<?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 PostCreatedEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* @var array
*/
public $post;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(array $post)
{
$this->post = $post;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new Channel('chan-demo');
}
}
L'interface ne déclare qu'une seule méthode broadcastOn
qui doit renvoyer le channel sur lequel on doit émettre l'évènement. Ce channel être de plusieurs types :
Channel
pour un channel publicPrivateChannel
pour un channel privée (qui nécessite une authentification)PresenceChannel
pour un channel privée qui gère le système de présence des utilisateur (nécessite aussi une authentification)
Lorsque vous émettez l'évènement event(new PostCreatedEvent($post));
, il sera alors serialisé et "publié" sur Redis.
Les Websockets
Maintenant que l'on est capable d'émettre un évènement il faut être capable de le renvoyer en temps réel au client. Pour cela on doit créer un serveur de websocket qui va s'abonner à Redis. laravel-echo-server est une serveur NodeJS spécifiquement conçu pour gérer le système d'évènement mis en place par Laravel. Vous pouvez l'installer simplement gràce à la commande
npm install -g laravel-echo-server
Et ensuite initialiser le projet via
laravel-echo-server init
Cette commande aura pour effet de créer un fichier laravel-echo-server.json qui contiendra la configuration de votre serveur NodeJS.
Vous pouvez ensuite lancer le serveur via la commande
laravel-echo-server start
Côté client
Côté client on va charger la librairie socket.io depuis notre serveur websockets et le JavaScript de notre application.
<script src="//{{ Request::getHost() }}:6001/socket.io/socket.io.js"></script>
<script src="{{ asset('js/app.js') }}"></script>
Ensuite, on utilisera laravel-echo
afin de se connecter au channel précédemment créé.
import Echo from 'laravel-echo'
let e = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
})
e.channel('chan-demo')
.listen('PostCreatedEvent', function (e) {
console.log('PostCreatedEvent', e)
})
e
contiendra une représentation de notre évènement Laravel.
Pour plus de cas vous pouvez regarder la vidéo ou la documentation