Advanced Laravel
Advanced Notifications & Broadcasting
Advanced Notifications & Broadcasting
Laravel's notification system provides a unified API for sending notifications across multiple channels. Combined with broadcasting, you can create real-time, interactive applications that keep users informed through their preferred communication channels.
Available Channels: Database, Mail, Broadcast, SMS (Vonage/Twilio), Slack, Discord, and custom channels. You can send a single notification to multiple channels simultaneously.
Custom Notification Channels
Creating custom channels allows you to send notifications through any service:
<?php
// app/Notifications/Channels/WhatsAppChannel.php
namespace App\Notifications\Channels;
use Illuminate\Notifications\Notification;
class WhatsAppChannel
{
public function send($notifiable, Notification $notification)
{
// Get the message from notification
$message = $notification->toWhatsApp($notifiable);
// Send via WhatsApp API
$phoneNumber = $notifiable->routeNotificationFor('whatsapp', $notification);
Http::post('https://api.whatsapp.com/send', [
'phone' => $phoneNumber,
'message' => $message->content,
'media_url' => $message->mediaUrl ?? null,
]);
}
}
// Create a notification
class OrderShipped extends Notification
{
protected $order;
public function __construct($order)
{
$this->order = $order;
}
public function via($notifiable)
{
return ['whatsapp', 'database', 'mail'];
}
public function toWhatsApp($notifiable)
{
return (object) [
'content' => "Your order #{$this->order->id} has been shipped!",
'mediaUrl' => $this->order->tracking_image_url,
];
}
public function toDatabase($notifiable)
{
return [
'order_id' => $this->order->id,
'tracking_number' => $this->order->tracking_number,
'message' => 'Your order has been shipped',
];
}
}
// User model
public function routeNotificationForWhatsApp($notification)
{
return $this->whatsapp_number;
}
// Send notification
$user->notify(new OrderShipped($order));
Database Notifications
Store notifications in the database for in-app notification centers:
<?php
// Migration: php artisan notifications:table
// php artisan migrate
// Notification with database channel
class CommentReceived extends Notification
{
protected $comment;
public function via($notifiable)
{
return ['database'];
}
public function toDatabase($notifiable)
{
return [
'comment_id' => $this->comment->id,
'post_id' => $this->comment->post_id,
'author' => $this->comment->author->name,
'message' => $this->comment->author->name . ' commented on your post',
'action_url' => route('posts.show', $this->comment->post_id),
];
}
}
// Retrieve notifications in controller
class NotificationController extends Controller
{
public function index()
{
$notifications = auth()->user()
->notifications()
->paginate(20);
return view('notifications.index', compact('notifications'));
}
public function unread()
{
$unreadNotifications = auth()->user()
->unreadNotifications()
->get();
return response()->json($unreadNotifications);
}
public function markAsRead($id)
{
$notification = auth()->user()
->notifications()
->findOrFail($id);
$notification->markAsRead();
return redirect($notification->data['action_url']);
}
public function markAllAsRead()
{
auth()->user()->unreadNotifications->markAsRead();
return response()->json(['message' => 'All notifications marked as read']);
}
}
Notification Center UI: Display unread count in your navigation using `auth()->user()->unreadNotifications->count()`. Use real-time updates with broadcasting to show new notifications instantly.
Broadcast Notifications
Send real-time notifications using Laravel Echo and WebSockets:
<?php
// Install broadcasting support
// composer require pusher/pusher-php-server
// npm install --save-dev laravel-echo pusher-js
// config/broadcasting.php
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
],
],
],
// Notification with broadcast channel
class NewMessage extends Notification implements ShouldBroadcast
{
use Queueable;
protected $message;
public function via($notifiable)
{
return ['database', 'broadcast'];
}
public function toDatabase($notifiable)
{
return [
'message_id' => $this->message->id,
'sender' => $this->message->sender->name,
'preview' => Str::limit($this->message->content, 50),
];
}
public function toBroadcast($notifiable)
{
return new BroadcastMessage([
'message_id' => $this->message->id,
'sender' => [
'id' => $this->message->sender->id,
'name' => $this->message->sender->name,
'avatar' => $this->message->sender->avatar_url,
],
'content' => $this->message->content,
'created_at' => $this->message->created_at->toISOString(),
]);
}
public function broadcastType()
{
return 'message.new';
}
}
// Frontend with Laravel Echo (resources/js/bootstrap.js)
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true
});
// Listen for notifications
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
console.log('New notification:', notification);
// Show toast notification
showNotification(notification.sender.name, notification.content);
// Update unread count
updateUnreadCount();
// Play notification sound
playNotificationSound();
});
Advanced Notification Formatting
<?php
// Rich mail notifications with actions
class InvoicePaid extends Notification
{
use Queueable;
protected $invoice;
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Invoice Paid')
->greeting('Hello '.$notifiable->name.',')
->line('Your invoice #'.$this->invoice->id.' has been paid.')
->lineIf($this->invoice->hasDiscount(), 'A discount of $'.$this->invoice->discount.' was applied.')
->action('View Invoice', url('/invoices/'.$this->invoice->id))
->line('Thank you for your business!')
->attach(storage_path('invoices/'.$this->invoice->pdf_file), [
'as' => 'invoice.pdf',
'mime' => 'application/pdf',
]);
}
}
// Conditional channels based on user preferences
class SystemAlert extends Notification
{
public function via($notifiable)
{
$channels = ['database'];
if ($notifiable->prefers_email) {
$channels[] = 'mail';
}
if ($notifiable->prefers_sms) {
$channels[] = 'vonage';
}
if ($notifiable->is_online) {
$channels[] = 'broadcast';
}
return $channels;
}
}
// Throttled notifications (prevent spam)
class RateLimitedNotification extends Notification
{
public function shouldSend($notifiable, $channel)
{
// Only send email once per hour
if ($channel === 'mail') {
return Cache::add(
'notification:'.$notifiable->id.':'.$channel,
true,
now()->addHour()
);
}
return true;
}
}
Broadcasting Security: Always use private or presence channels for user-specific notifications. Never broadcast sensitive information on public channels. Implement proper authorization in your broadcasting routes.
On-Demand Notifications
Send notifications to non-users (guests, external parties):
<?php
use Illuminate\Support\Facades\Notification;
// Send to email address without user model
Notification::route('mail', 'guest@example.com')
->route('vonage', '5555555555')
->notify(new OrderConfirmation($order));
// Send to multiple recipients
Notification::route('mail', [
'support@example.com',
'admin@example.com',
])->notify(new SystemAlert($issue));
// With Slack webhook
Notification::route('slack', env('SLACK_WEBHOOK_URL'))
->notify(new DeploymentCompleted($deployment));
// Custom notification class for on-demand
class GuestPasswordReset extends Notification
{
protected $token;
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
$email = $notifiable->routes['mail'];
return (new MailMessage)
->subject('Password Reset Request')
->line('You requested a password reset.')
->action('Reset Password', url('reset-password/'.$this->token))
->line('If you did not request this, please ignore this email.');
}
}
Exercise 1: Build a notification center with unread badges, mark as read functionality, and real-time updates using broadcasting. Include filtering by notification type and a "mark all as read" button.
Exercise 2: Create a custom Telegram notification channel. Implement a TelegramChannel class that sends messages via the Telegram Bot API. Send order updates through both email and Telegram.
Exercise 3: Implement a notification preference system where users can choose which channels they want to receive notifications on. Create a settings page with toggles for email, SMS, and push notifications for different event types.