Notificaciones
Laravel proporciona un sistema unificado para enviar notificaciones a través de múltiples canales: email, base de datos, SMS, Slack y más. Una sola clase de notificación puede enviarse por varios canales simultáneamente.
¿Por qué usar notificaciones?
Las notificaciones son diferentes a los emails tradicionales. Mientras que un email es un mensaje puntual, una notificación es un sistema que puede enviarse por múltiples canales según las preferencias del usuario.
Ejemplos de uso:
- Pedido confirmado: email + notificación en la app
- Nuevo mensaje: push notification + base de datos
- Pago recibido: email + SMS para montos altos
- Alerta del sistema: Slack para el equipo técnico
El trait Notifiable
Para enviar notificaciones a un modelo (normalmente
User), debe usar el trait Notifiable.
Laravel lo incluye por defecto en el modelo User:
<?php
namespace App\Models;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
// ...
}
Este trait proporciona el método notify()
y las relaciones para acceder a las notificaciones
del usuario. Sin él, no podrás enviar notificaciones.
Crear una notificación
Usa Artisan para generar una nueva notificación:
php artisan make:notification OrderConfirmed
Esto crea app/Notifications/OrderConfirmed.php:
<?php
declare(strict_types=1);
namespace App\Notifications;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class OrderConfirmed extends Notification
{
use Queueable;
public function __construct(
public Order $order
) {}
// Define por qué canales se enviará
public function via(object $notifiable): array
{
return ['mail'];
}
// Contenido para el canal email
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Pedido confirmado')
->greeting("Hola {$notifiable->name}")
->line("Tu pedido #{$this->order->id} ha sido confirmado.")
->line("Total: {$this->order->total}€")
->action('Ver pedido', route('orders.show', $this->order))
->line('Gracias por tu compra.');
}
}
Enviar notificaciones
Hay dos formas de enviar notificaciones. La más
común es usar el método notify() del
modelo User:
<?php
use App\Notifications\OrderConfirmed;
// Enviar a un usuario específico
$user->notify(new OrderConfirmed($order));
Para enviar a múltiples usuarios, usa la facade
Notification:
<?php
use Illuminate\Support\Facades\Notification;
$admins = User::where('is_admin', true)->get();
Notification::send($admins, new OrderConfirmed($order));
Notificaciones por email
El método toMail() devuelve un objeto
MailMessage con una API fluida para
construir el contenido:
<?php
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Bienvenido a nuestra plataforma')
->greeting('Hola ' . $notifiable->name)
->line('Gracias por registrarte.')
->line('Tu cuenta ha sido creada correctamente.')
->action('Acceder al dashboard', route('dashboard'))
->line('Si tienes preguntas, no dudes en contactarnos.')
->salutation('Saludos, el equipo de ' . config('app.name'));
}
Para emails de error o alerta, usa error():
<?php
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->error()
->subject('Pago fallido')
->line('No pudimos procesar tu pago.')
->action('Actualizar método de pago', route('billing.edit'));
}
Notificaciones en base de datos
El canal database guarda las notificaciones
en una tabla para mostrarlas en la aplicación (como
el icono de campana con notificaciones pendientes).
Primero, crea la tabla de notificaciones:
php artisan make:notifications-table
php artisan migrate
Añade el canal database al método
via() y define el método
toDatabase() o toArray():
<?php
declare(strict_types=1);
namespace App\Notifications;
use App\Models\Order;
use Illuminate\Notifications\Notification;
class OrderConfirmed extends Notification
{
public function __construct(
public Order $order
) {}
public function via(object $notifiable): array
{
return ['mail', 'database'];
}
public function toMail(object $notifiable): MailMessage
{
// ... configuración del email
}
// Datos que se guardan en la base de datos
public function toArray(object $notifiable): array
{
return [
'order_id' => $this->order->id,
'total' => $this->order->total,
'message' => "Tu pedido #{$this->order->id} ha sido confirmado.",
];
}
}
Leer notificaciones del usuario
El modelo User (con el trait Notifiable)
tiene relaciones para acceder a sus notificaciones:
<?php
$user = auth()->user();
// Todas las notificaciones
$user->notifications;
// Solo las no leídas
$user->unreadNotifications;
// Contar notificaciones no leídas
$user->unreadNotifications()->count();
// Acceder a los datos de una notificación
foreach ($user->unreadNotifications as $notification) {
echo $notification->data['message'];
}
Marcar notificaciones como leídas
<?php
// Marcar una notificación específica como leída
$notification->markAsRead();
// Marcar todas como leídas
$user->unreadNotifications->markAsRead();
// También puedes usar el método directo
auth()->user()->unreadNotifications()->update(['read_at' => now()]);
Un controlador típico para gestionar notificaciones:
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class NotificationController extends Controller
{
public function index(): View
{
return view('notifications.index', [
'notifications' => auth()->user()->notifications()->paginate(20),
]);
}
public function markAsRead(string $id): RedirectResponse
{
auth()->user()->notifications()->findOrFail($id)->markAsRead();
return redirect()->back();
}
public function markAllAsRead(): RedirectResponse
{
auth()->user()->unreadNotifications->markAsRead();
return redirect()->back()->with('success', 'Notificaciones marcadas como leídas.');
}
// Para APIs: devolver notificaciones como JSON
public function unread(): JsonResponse
{
return response()->json([
'count' => auth()->user()->unreadNotifications()->count(),
'notifications' => auth()->user()->unreadNotifications()->take(5)->get(),
]);
}
}
Canales condicionales
Puedes enviar por diferentes canales según condiciones del usuario o la notificación:
<?php
public function via(object $notifiable): array
{
$channels = ['database'];
// Siempre email si el usuario lo tiene habilitado
if ($notifiable->email_notifications) {
$channels[] = 'mail';
}
// SMS solo para pedidos grandes
if ($this->order->total > 1000) {
$channels[] = 'vonage'; // antes Nexmo
}
return $channels;
}
Notificaciones en cola
Para evitar que el envío de emails ralentice la
respuesta, implementa ShouldQueue:
<?php
declare(strict_types=1);
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class OrderConfirmed extends Notification implements ShouldQueue
{
use Queueable;
// La notificación se enviará en segundo plano
}
Recuerda: Para que las
notificaciones en cola funcionen, debes tener
un worker ejecutándose (php artisan queue:work).
Vimos esto en la lección anterior sobre Colas y Jobs.
Notificaciones bajo demanda
A veces necesitas notificar a alguien que no es un usuario de tu aplicación (por ejemplo, enviar un email a una dirección específica):
<?php
use Illuminate\Support\Facades\Notification;
use App\Notifications\ContactFormReceived;
Notification::route('mail', 'admin@example.com')
->notify(new ContactFormReceived($message));
// Múltiples canales
Notification::route('mail', 'admin@example.com')
->route('slack', 'https://hooks.slack.com/...')
->notify(new ContactFormReceived($message));
Personalizar el remitente
Por defecto, Laravel usa la configuración de
config/mail.php. Puedes personalizarlo
por notificación:
<?php
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->from('soporte@example.com', 'Equipo de Soporte')
->replyTo('no-reply@example.com')
->subject('Tu solicitud ha sido recibida')
->line('Hemos recibido tu mensaje y te responderemos pronto.');
}
Adjuntar archivos
<?php
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Tu factura')
->line('Adjuntamos la factura de tu pedido.')
->attach(storage_path("app/invoices/{$this->order->id}.pdf"), [
'as' => "factura-{$this->order->id}.pdf",
'mime' => 'application/pdf',
]);
}
Resumen
- Las notificaciones permiten enviar mensajes por múltiples canales desde una sola clase
- Crea notificaciones con
php artisan make:notification - El método
via()define los canales:mail,database,slack, etc. - Usa
$user->notify()para enviar a un usuario - El canal
databaseguarda notificaciones para mostrar en la UI - Implementa
ShouldQueuepara enviar en segundo plano - Accede a las notificaciones con
$user->notificationsy$user->unreadNotifications
Ejercicios
Ejercicio 1: Notificación de bienvenida
Crea una notificación WelcomeNotification
que se envíe por email cuando un usuario se registra.
Debe incluir un saludo personalizado con el nombre
del usuario y un botón para acceder al dashboard.
Ver solución
php artisan make:notification WelcomeNotification
<?php
// app/Notifications/WelcomeNotification.php
declare(strict_types=1);
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class WelcomeNotification extends Notification implements ShouldQueue
{
use Queueable;
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Bienvenido a ' . config('app.name'))
->greeting("¡Hola {$notifiable->name}!")
->line('Gracias por unirte a nuestra plataforma.')
->line('Tu cuenta ha sido creada correctamente.')
->action('Ir al dashboard', route('dashboard'))
->line('Si tienes alguna pregunta, no dudes en contactarnos.')
->salutation('Saludos, el equipo de ' . config('app.name'));
}
}
<?php
// Uso en el controlador de registro
use App\Notifications\WelcomeNotification;
public function store(Request $request): RedirectResponse
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$user->notify(new WelcomeNotification());
return redirect()->route('dashboard');
}
Ejercicio 2: Notificación multicanal
Crea una notificación NewCommentNotification
que se envíe por email y base de datos cuando alguien
comenta en un artículo del usuario. Guarda en la
base de datos el ID del comentario, el nombre del
autor y un mensaje descriptivo.
Ver solución
php artisan make:notification NewCommentNotification
<?php
// app/Notifications/NewCommentNotification.php
declare(strict_types=1);
namespace App\Notifications;
use App\Models\Comment;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class NewCommentNotification extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(
public Comment $comment
) {}
public function via(object $notifiable): array
{
return ['mail', 'database'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Nuevo comentario en tu artículo')
->greeting("Hola {$notifiable->name}")
->line("{$this->comment->author->name} ha comentado en tu artículo:")
->line("\"{$this->comment->article->title}\"")
->action('Ver comentario', route('articles.show', $this->comment->article))
->line('Gracias por ser parte de nuestra comunidad.');
}
public function toArray(object $notifiable): array
{
return [
'comment_id' => $this->comment->id,
'author_name' => $this->comment->author->name,
'article_id' => $this->comment->article_id,
'message' => "{$this->comment->author->name} comentó en \"{$this->comment->article->title}\"",
];
}
}
<?php
// Uso en el controlador de comentarios
use App\Notifications\NewCommentNotification;
public function store(Request $request, Article $article): RedirectResponse
{
$comment = $article->comments()->create([
'user_id' => auth()->id(),
'body' => $request->body,
]);
// Notificar al autor del artículo (si no es el mismo que comenta)
if ($article->user_id !== auth()->id()) {
$article->author->notify(new NewCommentNotification($comment));
}
return redirect()->back()->with('success', 'Comentario publicado.');
}
Ejercicio 3: Listar notificaciones no leídas
Crea un controlador y una vista para mostrar las notificaciones no leídas del usuario autenticado. Incluye un botón para marcar todas como leídas.
Ver solución
php artisan make:controller NotificationController
<?php
// app/Http/Controllers/NotificationController.php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
class NotificationController extends Controller
{
public function index(): View
{
return view('notifications.index', [
'notifications' => auth()->user()->unreadNotifications,
]);
}
public function markAsRead(string $id): RedirectResponse
{
$notification = auth()->user()
->notifications()
->findOrFail($id);
$notification->markAsRead();
return redirect()->back()
->with('success', 'Notificación marcada como leída.');
}
public function markAllAsRead(): RedirectResponse
{
auth()->user()->unreadNotifications->markAsRead();
return redirect()->back()
->with('success', 'Todas las notificaciones marcadas como leídas.');
}
}
<?php
// routes/web.php
use App\Http\Controllers\NotificationController;
Route::middleware('auth')->group(function () {
Route::get('/notifications', [NotificationController::class, 'index'])
->name('notifications.index');
Route::post('/notifications/{id}/read', [NotificationController::class, 'markAsRead'])
->name('notifications.read');
Route::post('/notifications/read-all', [NotificationController::class, 'markAllAsRead'])
->name('notifications.read-all');
});
<!-- resources/views/notifications/index.blade.php -->
<x-app-layout>
<h1>Notificaciones</h1>
@if($notifications->count() > 0)
<form action="{{ route('notifications.read-all') }}" method="POST">
@csrf
<button type="submit">Marcar todas como leídas</button>
</form>
<ul>
@foreach($notifications as $notification)
<li>
<p>{{ $notification->data['message'] }}</p>
<small>{{ $notification->created_at->diffForHumans() }}</small>
<form action="{{ route('notifications.read', $notification->id) }}" method="POST">
@csrf
<button type="submit">Marcar como leída</button>
</form>
</li>
@endforeach
</ul>
@else
<p>No tienes notificaciones pendientes.</p>
@endif
</x-app-layout>
¿Has encontrado un error o tienes una sugerencia para mejorar esta lección?
Escríbenos¿Te está gustando el curso?
Tenemos cursos premium con proyectos reales, soporte personalizado y certificado.
Descubrir cursos premium