https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-turkey-timer-laravel-facebook-messenger-dr/Blog_Timer-Lavavel-FB_1200x600.png

Construire un minuteur pour la dinde avec Laravel, Facebook Messenger et Vonage

Publié le May 21, 2021

Temps de lecture : 7 minutes

Cette année, ma belle-mère m'a demandé de l'aider à préparer le repas de Noël pour la famille. J'ai vraiment hâte d'y être, mais avec un nouveau chiot à la maison et un jeune neveu, je risque de me laisser distraire et d'oublier de mettre les pommes de terre au four au bon moment !

Pour aider à cela, j'ai décidé d'écrire une petite application Laravel qui maintient une collection de recettes. Vous lui envoyez un message avec le nom d'une recette via WhatsApp, Facebook ou Viber. L'application récupère la liste des étapes nécessaires à chaque recette et vous envoie l'étape suivante lorsqu'il est temps de la réaliser. Vous pouvez vous détendre, sachant que tout ce qui se passe dans la cuisine est sous contrôle et qu'en cas d'intervention humaine, vous en serez averti !

Voici l'application en action :

Turkey Timer DemoTurkey Timer Demo

Dans cet article, je vais travailler avec Facebook, mais il est facile d'étendre le système à WhatsApp et Viber, car nous utiliserons le paquetage Vonage laravel-notification package.

Configuration du projet Laravel et Vonage

Il y a pas mal de configuration nécessaire pour ce projet, donc pour éviter de vous prendre jusqu'au Nouvel An pour lire ceci, j'ai sauté directement au code spécifique à Vonage dans ce post. Si cela vous intéresse, voici le processus que j'ai suivi pour mettre en place l'application (chaque élément renvoie à un commit qui contient une description plus longue du travail effectué) :

Il s'agit d'une application assez simple qui permet de gérer les utilisateurs et d'afficher une recette et ses horaires. Il s'agit d'une application autonome qui ne dépend pas de Vonage pour le moment. Cependant, nous voulons être en mesure de recevoir des messages sur notre page Facebook, donc je dois faire un peu plus de configuration. Pour que l'application fonctionne, je dois relier ma page Facebook à un Account Vonage, créer et configurer une application afin que Vonage sache où envoyer les demandes de webhook et exposer mon application à l'internet en utilisant ngrok pour que Vonage puisse l'atteindre.

Si vous souhaitez essayer de construire cela vous-même, rejoignez le Communauté Vonage Slack et nous pourrons travailler ensemble sur les étapes nécessaires.

Dans la suite de ce billet, nous allons ajouter la possibilité pour les utilisateurs de nous envoyer un message avec un nom de recette et de voir l'application répondre avec les actions qui doivent être effectuées au bon moment.

Traitement des messages entrants sur Facebook

Lorsque j'ai créé mon application Vonage, j'ai dû fournir deux URL ; une qui sera appelée lorsque je recevrai un message d'un utilisateur et une autre qui recevra les mises à jour de statut de Vonage. J'ai choisi /webhooks/inbound-message pour la réception des messages et /webhooks/message-status pour les mises à jour d'état. Comme Vonage enverra une requête depuis l'extérieur de l'application, j'ai dû désactiver la fonction CSRF dans app/Http/Middleware/VerifyCsrfToken.php:

protected $except = [
    '/webhooks/*'
];

Maintenant que Vonage peut accéder à mon webhook, il est temps de gérer les demandes entrantes. J'ai utilisé make:controller pour générer un nouveau WebhooksController et mis à jour routes/web.php pour faire pointer les URLs ci-dessus vers ce contrôleur :

Route::post('/webhooks/inbound-message', 'WebhooksController@inboundMessage')->name('webhooks.inbound');
Route::post('/webhooks/message-status', 'WebhooksController@messageStatus')->name('webhooks.status');

La dernière chose à faire est d'implémenter la fonction WebhooksController. Pour l'instant, j'enregistre la requête entrante afin de voir le format de la requête envoyée par Vonage :

namespace App\Http\Controllers;
use Illuminate\Http\Request;

class WebhooksController extends Controller
{
    public function inboundMessage(Request $request) {
        \Log::debug('Inbound Message', $request->all());
    }

    public function messageStatus(Request $request) {
        \Log::debug('Message Status', $request->all());
    }
}

Après avoir effectué ces modifications, j'ai envoyé un message depuis mon Account personnel vers ma page Facebook et l'entrée suivante est apparue dans le fichier journal de Laravel :

