Créer un chat vidéo de groupe avec Symfony, PHP, Twilio et React.js

October 12, 2020
Rédigé par
Oluyemi Olususi
Contributeur
Les opinions exprimées par les contributeurs de Twilio sont les leurs
Révisé par
Diane Phan
Twilion

Créer un chat vidéo de groupe avec Symfony, PHP, Twilio et React.js

Si les actualités et les statistiques actuelles sur le télétravail sont un indicateur de l'avenir, il est évident que le travail à domicile va progressivement devenir la nouvelle norme pour les employés du monde entier, y compris de nombreuses entreprises technologiques. Bien que la définition d'une communication efficace puisse varier d'une entreprise à une autre, l'une des façons les plus prometteuses d'améliorer la productivité et de maintenir le contact au sein de votre équipe consiste à utiliser la visioconférence ou le chat.

Ce tutoriel vous guidera sur la création d'une application de chat en visioconférence à l'aide de SymfonyReact.js et Twilio Programmable Video. L'application de chat vidéo permettra aux utilisateurs de se connecter et de participer à un salon de chat prédéfini.

Conditions préalables

Pour participer à ce tutoriel, vous aurez besoin des éléments suivants :

Création d'une nouvelle application Symfony

Considéré comme l'un des principaux frameworks PHP utilisés pour la création d'applications web et d'API RESTful, Symfony est construit avec une structure élégante et est assez robuste pour construire n'importe quel type d'application, quelle que soit sa taille.

Pour commencer à créer une nouvelle application Symfony, vous utiliserez Composer. Exécutez la commande suivante à partir du terminal :

$ composer create-project symfony/website-skeleton symfony-react-video-chat

Cela permettra de poser les bases d'une nouvelle application Symfony dans le dossier symfony-react-video-chat de votre dossier de développement. Sinon, vous pouvez également utiliser le programme d'installation de Symfony pour configurer votre projet en suivant les instructions suivantes.

Installez le SDK PHP Twilio pour le projet

Allez dans le dossier du projet et exécutez la commande suivante pour installer les autres dépendances requises :

$ cd symfony-react-video-chat
$ composer require twilio/sdk

Ici, nous avons installé :

  • twilio/sdk : un SDK PHP Twilio qui facilitera l'interaction entre l'API Twilio et notre application

Obtenez les informations d'identification et mettez à jour le fichier d'environnement

Comme nous l'avons mentionné, un compte Twilio est nécessaire pour ce tutoriel et vous devriez en avoir créé un à ce stade. Naviguez jusqu'à votre Console Twilio pour accéder à vos informations d'identification Twilio. Copiez le TWILIO_ACCOUNT_SID depuis votre tableau de bord et conservez-le en lieu sûr :

SID du compte

Rendez-vous maintenant sur la liste des clés API et consultez la page suivante :

Créer une nouvelle clé API

Donnez à votre clé API un nom convivial tel que « sample key » et cliquez sur le bouton Create API Key pour terminer le processus. Ceci générera un SID de clé API unique aléatoire et un secret de clé API pour vous.

Accédez au fichier .env de votre projet et incluez les valeurs des TWILIO_ACCOUNT_SID, API_KEY_SID et API_KEY_SECRET obtenues à partir de la Console Twilio. Le contenu du fichier .env devrait être le suivant :

TWILIO_ACCOUNT_SID=YOUR_ACCOUNT_SID
TWILIO_API_KEY_SID=YOUR_API_KEY
TWILIO_API_KEY_SECRET=YOUR_API_SECRET

Ces informations d'identification sont essentielles pour générer un token d'accès et des autorisations de salon pour un utilisateur. Un participant dans un salon de conversation qui sera généré dans la section suivante.

Générer les tokens d'accès

Dans une application vidéo programmable, le token d'accès contrôle l'identité et les autorisations de salon d'un participant à un chat via le SDK Twilio. Il contient généralement des informations sur les détails du SID et de la clé API de votre compte Twilio.

Vous allez ensuite créer un point de terminaison qui utilisera ces informations d'identification afin de générer un token d'accès pour les utilisateurs.

À l'image de ce qu'on peut obtenir dans d'autres applications web à structure MVC, les points de terminaison sont souvent mappés vers une action de contrôleur spécifique pour une gestion correcte des requêtes HTTP, de la logique métier, et pour renvoyer les réponses appropriées. À cette fin, nous utiliserons le MakerBundle qui est installé avec Symfony afin de générer un contrôleur et sa vue correspondante. Exécutez la commande suivante pour créer un nouveau contrôleur :

