Notification:多渠道通知系统
High Contrast
Dark Mode
Light Mode
Sepia
Forest
1 min read170 words

Notification:多渠道通知系统

Laravel Notification 用统一的接口管理多种通知渠道——邮件、Slack、SMS、数据库内通知。用户可以选择自己偏好的通知方式,代码结构保持一致。


创建 Notification

php artisan make:notification TaskCompletedNotification
php artisan make:notification TeamInvitationNotification
<?php
// app/Notifications/TaskCompletedNotification.php
namespace App\Notifications;
use App\Models\Task;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
class TaskCompletedNotification extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(
public readonly Task $task
) {}
// 通知渠道:根据用户偏好动态决定
public function via(object $notifiable): array
{
$channels = ['database'];  // 始终存入数据库(应用内通知)
// 根据用户通知设置决定是否发邮件
if ($notifiable->notification_preferences['email_on_completion'] ?? true) {
$channels[] = 'mail';
}
// 如果用户设置了 Slack
if ($notifiable->slack_webhook_url) {
$channels[] = 'slack';
}
return $channels;
}
// 邮件内容
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject("✅ 任务已完成:{$this->task->title}")
->greeting("Hi {$notifiable->name},")
->line("恭喜!你的任务《{$this->task->title}》已标记为完成。")
->action('查看任务', route('tasks.show', $this->task))
->line('感谢使用 TaskFlow!');
}
// Slack 消息
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->success()
->content("✅ 任务完成:{$this->task->title}")
->attachment(function ($attachment) {
$attachment->title($this->task->title, route('tasks.show', $this->task))
->fields([
'状态'  => '已完成',
'完成时间' => now()->format('Y-m-d H:i'),
]);
});
}
// 数据库通知(应用内通知中心)
public function toDatabase(object $notifiable): array
{
return [
'type'    => 'task_completed',
'task_id' => $this->task->id,
'title'   => $this->task->title,
'message' => "任务《{$this->task->title}》已完成",
];
}
// 数组格式(toDatabase 的别名,某些场景用)
public function toArray(object $notifiable): array
{
return $this->toDatabase($notifiable);
}
}

发送通知

use Illuminate\Support\Facades\Notification;
// 给单个用户发通知
$user->notify(new TaskCompletedNotification($task));
// 给多个用户发通知(Facade)
Notification::send($users, new TaskCompletedNotification($task));
// 发给非模型(如临时邮件地址)
Notification::route('mail', 'temp@example.com')
->notify(new TeamInvitationNotification($team, $inviteToken));
// 立即同步发送(不入队,即使实现了 ShouldQueue)
$user->notifyNow(new TaskCompletedNotification($task));

数据库通知(应用内通知中心)

# 创建 notifications 表
php artisan notifications:table
php artisan migrate
// app/Models/User.php
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;  // 提供 notify()、notifications() 等方法
}
// 读取通知
$notifications = $user->notifications;                    // 所有通知
$unread        = $user->unreadNotifications;              // 未读通知
$count         = $user->unreadNotifications()->count();   // 未读数量
// 标记已读
$user->unreadNotifications->markAsRead();         // 标记全部已读
$notification->markAsRead();                      // 标记单条已读
// 删除通知
$user->notifications()->delete();
$user->readNotifications()->delete();  // 只删除已读
// API 接口:通知中心
// app/Http/Controllers/Api/V1/NotificationController.php
class NotificationController extends Controller
{
public function index(Request $request)
{
$notifications = $request->user()
->notifications()
->latest()
->paginate(20);
return response()->json([
'data'         => $notifications,
'unread_count' => $request->user()->unreadNotifications()->count(),
]);
}
public function markRead(Request $request, string $notificationId)
{
$notification = $request->user()
->notifications()
->findOrFail($notificationId);
$notification->markAsRead();
return response()->noContent();
}
public function markAllRead(Request $request)
{
$request->user()->unreadNotifications->markAsRead();
return response()->noContent();
}
}

SMS 通知(Vonage / AWS SNS)

composer require laravel/vonage-notification-channel
// app/Models/User.php
// 告诉 Laravel 短信发给哪个号码
public function routeNotificationForVonage(): string
{
return $this->phone_number;  // '+60112345678'
}
// Notification 中添加 SMS 渠道
public function via(object $notifiable): array
{
return ['mail', 'vonage', 'database'];
}
public function toVonage(object $notifiable): \Illuminate\Notifications\Messages\VonageMessage
{
return (new \Illuminate\Notifications\Messages\VonageMessage)
->content("TaskFlow: 你的任务《{$this->task->title}》已完成。");
}

用户通知偏好设置

// 让用户自定义通知设置
// database/migrations: add notification_preferences to users
// Schema::table('users', function (Blueprint $table) {
//     $table->jsonb('notification_preferences')->default('{}');
// });
// 更新通知设置 API
class NotificationPreferencesController extends Controller
{
public function update(Request $request)
{
$request->validate([
'email_on_completion' => ['boolean'],
'email_on_assignment' => ['boolean'],
'email_daily_digest'  => ['boolean'],
]);
$request->user()->update([
'notification_preferences' => $request->validated(),
]);
return response()->noContent();
}
}

下一章生产部署:Forge、Docker 与性能监控——TaskFlow 的所有功能都开发完了,最后一步是把它部署到生产环境。Laravel Forge 让你在 5 分钟内完成服务器配置和首次部署。