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 public
  • PrivateChannel 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