$ php bin/console make:controller TokenController

Deux nouveaux fichiers seront créés pour vous :

  • Un contrôleur situé dans src/Controller/TokenController.php
  • Une page d'affichage dans templates/token/index.html.twig

Ouvrez le contrôleur nouvellement créé et remplacez son contenu par ce qui suit :

 

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Twilio\Jwt\AccessToken;
use Twilio\Jwt\Grants\VideoGrant;

class TokenController extends AbstractController
{
    /**
     * @Route("/", name="token")
     */
    public function index()
    {
        return $this->render('token/index.html.twig', [
            'controller_name' => 'TokenController',
        ]);
    }


    /**
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     * @Route("access_token", name="access_token", methods={"POST"})
     */
    public function generate_token(Request $request)
    {
        $accountSid = getenv('TWILIO_ACCOUNT_SID');
        $apiKeySid = getenv('TWILIO_API_KEY_SID');
        $apiKeySecret = getenv('TWILIO_API_KEY_SECRET');
        $identity = uniqid();

        $roomName = json_decode($request->getContent());

        // Create an Access Token
        $token = new AccessToken(
            $accountSid,
            $apiKeySid,
            $apiKeySecret,
            3600,
            $identity
        );

        // Grant access to Video
        $grant = new VideoGrant();
        $grant->setRoom($roomName->roomName);
        $token->addGrant($grant);
        return $this->json(['token' => $token->toJWT()], 200);
    }
}

Ici, nous avons modifié le code par défaut généré par le MakerBundle en configurant la méthode index() de façon à obtenir le rendu du contenu de token/index.html.twig sur la route de la page d'accueil. Le chat vidéo sera visible sur cette page à la fin de ce tutoriel.

Une méthode nommée generate_token() est créée. Dans cette méthode, nous avons accédé aux variables d'environnement définies précédemment dans le fichier .env et les avons passées comme une partie des paramètres requis pour une nouvelle instance de la méthode AccessToken() à partir du SDK Twilio.

Le nom de salon préféré, qui sera affiché depuis le front-end, a été récupéré via la méthode HTTP Request et défini comme salon auquel le détenteur du token d'accès généré ne peut que se connecter.

Accédez au fichier templates/token/index.html.twig et remplacez le contenu par le HTML suivant :

{% extends 'base.html.twig' %}

{% block title %} Symfony React Video Chat !{% endblock %}

{% block body %}
    <div id="root"></div>
{% endblock %}

Il s'agit d'un fichier de modèle twig basique pour une application Symfony qui restera vide jusqu'à ce que le front-end React.js soit ajouté au <div> avec un ID de root.

Démarrer l'application

Démarrez l'application en exécutant la commande suivante sur le terminal :

$ symfony server:start

Saisissez localhost:8000 dans votre navigateur web préféré. Vous remarquerez une page vide. Laissez le serveur en cours d'exécution pour le moment. Nous y reviendrons plus tard.

Construire la logique front-end

Maintenant que la fonctionnalité back-end a été instaurée et est en cours d'exécution, configurez l'application React pour la connecter à l'API back-end créée, ce qui va nous donner une application de chat vidéo fonctionnelle. Ouvrez un autre terminal dans le répertoire racine (root) du projet et utilisez Composer pour installer Symfony Webpack Encore en exécutant la commande ci-dessous :

$ composer require symfony/webpack-encore-bundle

En plus de :

$ yarn install

Webpack Encore est une bibliothèque JavaScript qui utilise Webpack « sous le capot ». Elle est connue pour être compatible avec les fichiers CSS et JavaScript dans une application Symfony. La commande précédente créera un fichier webpack.config.js, un dossier assets, et ajoutera le dossier node_modules au fichier .gitignore.

Une fois l'installation terminée, utilisez Yarn pour installer React,Axios et le SDK JavaScript Twilio Programmable Video en exécutant les commandes suivantes :

$ yarn add react react-dom @babel/preset-react --dev
$ yarn add axios twilio-video --save
$ yarn install

Configurer Webpack Encore et activer React

Ici, nous allons activer React et configurer un point d'entrée dans le fichier webpack.config.js à la racine de notre projet, comme indiqué ici :