{
  "message_uuid": "f4fcc665-7b71-4291-a079-505154e28c36",
  "to": {
    "id": "987654210987654",
    "type": "messenger"
  },
  "from": {
    "id": "123456789012345",
    "type": "messenger"
  },
  "timestamp": "2018-12-12T11:36:44.663Z",
  "direction": "inbound",
  "message": {
    "content": {
      "type": "text",
      "text": "Christmas Dinner"
    }
  }
}

Excellent ! L'utilisateur m'a envoyé un message et mon application l'a reçu comme prévu. Maintenant que nous pouvons recevoir des messages, il est temps de commencer à renvoyer des réponses.

Les modifications apportées dans cette section sont indiquées dans ce commit

Créer une notification Laravel

Pour renvoyer les mises à jour à l'utilisateur au bon moment, nous allons utiliser le système de file d'attente de Laravel. delay du système de file d'attente de Laravel. Avant de pouvoir le faire, nous devons activer la fonctionnalité queue dans Laravel. Nous allons utiliser le pilote database car le débit ne sera pas particulièrement élevé et l'utilisation de la base de données élimine le besoin de dépendances supplémentaires telles que Redis. Nous pouvons configurer ce paramètre dans le fichier .env dans le fichier

QUEUE_CONNECTION=database

Une fois que c'est fait, j'ai créé la table pour stocker les travaux en exécutant php artisan queue:table && php artisan migrate.

Une fois l'administration terminée, il est temps de commencer à construire nos notifications. J'ai besoin d'envoyer une phrase simple chaque fois qu'une condition est déclenchée. J'aurais pu créer une notification par message, mais par souci de rapidité, j'ai créé une notification unique qui accepte une chaîne à l'adresse app/Notifications/FreeText.php avec le contenu suivant :

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;

class FreeText extends Notification implements ShouldQueue
{
    use Queueable, ShouldQueue;

    protected $text;
    protected $channel;

    public function __construct($text, $channel)
    {
        $this->text = $text;
        $this->channel = $channel;
    }

    public function via($notifiable)
    {
        return [];
    }
}

Ceci définit une notification, mais notre application ne sait pas encore comment l'envoyer. Nous devons remplir la méthode via et implémenter toutes les méthodes to* sur la notification. Pour envoyer ces notifications, nous allons utiliser la méthode nexmo/laravel-notification qui nous permet d'implémenter les méthodes suivantes sur notre notification :

  • toNexmoWhatsApp

  • toNexmoFacebook

  • toNexmoViberServiceMessage

  • toNexmoSms

Nous allons mettre en œuvre et toNexmoFacebook en ajoutant ce qui suit à la notification :

public function toNexmoFacebook($notifiable)
{
    return (new \Nexmo\Notifications\Message\Text)
        ->content($this->text);
}

En plus d'implémenter ces méthodes, nous devons indiquer à Laravel comment acheminer le message. Habituellement, vous utilisez l'entité $notifiable transmise à la méthode pour déterminer comment l'utilisateur souhaite être contacté. Dans ce cas, nous allons répondre sur le canal sur lequel nous avons reçu le message. Ce canal est passé au constructeur de la notification. Voici à quoi ressemble ma méthode via avec ces changements :

public function via($notifiable)
{
    return [$this->channel];
}

Il reste une dernière chose à faire avant que tout cela ne commence à fonctionner, et c'est de fournir des identifiants d'authentification Vonage et une configuration pour l'envoi via Messenger. Si vous voulez faire la même chose, créez une application sur le tableau de bord de Vonage et ajoutez ce qui suit à votre fichier .env fichier :

NEXMO_APPLICATION_ID="YOUR_APPLICATION_ID"
NEXMO_PRIVATE_KEY=./private.key
NEXMO_FROM_MESSENGER="FACEBOOK_PAGE_ID"

Les modifications apportées dans cette section sont indiquées dans ce commit

Envoi de mises à jour sur Facebook

Maintenant que nous avons fait tout le travail, la dernière chose à faire est d'envoyer les actions qui doivent être effectuées pour cuisiner la recette.

Lorsque nous recevons un message d'un utilisateur, nous devons extraire le canal sur lequel le message a été envoyé et l'identifiant de l'utilisateur qui nous a envoyé le message. Une fois que nous avons ces informations, nous pouvons créer une nouvelle notification à la demande en utilisant ces informations :

// The incoming message contains the platform + contact details that
// we need to reply with, so configure a notification route with those
// details
$from = $request->input('from');

// The Vonage Messages API returns messenger, but our channel names are all prefixed with nexmo-
$channel = 'nexmo-' . $from['type'];
$sender = Notification::route($channel, $from['id']);

