A travers ce tutoriel, nous allons découvrir comment envoyer une notification sur Discord lorsqu’un événement ce produit.
Cela pourrait être dans le cas de l’inscription d’un utilisateur, lors d’un paiement ou quoi que ce soit d’autres.
Dans notre exemple, nous allons notifier Discord, via leur système de webhook, lorsqu’un article est créé.
Mise en situation
Pour les besoins de notre tutoriel, nous allons créer un modèle Post
qui dispose des champs created_at
et updated_at
de base ainsi que les champs title
et content
:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Factories\HasFactory; 6use Illuminate\Database\Eloquent\Model; 7 8class Post extends Model 9{10 use HasFactory;11 12 protected $fillable = ['title', 'content'];13}
Voici la migration qui va nous permettre de créer la table posts
:
1Schema::create('posts', function (Blueprint $table) {2 $table->id();3 $table->timestamps();4 $table->string('title');5 $table->text('content');6});
Continuons, en implémentant dans un PostController
une méthode qui va enregistrer un article en base de donnée lors de la soumission d’un formulaire et une autre qui se chargera d’afficher le contenu d’un artile :
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Models\Post; 6use App\Notifications\PostCreated; 7use Illuminate\Contracts\View\View; 8use Illuminate\Http\RedirectResponse; 9use Illuminate\Http\Request;10use Illuminate\Support\Facades\Notification;11 12class PostController extends Controller13{14 public function store(Request $request): RedirectResponse15 {16 $post = Post::create($request->all());17 18 return redirect()->back();19 }20 21 public function show(Post $post): View22 {23 return view('posts.show', ['post' => $post]);24 }25}
Attention, afin de simplifier la compréhension du tutoriel, toute validation et tout contrôle d’accès a été supprimé, nous vous invitons à parcourir la suite de tutoriel sur les bases de Laravel si ces points vous intéressent !
Enfin, il nous reste plus qu’à déclarer nos routes qui pointent sur notre contrôleur :
1Route::post('/posts', [\App\Http\Controllers\PostController::class, 'store'])2 ->name('posts.store');3Route::get('/posts/{post}', [\App\Http\Controllers\PostController::class, 'show'])4 ->name('posts.show');
Nous voilà avec tout le contexte nécessaire pour pouvoir maintenant jouer avec Discord !
Création du channel Discord
Afin de pouvoir notifier Discord, nous allons utiliser le système de notifications Laravel qui effectuera un post sur un webhook Discord.
Avant cela, petit aparté sur le contenu attendu par Discord lors de l'exécution d’un webhook.
Il faut savoir que le contenu d’un message peut-être très varié, ce qui se traduit par une souplesse accrue de leur webhook. Pour ce qui nous concerne, on va considérer que le message est un unique embed
de type article
qui possède :
- un titre
- une description
- un lien
- un auteur (nom + avatar)
En partant des pré-requis susmentionnés, nous pouvons établir les classes que nous allons implémenter :
-
DiscordMessage
qui transporte les propriétés du message -
DiscordWebhookChannel
qui envoie le message
Commençons par le DiscordMessage
qui est ni plus ni moins qu’un DTO :
1<?php 2 3namespace App\Services\Discord; 4 5class DiscordMessage 6{ 7 public function __construct( 8 public string $authorName, 9 public string $authorAvatar,10 public string $title,11 public string $description,12 public string $url,13 ) {14 }15}
Si vous souhaitez en savoir plus sur les DTOs, vous pouvez consultez nos articles ici, là ou bien le dernier en date, celui-ci.
Maintenant que nous avons de quoi créer notre message, il nous faut de quoi l’envoyer, voilà donc notre classe DiscordWebhookChannel
qui reprend la logique d’implémentation des autres canaux nécessaires au système de Notification de Laravel :
1<?php 2 3namespace App\Services\Discord; 4 5use Illuminate\Http\Client\Factory as Http; 6use Illuminate\Notifications\Notification; 7 8class DiscordWebhookChannel 9{10 public function __construct(public Http $http)11 {12 }13 14 public function send(object $notifiable, Notification $notification): void15 {16 if (! $url = $notifiable->routeNotificationFor('discord')) {17 return;18 }19 20 $payload = $this->buildPayload(21 $notification->toDiscord($notifiable)22 );23 24 $this->http->post($url, $payload);25 }26 27 protected function buildPayload(DiscordMessage $message): array28 {29 return [30 'embeds' => [31 [32 'author' => [33 'name' => $message->authorName,34 'icon_url' => $message->authorAvatar,35 ],36 'title' => $message->title,37 'description' => $message->description,38 'url' => $message->url,39 ]40 ],41 ];42 }43}
Ici, la particularité réside dans la récupération de l’url du webhook, elle se fait via le $notifiable
sauf que ce dernier n’est pas un utilisateur ou quoique ce soit de notifiable comme l’entend Laravel et nous sommes contraints d’avoir au moins un élément à notifier sinon rien ne se produit. Nous allons voir comment ruser lors de l’utilisation de notre notification peu après.
Création de la notification
Voilà arriver le moment où nous allons implémenter notre notification qui embarquera l’article fraîchement créé en passant par la commande dédiée suivante :
1php artisan make:notification PostCreated
Pour rappel, les canaux à utiliser sont à indiquer en retour de la méthode via()
, on y ajoute donc notre DiscordWebhookChannel
puis nous créons la méthode toDiscord()
qui retournera un DiscordMessage
basé sur le contenu de notre article :
1<?php 2 3namespace App\Notifications; 4 5use App\Models\Post; 6use App\Services\Discord\DiscordMessage; 7use App\Services\Discord\DiscordWebhookChannel; 8use Illuminate\Bus\Queueable; 9use Illuminate\Notifications\Notification;10use Illuminate\Support\Str;11 12class PostCreated extends Notification13{14 use Queueable;15 16 public function __construct(public Post $post)17 {18 }19 20 public function via(object $notifiable): array21 {22 return [DiscordWebhookChannel::class];23 }24 25 public function toDiscord(object $notifiable): DiscordMessage26 {27 return new DiscordMessage(28 authorName: 'John',29 authorAvatar: 'https://i.pravatar.cc/300',30 title: $this->post->title,31 description: Str::limit($this->post->content, 200),32 url: route('posts.show', $this->post),33 );34 }35}
Toujours dans le but de simplifier le tutoriel, nous avons simplifier la notion d’auteur. Libre à vous d’implémenter, par exemple, une relation
Post
→User
pour rendre votre fonctionnalité complète.
Déclenchement de la notification
Nous avons dorénavant tout les éléments en notre possession pour envoyer notre notification.
Pour déclencher l’envoi, nous retournons au sein de la méthode PostController::store()
pour y ajouter le code suivant :
1public function store(Request $request): RedirectResponse2{3 $post = Post::create($request->all());4 5 Notification::route('discord', 'https://discord.com/api/webhooks/****/****')6 ->notify(new PostCreated($post));7 8 return redirect()->back();9}
Comme annoncé précédemment, nous avons besoin d’au moins un notifiable
et c’est ce qu’on produit lorsque la méthode Notification::route()
est appelée, un AnonymousNotifiable
est instancié ayant pour information une route, le webhook, pour notre canal Discord. D’où l’appel à $notifiable->routeNotificationFor('discord')
dans le DiscordWebhookChannel
, Eurêka !
Conclusion
La question qu’on se pose c’est pourquoi s’embêter à passer par le système de notification de Laravel ? Eh bien, une raison viable selon moi est que si demain vous souhaitez provoquer l’envoi de cette même notification sur d’autre channel (slack, email, websocket, l’api d’un réseau social, etc), vous n’avez qu’à implémenter les méthodes toSlack
ou toTwitter
, par exemple, pour que ce soit fonctionnel ! Le reste du code ne changeant pas.
A lire
Autres articles de la même catégorie
Maîtrisez les relations belongs-to-many avec la méthode attach
Attardons nous sur les subtilités de la méthode attach
Mathieu De Gracia
Comment développer un paquet en local ?
Vous souhaitez ajouter une fonctionnalité à votre application via un paquet ? Voici un tour d’horizon de la phase de développement.
William Suppo
Installer une beta de PHP en CLI
Que ce soit pour tester une nouvelle alpha ou s’amuser sur une vieille version, voyons comment installer en quelques minutes une version spécifique de php en CLI.
Mathieu De Gracia