var Encore = require('@symfony/webpack-encore');

// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
    Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}

Encore
    // directory where compiled assets will be stored
    .setOutputPath('public/build/')
    // public path used by the web server to access the output path
    .setPublicPath('/build')
    // only needed for CDN's or sub-directory deploy
    //.setManifestKeyPrefix('build/')

    /*
     * ENTRY CONFIG
     *
     * Add 1 entry for each "page" of your app
     * (including one that's included on every page - e.g. "app")
     *
     * Each entry will result in one JavaScript file (e.g. app.js)
     * and one CSS file (e.g. app.css) if your JavaScript imports CSS.
     */
    .addEntry('app', './assets/app.js')

    // When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
    .splitEntryChunks()

    // will require an extra script tag for runtime.js
    // but, you probably want this, unless you're building a single-page app
    .enableSingleRuntimeChunk()

    /*
     * FEATURE CONFIG
     *
     * Enable & configure other features below. For a full
     * list of features, see:
     * https://symfony.com/doc/current/frontend.html#adding-more-features
     */
    .cleanupOutputBeforeBuild()
    .enableBuildNotifications()
    .enableSourceMaps(!Encore.isProduction())
    // enables hashed filenames (e.g. app.abc123.css)
    .enableVersioning(Encore.isProduction())

    // enables @babel/preset-env polyfills
    .configureBabelPresetEnv((config) => {
        config.useBuiltIns = 'usage';
        config.corejs = 3;
    })

    // enables Sass/SCSS support
    //.enableSassLoader()

    // uncomment if you use TypeScript
    //.enableTypeScriptLoader()

    // uncomment to get integrity="..." attributes on your script & link tags
    // requires WebpackEncoreBundle 1.4 or higher
    //.enableIntegrityHashes(Encore.isProduction())

    // uncomment if you're having problems with a jQuery plugin
    //.autoProvidejQuery()

    // uncomment if you use API Platform Admin (composer req api-admin)
    .enableReactPreset()
    //.addEntry('admin', './assets/js/admin.js')
;

module.exports = Encore.getWebpackConfig();

À partir du code ci-dessus, nous avons donné à Encore l'instruction de charger ./assets/js/app.js comme point d'entrée de l'application et de décommenter la méthode .enableReactPreset().

Créer un composant de Chat

Encore a déjà créé une structure existante sur laquelle nous allons nous appuyer. Créez un nouveau composant fichier nommé Chat.js dans le dossier assets/js et collez-y le code suivant :

import React, { useState } from "react";
import axios from "axios";
import Video from "twilio-video";

const Chat = () => {
    const [roomName, setRoomName] = useState('');
    const [hasJoinedRoom, setHasJoinedRoom] = useState(false);

    const joinChat = event => {
    event.preventDefault();
      if (roomName) {
            axios.post('/access_token', { roomName }, ).then((response) => {
                connectToRoom(response.data.token);
                setHasJoinedRoom(true);
                setRoomName('');

            }).catch((error) => {
                console.log(error);
            })
        } else {
            alert("You need to enter a room name")
        }
    };


    return(
        <div className="container">
            <div className={"col-md-12"}>
                <h1 className="text-title">Symfony React Video Chat</h1>
            </div>

            <div className="col-md-6">
                <div className={"mb-5 mt-5"}>
                    {!hasJoinedRoom && (
                        <form className="form-inline" onSubmit={joinChat}>
                            <input type="text" name={'roomName'} className={"form-control"} id="roomName"
                                   placeholder="Enter a room name" value={roomName} onChange={event => setRoomName(event.target.value)}/>

                                <button type="submit" className="btn btn-primary">Join Room</button>

                        </form>
                    )}

                </div>
                <div id="video-chat-window"></div>
            </div>
        </div>
    )
};

export default Chat;

Ce composant sera chargé de se connecter au point de terminaison d'API créé, de récupérer le token d'accès généré à partir de l'API et de produire le rendu de la fenêtre de chat. Pour réaliser ces étapes, nous avons créé un formulaire avec un champ de saisie afin que les utilisateurs puissent entrer leur nom préféré pour le salon de chat et le publier sur le point de terminaison de l'API une fois qu'ils cliqueront sur le bouton Join Room.