À ce stade, nous pouvons envoyer le texte de notre choix à l'utilisateur. La première chose que nous devons vérifier est si le message qu'il nous a envoyé contient un nom de recette. Si ce n'est pas le cas, nous lui envoyons un message indiquant que nous n'avons pas pu trouver cette recette.

// Try and find the recipe name that was sent to us
$recipeName = $request->input('message.content.text');
$recipe = \App\Recipe::where('name', $recipeName)->first();
if (!$recipe) {
    $sender->notify(new FreeText(
        "I couldn't find that recipe",
        $channel
    ));
    return;
}

Si nous passons ce bloc de code, nous avons une recette valide et il est temps de programmer des notifications ! Chaque ensemble d'horaires d'une recette possède un élément action et un start_time en secondes, commençant à zéro. Heureusement, Numbers nous permet de retarder une notification d'un certain nombre de secondes à partir de maintenant, ce qui correspond parfaitement à notre cas d'utilisation.

La dernière partie de notre méthode inboundMessage doit itérer sur chaque timing et programmer une nouvelle notification :

foreach ($recipe->timings()->get() as $t) {
    $sender->notify((new FreeText(
        $t->action,
        $channel
    ))->delay($t->start_time));
}

Si l'on met tout cela bout à bout, notre méthode inboundMessage ressemble à ce qui suit :

public function inboundMessage(Request $request) {
    \Log::debug('Inbound Message', $request->all());

    $from = $request->input('from');

    // The Vonage API returns messenger, but our channel names are all prefixed with nexmo-
    $channel = 'nexmo-' . $from['type'];
    $sender = Notification::route($channel, $from['id']);

    // Try and find the recipe name that was sent to us
    $recipeName = $request->input('message.content.text');
    $recipe = \App\Recipe::where('name', $recipeName)->first();
    if (!$recipe) {
        $sender->notify(new FreeText(
            "I couldn't find that recipe",
            $channel
        ));
        return;
    }

    // If we get this far, we have a recipe! Time to schedule some notifications
    foreach ($recipe->timings()->get() as $t) {
        $sender->notify((new FreeText(
            $t->action,
            $channel
        ))->delay($t->start_time));
    }
}

Les modifications apportées dans cette section sont indiquées dans ce commit

Exécution de l'application

Maintenant que tout a été construit, il est temps de lancer l'application finale ! Voici une liste de contrôle rapide de tout ce que j'ai dû faire pour que tout fonctionne :

  1. Exécuter php artisan serve

  2. S'assurer que ngrok http 8000 s'exécute afin que Vonage puisse effectuer des appels vers mon application.

  3. Exécuter php artisan queue:work pour surveiller les travaux insérés dans la base de données

  4. Visitez ma page Facebook et envoyez-lui une recette (dans ce cas, Christmas Dinner!)

  5. S'asseoir et se détendre, en sachant que je recevrai un message lorsque j'aurai quelque chose à faire.

Si vous souhaitez voir le projet complet de ce billet, vous pouvez le trouver le trouver sur Github. Si vous voulez l'exécuter vous-même, vous aurez besoin de :

  1. Lier une page Facebook à Vonage

  2. Créez une nouvelle application Vonage et associez votre page à cette application.

  3. Configurez vos webhooks

  4. Cloner le repo

  5. Mise à jour .env avec vos identifiants Vonage

  6. Exécuter composer install

  7. Exécuter php artisan migrate && php artisan db:seed

  8. Exécuter php artisan serve et php artisan queue:work dans des bornes séparées

  9. Envoyez un message à votre page Facebook

Quelle est la prochaine étape ?

Eh bien, c'était amusant ! Non seulement j'ai pu essayer l Vonage Messages API mais j'ai aussi beaucoup appris sur les notifications Laravel (y compris sur la façon de créer de nouveaux canaux). En prime, j'aurai même un petit assistant qui me rappellera quand il faut faire quelque chose le jour de Noël !

Partager:

https://a.storyblok.com/f/270183/384x384/1c8825919c/mheap.png
Michael HeapAnciens de Vonage

Michael est un ingénieur logiciel polyglotte qui s'attache à réduire la complexité des systèmes et à les rendre plus prévisibles. Travaillant avec une variété de langages et d'outils, il partage son expertise technique avec des publics du monde entier lors de groupes d'utilisateurs et de conférences. Au quotidien, Michael est un ancien défenseur des développeurs chez Vonage, où il a passé son temps à apprendre, enseigner et écrire sur toutes sortes de technologies.