Notifications personnalisées (mail, SMS, base de données) avec Laravel
Introduction
Dans le vaste écosystème du développement backend, la communication avec les utilisateurs est une pierre angulaire. Qu'il s'agisse de confirmer une commande, de signaler une activité importante ou de rappeler un événement, les notifications sont omniprésentes. Laravel, le framework PHP le plus populaire, offre un système de notification puissant et flexible, permettant de délivrer des messages via divers canaux tels que l'e-mail, les SMS, les notifications en base de données, et même des canaux personnalisés.
Cette leçon, destinée aux développeurs ayant une maîtrise avancée de Laravel, explorera en profondeur le système de notifications. Nous dépasserons les bases pour comprendre comment personnaliser chaque canal, intégrer des services tiers, et même créer nos propres mécanismes de diffusion. L'objectif est de vous fournir les outils nécessaires pour implémenter une stratégie de notification robuste et adaptée à vos besoins spécifiques.
Nous aborderons les points suivants :
- Les fondements du système de notification de Laravel.
- L'envoi de notifications par e-mail avec des modèles Markdown.
- Le stockage et la gestion des notifications en base de données.
- L'intégration de services SMS via des packages tiers.
- La création de canaux de notification personnalisés pour une flexibilité maximale.
- La gestion de l'envoi asynchrone des notifications via les files d'attente.
Préparez-vous à enrichir votre boîte à outils Laravel pour des communications utilisateur intelligentes et efficaces.
Les Bases des Notifications Laravel
Le système de notification de Laravel repose sur quelques concepts clés : les Notifiable, les Notification et les Channels (canaux).
Le Modèle Notifiable
Pour qu'un modèle puisse recevoir des notifications, il doit implémenter le trait Illuminate\Notifications\Notifiable. Par défaut, le modèle App\Models\User inclut déjà ce trait.
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; // <-- C'est ici !
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable; // <-- Et là !
// ...
}
Ce trait fournit la méthode notify() qui est le point d'entrée pour l'envoi d'une notification à une instance du modèle.
La Classe Notification
Chaque type de notification que vous souhaitez envoyer est représenté par une classe distincte. Vous pouvez générer une nouvelle classe de notification à l'aide de la commande Artisan :
php artisan make:notification OrderShipped
Cela créera un fichier app/Notifications/OrderShipped.php.
Voici la structure de base d'une classe de notification :
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue; // Pour les notifications asynchrones
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\DatabaseMessage; // Pour les notifications de BDD
class OrderShipped extends Notification implements ShouldQueue // Implémente ShouldQueue pour la mise en file d'attente
{
use Queueable;
protected $order;
/**
* Crée une nouvelle instance de notification.
*
* @return void
*/
public function __construct($order)
{
$this->order = $order;
}
/**
* Définit les canaux via lesquels la notification doit être envoyée.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
// Retourne un tableau de canaux, ex: ['mail', 'database', 'nexmo']
return ['mail', 'database'];
}
/**
* Récupère la représentation "mail" de la notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
// Logique spécifique à l'e-mail
}
/**
* Récupère la représentation "database" de la notification.
*
* @param mixed $notifiable
* @return array
*/
public function toDatabase($notifiable)
{
// Logique spécifique à la base de données
}
// ... d'autres méthodes toChannel() pour d'autres canaux
}
__construct(): Ce constructeur est l'endroit où vous injectez les données nécessaires à votre notification (par exemple, un objetOrder).via($notifiable): Cette méthode est essentielle. Elle détermine quels canaux seront utilisés pour envoyer la notification. Elle doit retourner un tableau de chaînes de caractères correspondant aux noms des canaux ('mail','database','nexmo','slack', ou le nom de vos canaux personnalisés).- Méthodes
toChannel($notifiable): Pour chaque canal défini dansvia(), vous devez implémenter une méthodeto[ChannelName](). Par exemple, sivia()retourne'mail', vous devez implémentertoMail(). Cette méthode est responsable de la construction du message spécifique à ce canal.
Canal 1 : Les Notifications par E-mail
L'envoi d'e-mails est l'un des usages les plus courants du système de notification de Laravel. Le système de notifications simplifie considérablement l'envoi d'e-mails transactionnels.
toMail() et MailMessage
La méthode toMail() doit retourner une instance de Illuminate\Notifications\Messages\MailMessage. Cette classe fournit une interface fluide pour construire des e-mails simples et propres.
// Dans app/Notifications/OrderShipped.php
use Illuminate\Notifications\Messages\MailMessage;
public function toMail($notifiable)
{
$url = url('/orders/'.$this->order->id);
return (new MailMessage)
->greeting('Bonjour ' . $notifiable->name . '!')
->subject('Votre commande a été expédiée !')
->line('La commande #' . $this->order->id . ' a bien été expédiée. Vous devriez la recevoir sous peu.')
->action('Voir ma commande', $url)
->line('Merci d\'utiliser notre application !');
}
greeting(): Un titre d'accroche pour l'e-mail.subject(): Le sujet de l'e-mail.line(): Ajoute une ligne de texte dans le corps de l'e-mail. Vous pouvez appeler cette méthode plusieurs fois.action(): Ajoute un bouton d'appel à l'action. Le premier argument est le texte du bouton, le second est l'URL.error(): Similaire àline(), mais colore la ligne en rouge pour indiquer une erreur.salutation(): Texte de clôture, par défaut "Cordialement, [Nom de l'application]".
Utilisation de Modèles Markdown pour les E-mails
Pour des e-mails plus sophistiqués avec une mise en page personnalisée, Laravel permet d'utiliser des Markdown Mailables. Ces templates Blade sont compilés en HTML et Markdown pour une compatibilité maximale.
-
Créez un template Markdown :
public function toMail($notifiable) { return (new MailMessage) ->subject('Votre commande a été expédiée !') ->markdown('mail.orders.shipped', ['order' => $this->order, 'user' => $notifiable]); }Le chemin
mail.orders.shippedfait référence àresources/views/mail/orders/shipped.blade.php. -
Exemple de
resources/views/mail/orders/shipped.blade.php:@component('mail::message') # Commande Expédiée Bonjour {{ $user->name }}, Nous avons le plaisir de vous informer que votre commande numéro **{{ $order->id }}** a été expédiée avec succès ! --- **Détails de la commande :** @foreach ($order->items as $item) - {{ $item->quantity }} x {{ $item->product->name }} @endforeach --- Vous pouvez suivre votre commande ou voir les détails en cliquant sur le bouton ci-dessous : @component('mail::button', ['url' => url('/orders/' . $order->id)]) Voir ma commande @endcomponent Si vous avez des questions, n'hésitez pas à nous contacter. Merci d'avoir fait vos achats chez nous ! Cordialement,<br> {{ config('app.name') }} @endcomponentLaravel fournit des composants Markdown (comme
mail::messageetmail::button) pour structurer facilement vos e-mails.
Astuce : Vous pouvez prévisualiser vos Mailables/Notifications dans le navigateur en créant une route qui retourne l'instance de votre notification :
// routes/web.php
use App\Models\User;
use App\Models\Order; // Supposons que vous avez un modèle Order
use App\Notifications\OrderShipped;
Route::get('/mailable/order-shipped', function () {
$user = User::factory()->create(['name' => 'John Doe']);
$order = Order::factory()->create(); // Crée une fausse commande
return new OrderShipped($order);
});
Visitez /mailable/order-shipped dans votre navigateur pour voir le rendu HTML de l'e-mail.
Canal 2 : Les Notifications en Base de Données
Les notifications en base de données sont parfaites pour créer des "flux d'activité" ou des "centres de notifications" au sein de votre application, permettant aux utilisateurs de voir les événements passés directement dans leur tableau de bord.
Préparation de la Base de Données
Laravel fournit une commande Artisan pour générer la migration nécessaire :
php artisan notifications:table
php artisan migrate
Cela créera une table notifications avec les colonnes id, type, notifiable_type, notifiable_id, data, read_at, created_at, updated_at.
toDatabase() et DatabaseMessage
La méthode toDatabase() doit retourner un tableau (ou une instance de Illuminate\Notifications\Messages\DatabaseMessage) contenant les données que vous souhaitez stocker pour la notification. Ces données seront sérialisées en JSON dans la colonne data de la table notifications.
// Dans app/Notifications/OrderShipped.php
use Illuminate\Notifications\Messages\DatabaseMessage;
public function toDatabase($notifiable)
{
return [
'order_id' => $this->order->id,
'order_total' => $this->order->total_amount,
'message' => 'Votre commande #' . $this->order->id . ' a été expédiée !',
'url' => url('/orders/'.$this->order->id),
];
}
// Alternativement, en utilisant DatabaseMessage (moins courant pour des données simples) :
// public function toDatabase($notifiable)
// {
// return (new DatabaseMessage)->data([
// 'order_id' => $this->order->id,
// 'order_total' => $this->order->total_amount,
// 'message' => 'Votre commande #' . $this->order->id . ' a été expédiée !',
// 'url' => url('/orders/'.$this->order->id),
// ]);
// }
Accéder et Gérer les Notifications de Base de Données
Le trait Notifiable ajoute des méthodes pratiques pour interagir avec les notifications stockées :
// Récupérer toutes les notifications pour un utilisateur
$user = User::find(1);
foreach ($user->notifications as $notification) {
echo $notification->type; // App\Notifications\OrderShipped
echo $notification->data['message']; // Votre commande #123 a été expédiée !
echo $notification->created_at->diffForHumans();
}
// Récupérer les notifications non lues
foreach ($user->unreadNotifications as $notification) {
// ...
}
// Marquer une notification comme lue
$notification->markAsRead();
// Marquer toutes les notifications non lues pour un utilisateur comme lues
$user->unreadNotifications->markAsRead();
// Supprimer les notifications
$notification->delete();
Canal 3 : Les Notifications par SMS
Pour envoyer des SMS, Laravel ne fournit pas de client SMS intégré, car cela dépend de services tiers. Cependant, le système de notification est conçu pour s'intégrer facilement avec ces services via des packages de la communauté ou des adaptateurs officiels. Les plus courants sont Twilio et Vonage (anciennement Nexmo).
Pour cet exemple, nous utiliserons Vonage (Nexmo), qui dispose d'un package de notification officiel.
-
Installation du package Vonage/Nexmo :
composer require laravel/nexmo-notification-channel guzzlehttp/guzzle -
Configuration des identifiants Vonage : Ajoutez vos clés API Vonage dans votre fichier
.env:VONAGE_KEY=YOUR_VONAGE_API_KEY VONAGE_SECRET=YOUR_VONAGE_API_SECRET VONAGE_SMS_FROM=YOUR_VONAGE_PHONE_NUMBERAssurez-vous que
VONAGE_SMS_FROMest un numéro de téléphone Vonage valide que vous avez configuré. -
Définition du numéro de téléphone du destinataire : Votre modèle
Notifiable(par exemple,User) doit avoir une méthoderouteNotificationForVonage()qui retourne le numéro de téléphone du destinataire.// Dans app/Models/User.php (ou tout autre modèle Notifiable) public function routeNotificationForVonage($notification) { return $this->phone_number; // Assurez-vous que votre modèle User a une colonne phone_number } -
Implémentation de
toVonage()dans la Notification : La méthodetoVonage()doit retourner une instance deIlluminate\Notifications\Messages\VonageMessage(ouNexmoMessagesi vous utilisez l'ancien nom de package).
// Dans app/Notifications/OrderShipped.php
use Illuminate\Notifications\Messages\VonageMessage; // ou NexmoMessage;
public function via($notifiable)
{
return ['mail', 'database', 'vonage']; // Ajout du canal 'vonage'
}
public function toVonage($notifiable)
{
return (new VonageMessage)
->content('Votre commande #' . $this->order->id . ' a été expédiée ! Suivi: votre_lien_de_suivi');
}
content(): Le corps du message SMS. Les SMS ont des limitations de caractères, alors soyez concis.- D'autres options sont disponibles pour les messages binaires, la conciliation, etc. Consultez la documentation du package.
Pour un canal SMS comme Twilio, le processus serait similaire, mais vous installeriez laravel/twilio-notification-channel et implémenteriez une méthode toTwilio() et routeNotificationForTwilio().
Créer un Canal de Notification Personnalisé
La force de Laravel réside dans sa capacité d'extension. Si les canaux intégrés ou les packages tiers ne répondent pas à vos besoins (par exemple, envoyer une notification à un service de messagerie interne, à une API spécifique, ou via un webhook personnalisé), vous pouvez créer votre propre canal de notification.
Un canal personnalisé est simplement une classe PHP qui gère la logique d'envoi pour un type de message donné.
-
Créer la Classe de Canal : Un canal doit avoir une méthode
send(). Cette méthode recevra le modèle$notifiableet l'instance de$notification.php artisan make:notification-channel CustomWebhookChannelCela va générer
app/Notifications/Channels/CustomWebhookChannel.php.<?php namespace App\Notifications\Channels; use Illuminate\Notifications\Notification; use Illuminate\Support\Facades\Http; // Pour faire des requêtes HTTP class CustomWebhookChannel { /** * Envoyer la notification donnée. * * @param mixed $notifiable * @param \Illuminate\Notifications\Notification $notification * @return void */ public function send($notifiable, Notification $notification) { // Vérifie si la notification a une méthode toCustomWebhook() if (! method_exists($notification, 'toCustomWebhook')) { throw new \Exception('Notification missing toCustomWebhook method.'); } // Récupère les données spécifiques au webhook depuis la notification $data = $notification->toCustomWebhook($notifiable); // Détermine l'URL du webhook. Peut être statique, ou venir du $notifiable, ou de la config. // Pour cet exemple, nous allons le tirer d'une méthode sur le notifiable. $webhookUrl = $notifiable->routeNotificationForCustomWebhook($notification); if (!$webhookUrl) { return; // Ne rien faire si pas d'URL } // Envoi des données au webhook try { Http::post($webhookUrl, $data); // Optionnel: Log successful delivery } catch (\Exception $e) { // Optionnel: Gérer les erreurs (log, retenter, etc.) \Log::error("Failed to send custom webhook notification: " . $e->getMessage()); } } } -
Définir la Méthode
toCustomWebhook()dans votre Notification : Votre classeNotification(ex:OrderShipped) devra maintenant inclure une méthode qui renvoie les données spécifiques à envoyer via ce canal personnalisé.// Dans app/Notifications/OrderShipped.php // ... autres use statements use App\Notifications\Channels\CustomWebhookChannel; // N'oubliez pas d'importer public function via($notifiable) { return ['mail', 'database', CustomWebhookChannel::class]; // Utilisez la classe du canal personnalisé } /** * Récupère la représentation "custom webhook" de la notification. * * @param mixed $notifiable * @return array */ public function toCustomWebhook($notifiable) { return [ 'event' => 'order_shipped', 'order_id' => $this->order->id, 'user_id' => $notifiable->id, 'timestamp' => now()->toDateTimeString(), 'payload' => [ 'message' => 'Votre commande ' . $this->order->id . ' a été expédiée.', 'link' => url('/orders/'.$this->order->id), ], ]; } -
Définir la Méthode
routeNotificationForCustomWebhook()sur leNotifiable: Semblable aux SMS, si l'URL du webhook est dynamique et dépend de l'utilisateur, vous pouvez la définir sur le modèleNotifiable.// Dans app/Models/User.php (ou tout autre modèle Notifiable) public function routeNotificationForCustomWebhook($notification) { // Retourne l'URL du webhook pour cet utilisateur // Cela pourrait venir d'une colonne en base de données, d'une configuration par utilisateur, etc. return $this->custom_webhook_url; // Supposons que vous ayez cette colonne }
Maintenant, lorsque vous enverrez new OrderShipped($order) à un utilisateur, si CustomWebhookChannel::class est dans le tableau via(), Laravel appellera votre méthode send() dans CustomWebhookChannel en lui passant l'utilisateur et la notification.
Envoi des Notifications
L'envoi des notifications est simple et peut se faire de deux manières principales.
Envoi via le Modèle Notifiable
C'est la méthode la plus courante. Vous appelez la méthode notify() sur l'instance du modèle qui doit recevoir la notification :
use App\Models\User;
use App\Models\Order;
use App\Notifications\OrderShipped;
$user = User::find(1);
$order = Order::find(123);
$user->notify(new OrderShipped($order));
Envoi via la Facade Notification
Utile si vous souhaitez envoyer une notification à plusieurs destinataires qui ne sont pas nécessairement des modèles Eloquent, ou si vous préférez une approche plus "façade" :
use Illuminate\Support\Facades\Notification;
use App\Models\User;
use App\Models\Order;
use App\Notifications\OrderShipped;
$users = User::whereIn('id', [1, 2, 3])->get();
$order = Order::find(123);
Notification::send($users, new OrderShipped($order));
// Ou à une collection arbitraire d'objets implémentant Notifiable
// $adminEmail = 'admin@example.com';
// Notification::route('mail', $adminEmail)->notify(new OrderShipped($order));
// Note: route() est utile pour des destinataires qui ne sont pas des modèles Notifiable.
Mise en File d'Attente des Notifications (ShouldQueue)
Pour améliorer les performances de votre application, il est fortement recommandé de mettre en file d'attente l'envoi des notifications, surtout pour les canaux externes comme l'e-mail ou les SMS. Cela décharge le traitement des notifications vers un processus worker en arrière-plan, libérant ainsi le cycle de requête de l'utilisateur.
Pour ce faire, votre classe de notification doit simplement implémenter l'interface Illuminate\Contracts\Queue\ShouldQueue :
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue; // <--- C'est ici !
class OrderShipped extends Notification implements ShouldQueue // <--- Et ici !
{
use Queueable;
// ... reste de votre classe
}
Assurez-vous que votre configuration de file d'attente est prête (.env : QUEUE_CONNECTION=database ou redis ou sqs, etc.) et que vous exécutez un queue listener :
php artisan queue:work
Conclusion
Le système de notification de Laravel est une abstraction remarquablement bien conçue, offrant une flexibilité et une puissance considérables pour gérer les communications au sein de vos applications. Nous avons parcouru les concepts fondamentaux, exploré l'envoi par e-mail avec des modèles Markdown, la persistance en base de données, l'intégration de services SMS tiers, et la création de canaux personnalisés.
En maîtrisant ces outils, vous êtes désormais en mesure de :
- Envoyer des e-mails clairs et personnalisés à vos utilisateurs.
- Implémenter des centres de notifications internes grâce aux notifications en base de données.
- Envoyer des SMS pour des alertes urgentes ou des confirmations.
- Étendre le système pour intégrer n'importe quel service externe via des canaux personnalisés.
- Garantir la performance de votre application en mettant les notifications en file d'attente.
La capacité de Laravel à uniformiser l'interface pour divers types de communication vous permet de vous concentrer sur la logique métier de vos notifications plutôt que sur les détails d'implémentation de chaque canal. N'hésitez pas à expérimenter et à adapter ces techniques à vos cas d'usage spécifiques. Le monde des notifications Laravel est vaste et riche en possibilités !