Une fois le formulaire soumis, la méthode joinChat() sera appelée et une requête POST HTTP sera envoyée au point de terminaison access_token. Une fois une réponse obtenue, le token récupéré sera utilisé pour se connecter à une session de chat vidéo en direct.

Pour rejoindre le chat vidéo, ajoutez la méthode suivante appelée connectToRoom() immédiatement après la fonction joinChat() :

...
const Chat = () => {
    ...

    const connectToRoom = (token) => {
        const { connect, createLocalVideoTrack } = Video;

        let connectOption = { name: roomName };

        connect( token, connectOption).then(room => {

            console.log(`Successfully joined a Room: ${room}`);

            const videoChatWindow = document.getElementById('video-chat-window');

            createLocalVideoTrack().then(track => {
                videoChatWindow.appendChild(track.attach());
            });

            room.on('participantConnected', participant => {
                console.log(`Participant "${participant.identity}" connected`);

                participant.tracks.forEach(publication => {
                    if (publication.isSubscribed) {
                        const track = publication.track;
                        videoChatWindow.appendChild(track.attach());
                    }
                });

                participant.on('trackSubscribed', track => {
                    videoChatWindow.appendChild(track.attach());
                });
            });
        }, error => {
            console.error(`Unable to connect to Room: ${error.message}`);
        });
    };

    ...
};

export default Chat;

Ici, nous avons passé le token généré obtenu depuis l'API back-end et l'avons utilisé pour établir une connexion au salon de chat. Nous avons également créé une piste vidéo locale et l'avons ajoutée à une fenêtre de chat où elle sera affichée.

Dès qu'un nouveau participant se connecte au salon de chat, la méthode room.on() affiche son nom dans la fenêtre de discussion.

Mettre à jour l'AppComponent

Ici, nous allons initialiser React et le lier à un élément HTML avec un ID de root. Ouvrez le fichier assets/app.js et remplacez son contenu par :

import React from 'react';
import ReactDOM from "react-dom";
import Chat from './js/Chat';
import './styles/app.css'


ReactDOM.render(<Chat/>, document.getElementById("root"));

Modifier le modèle de base

Grâce au Webpack Encore, le code React sera compilé en JavaScript. Pour inclure le script généré dans le projet, rendez-vous sur le modèle de base situé dans templates/base.html.twig et remplacez son contenu par ce qui suit :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>

    </head>
    <body>
        {% block body %}{% endblock %}


        {% block stylesheets %}
            {{  encore_entry_link_tags('app') }}
        {% endblock %}


        {% block javascripts %}

            {{ encore_entry_script_tags('app') }}
        {% endblock %}
    </body>
</html>

Inclure le CDN Bootstrap

Pour introduire certains styles par défaut pour ce projet, nous inclurons un fichier CDN Bootstrap. Bootstrap est un framework CSS qui crée des mises en page. Il offre beaucoup de classes d'aide qui peuvent être incluses dans le HTML des pages web. Pour inclure le CDN Bootstrap dans ce projet, ouvrez le fichier assets/styles/app.css et ajoutez le lien suivant :

@import url(https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css);

Tester l'application Symfony

Assurez-vous que l'application Symfony est toujours en cours d'exécution à partir d'un terminal distinct dans le répertoire de votre projet. Si elle n'est pas exécutée, utilisez la commande ci-dessous pour reprendre l'application Symfony :

$ php bin/console server:run

Dans une deuxième session de terminal, exécutez la commande suivante pour compiler l'application REACT et examinez les fichiers JavaScript afin d'identifier toute modification :

$ yarn encore dev --watch

Rendez-vous sur http://localhost:8000 pour afficher l'application. Ouvrez deux fenêtres différentes et rejoignez une salle :

Tester l&#x27;application

Conclusion

L'application de chat vidéo que nous avons construite ici pourrait être améliorée en étendant sa logique métier pour qu'elle accueille davantage de fonctionnalités, telles que le partage d'écran et l'affichage du nombre de participants dans un salon de chat. Consultez la documentation officielle Programmable Video de Twilio pour en savoir plus sur la construction d'expériences virtuelles avec la vidéo.

J'espère que cet article vous aura été utile. Le code source complet de ce projet est consultable ici sur GitHub. Bon code à vous !

Olususi Oluyemi est un passionné de technologie et de programmation, accro au développement web, qui adore découvrir de nouvelles technologies.