Classiquement une notification est un message court pour informer un utilisateur qu'il s'est passé quelque chose qui le concerne dans l'application.
Par exemple une donnée sensible a été mise à jour, on envoie un SMS par sécurité en informant l'utilisateur de ce changement et, si ce n'est pas lui qui l'a effectué, il peut alors intervenir. Evidemment pour tout ce qui n'est pas email ou base de données il faut utiliser un service externe. Il y a un site dédié pour tous les drivers existants et la liste est déjà longue ! L'application d'exemple utilise les notifications pour l'envoi d'email pour :- la confirmation de l'adresse email lors de l'enregistrement,
- le renouvellement du mot de passe.
Organisation du code
Les notifications se trouvent dans le dossier app/Notifications :Ce dossier n'existe pas dans l'installation de base de Laravel, il est ajouté lorsqu'on crée la première notification avec Artisan qui dispose à cet effet d'une commande :
La confirmation de l'adresse email
Pour voir comment fonctionnent les notifications on va voir en détail la confirmation de l'adresse email de l'application d'exemple.Par défaut cette confirmation n'est pas prévue dans Laravel. Du coup lorsque quelqu'un s'enregistre en indiquant une adresse email on n'est pas sûr qu'elle soit valide.
Le contrôleur RegisterController
Par défaut le contrôleur App\Http\Controllers\Auth\RegisterController contient ce code :<?php namespace App\Http\Controllers\Auth; use App\User; use Validator; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\RegistersUsers; class RegisterController extends Controller { /* |-------------------------------------------------------------------------- | Register Controller |-------------------------------------------------------------------------- | | This controller handles the registration of new users as well as their | validation and creation. By default this controller uses a trait to | provide this functionality without requiring any additional code. | */ use RegistersUsers; /** * Where to redirect users after login / registration. * * @var string */ protected $redirectTo = '/home'; /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('guest'); } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => 'required|max:255', 'email' => 'required|email|max:255|unique:users', 'password' => 'required|min:6|confirmed', ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return User */ protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), ]); } }Autrement dit toute la logique pour l'enregistrement se fait dans le framework, dans le trait lluminate\Foundation\Auth\RegistersUsers. Pour modifier cette logique on doit surcharger la méthode correspondante :
public function register(Request $request) { $this->validator($request->all())->validate(); $this->guard()->login($this->create($request->all())); return redirect($this->redirectPath()); }Ici on trouve :
- la validation,
- la création de l'utilisateur et sa connexion,
- une redirection.
public function register(RegisterRequest $request, UserRepository $userRepository) { $user = $userRepository->store( $request->all(), str_random(30) ); $user->notify(new ConfirmEmail()); return redirect('/')->with('ok', trans('front/verify.message')); }On voit que :
- la validation se fait maintenant avec une requête de formulaire (ce n'était pas indispensable mais homogène par rapport à toutes les validations de l'application),
- on envoie une notification (notify) créée par la classe ConfirmEmail,
- on redirige sur la page d'accueil du site avec un message localisé.
Remarquez qu'on ajoute aux données du formulaire d'enregistrement un code de confirmation (une chaîne aléatoire de 30 caractères).
La partie qui nous intéresse est celle de la notification. Pour que ça fonctionne le modèle doit utiliser le trait Notifiable, ce qui est par défaut le cas du modèle User :class User extends Authenticatable { use Notifiable;
La notification
Voici la classe App\Notifications\ConfirmEmail :<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; class ConfirmEmail extends Notification implements ShouldQueue { use Queueable; /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return ['mail']; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->subject(trans('front/verify.email-title')) ->line(trans('front/verify.email-title')) ->line(trans('front/verify.email-intro')) ->action(trans('front/verify.email-button'), url('confirm/' . $notifiable->confirmation_code)); } }On définit le canal de notification (via), ici mail (ça pourrait être database, broadcast, nexmo ou slack). La méthode toMail définit le contenu de l'email. Il existe un lot de méthodes pratiques :
- subject : pour le sujet de l'email,
- line : pour ajouter une ligne de texte,
- action : pour ajouter un bouton de lien,
- ...
L'email
Voici l'email résultant en français :Vous avez une mise en forme automatique !
Par défaut le template est dans le framework. Mais si on doit le modifier, comme c'est le cas pour l'application d'exemple pour la localisation, il existe une commande d'Artisan pour le publier :php artisan vendor:publish --tag=laravel-notificationsOn trouve le template ici :
Il devient ainsi accessible et modifiable.
La notification des rédacteurs pour les nouveaux commentaires
On peut utiliser les notifications en base de données. Elles sont ainsi stockées en attendant d'être lues.La table des notifications
Pour que ça fonctionne il faut ajouter une table avec cette commande d'Artisan :php artisan notifications:tableCe qui a pour effet d'ajouter une migration : Après avoir effectué la migration on se retrouve avec cette table notifications : C'est dans cette table que sont stockées les notifications.
La notification
Comme pour les emails il nous faut une classe de notification :<?php namespace App\Notifications; use Illuminate\Notifications\Notification; use App\Models\Post; class Commented extends Notification { /** * Post property. * * @var \App\User\Post */ protected $post; /** * Create a new notification instance. * * @param \App\Models\Post * @return void */ public function __construct(Post $post) { $this->post = $post; } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return ['database']; } /** * Get the array representation of the notification. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ 'title' => $this->post->title, 'slug' => $this->post->slug, ]; } }Cette fois dans la méthode via on a database. On voit qu'on doit transmettre dans le constructeur une instance de l'article concerné ($post). La mise en forme se fait dans la méthode toArray où on retourne un tableau de données qui sera transformé en JSON dans la base. On va ainsi transmettre le titre et le slug (pour générer l'url) de l'article.
Création d'une notification
Une notification sera créée quand un commentaire le sera. Voici la méthode store du contrôleur des commentaires (App\Http\Controllers\CommentController) :public function store(CommentRequest $request, BlogRepository $blogRepository) { $this->commentRepository->store($request->all(), $request->user()->id); $blog = $blogRepository->getById($request->post_id); $blog->user->notify(new Commented($blog)); if (!$request->user()->valid) { $request->session()->flash('warning', trans('front/blog.warning')); } return back(); }La ligne qui crée la notification est celle-ci :
$blog->user->notify(new Commented($blog));Exactement comme on l'a vu pour les email ci-dessus. On trouve cet enregistrement dans la table des notifications :
La clé étrangère qui permet de connaître l'utilisateur est notifiable_id.
On a le type de notification pour les distinguer si on en a plusieurs, ce qui n'est pas le cas de l'application d'exemple. La colonne read_at est à NULL parce que la notification n'a pas encore été lue. Dans la colonne data on retrouve sous forme de JSON les informations transmises (title et slug).Les routes et le contrôleur
On a deux routes :Route::get('notifications/{user}', 'NotificationController@index'); Route::put('notifications/{notification}', 'NotificationController@update');La première est pour l'affichage des notifications. La seconde est pour marquer une notification comme lue. Voici le contrôleur (App\Http\Controllers\NotificationController) :
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\User; use Illuminate\Notifications\DatabaseNotification; class NotificationController extends Controller { /** * Create a new NotificationController instance. * * @return void */ public function __construct() { $this->middleware('redac'); } /** * Display a listing notifications. * * @param \App\Models\User $user * @return \Illuminate\Http\Response */ public function index(User $user) { return view('back.notifications.index', compact('user')); } /** * Update the notification. * * @param Illuminate\Http\Request $request * @param integer $id * @return \Illuminate\Http\Response */ public function update(Request $request, DatabaseNotification $notification) { $notification->markAsRead(); if($request->user()->unreadNotifications->isEmpty()) { return redirect()->route('blog.index'); } return back(); } }
On applique le middleware redac pour que les méthodes ne soient accessibles qu'aux rédacteurs.
La première méthode (index) ne pose pas de problème puisqu'on se contente d'utiliser une vue en transmettant une instance du modèle pour l'utilisateur connecté. La seconde méthode (update) est destinée à marquer une notification comme lue, ce qui se fait avec la méthode markAsRead.Remarquez que pour les deux méthodes on utilise la liaison automatique entre le paramètre de la route et un modèle. De cette manière on a directement une instance du modèle dans la méthode.
La vue index
Voici la vue pour afficher les notifications (resources/views/back/notifications/index.blade.php) :@extends('back.template') @section('main') @include('back.partials.entete', ['title' => trans('back/notifications.notifications'), 'icon' => 'bell', 'fil' => trans('back/notifications.new-notifications')]) <div class="row col-lg-12"> <div class="table-responsive"> <table class="table"> <thead> <tr> <th>{!! trans('back/notifications.post') !!}</th> <th>{!! trans('back/notifications.date') !!}</th> <th>{!! trans('back/notifications.valid') !!}</th> <th></th> </tr> </thead> <tbody> @foreach($user->unreadNotifications as $notification) <tr> <td>{!! link_to('blog/' . $notification->data['slug'], $notification->data['title']) !!}</td> <td>{{ formatDate($notification->created_at) }}</td> <td>{!! Form::checkbox(trans('valid'), null, $user->valid, ['disabled' => true]) !!}</td> <td> {!! Form::open(['method' => 'PUT', 'url' => 'notifications/' . $notification->id]) !!} {!! Form::submit(trans('back/notifications.erase'), ['class' => 'btn btn-success btn-block']) !!} {!! Form::close() !!} </td> </tr> @endforeach </tbody> </table> </div> </div> @endsection
On voit qu'on peut récupérer toutes les notifications non lues de l'utilisateur avec $user->unreadNotifications.
Voici l'aspect de la vue : Si on clique sur "Effacer" on appelle la méthode update du contrôleur vue ci-dessus et la notification est marquée comme lue (mise à jour de la colonne read_at) et elle disparaît de l'affichage. Il y aurait encore beaucoup à dire sur les notifications au-delà des deux exemples de ce chapitre, reportez-vous à la documentation officielle pour en savoir plus.En résumé
- Laravel comporte un système complet et performant de notifications.
- On peut envoyer des emails avec les notifications, leur mise en forme est facilitée par la présence de puissantes méthodes et d'un template.
- On peut stocker les notifications en base de données pour une utilisation ultérieure.
Par bestmomo
Aucun commentaire