Laravel 通知系统使用

Laravel 的通知系统提供了统一的 API 来发送通知到多种频道,包括邮件、短信(通过 Nexmo 或 Twilio)、Slack、数据库、广播等。你可以轻松地向用户发送重要提醒、订单状态更新、系统警报等。本章将带你全面掌握 Laravel 通知系统的用法。

📢 核心概念: 通知系统围绕两个核心组件:通知类(定义通知内容)和 频道(传递方式)。你只需创建通知类,Laravel 会负责将其发送到指定频道。

1. 环境准备

首先,确保你的 Laravel 版本 ≥ 5.3(通知系统原生支持)。对于数据库通知,你需要创建通知表:


php artisan notifications:table
php artisan migrate
                    

这会在数据库中创建 notifications 表,用于存储通知记录。

2. 生成通知类

使用 Artisan 命令快速创建通知类,例如订单发货通知:


php artisan make:notification OrderShipped
                    

生成的类位于 app/Notifications/OrderShipped.php。它包含两个方法:via() 指定使用的频道,以及 toMail()toDatabase() 等针对特定频道的输出方法。

3. 发送通知

有两种方式发送通知:

  • 通过模型的 notify() 方法(模型需使用 Notifiable trait)。
  • 通过 Notification Facade 的 send() 方法。

方法一:使用 Notifiable trait


use App\Models\User;
use App\Notifications\OrderShipped;

$user = User::find(1);
$user->notify(new OrderShipped($order));
                    

User 模型默认已引入 Illuminate\Notifications\Notifiable trait。

方法二:使用 Notification Facade


use Illuminate\Support\Facades\Notification;
use App\Notifications\OrderShipped;

Notification::send($users, new OrderShipped($order));
                    

$users 可以是集合或数组,会批量发送通知。

4. 邮件通知

邮件通知是最常用的频道。在通知类的 toMail() 方法中定义邮件内容。


use Illuminate\Notifications\Messages\MailMessage;

public function toMail($notifiable)
{
    return (new MailMessage)
                ->greeting('你好!')
                ->line('您的订单已发货。')
                ->action('查看订单', url('/orders/'.$this->order->id))
                ->line('谢谢您的支持!');
}
                    

你也可以使用 Markdown 邮件,提供更美观的模板:


return (new MailMessage)
    ->subject('订单已发货')
    ->markdown('emails.orders.shipped', ['order' => $this->order]);
                    

Markdown 模板位于 resources/views/emails/orders/shipped.blade.php,可使用 Laravel 预置的邮件组件。

5. 数据库通知

数据库通知将通知存储在 notifications 表中,便于在应用内显示。在 toDatabase() 方法中返回一个数组,该数组会被 JSON 序列化后存入数据库。


public function toDatabase($notifiable)
{
    return [
        'order_id' => $this->order->id,
        'amount' => $this->order->amount,
        'message' => '您的订单已发货!',
    ];
}
                    

读取用户的通知:


$user = User::find(1);
$notifications = $user->notifications; // 所有通知
$unread = $user->unreadNotifications; // 未读通知
                    

标记为已读:


$user->unreadNotifications->markAsRead();
// 或单条
$notification->markAsRead();
                    

6. 广播通知(实时)

广播通知使用 Laravel 的事件广播系统,通过 WebSocket 将通知实时推送到前端。需配置广播驱动(如 Pusher、Redis)。在 toBroadcast() 方法中返回数据。


use Illuminate\Notifications\Messages\BroadcastMessage;

public function toBroadcast($notifiable)
{
    return new BroadcastMessage([
        'order_id' => $this->order->id,
        'message' => '订单已发货',
    ]);
}
                    

广播通知会自动推送事件到私有频道 private-App.Models.User.{id},前端需订阅该频道并监听 Illuminate\Notifications\Events\BroadcastNotificationCreated 事件。

⚠️ 注意: 广播通知默认不会持久化,如需同时存储数据库,可在 via() 中返回 ['database', 'broadcast']

7. 短信与 Slack 通知

Laravel 支持通过 Vonage(原 Nexmo)或 Twilio 发送短信,以及通过 Slack 发送消息。需要先安装相应驱动。

短信通知示例


use Illuminate\Notifications\Messages\VonageMessage;

public function toVonage($notifiable)
{
    return (new VonageMessage)
                ->content('您的订单已发货!');
}
                    

Slack 通知示例


use Illuminate\Notifications\Messages\SlackMessage;

public function toSlack($notifiable)
{
    return (new SlackMessage)
                ->content('新订单已创建!')
                ->attachment(function ($attachment) {
                    $attachment->title('订单详情', url('/orders/1'))
                              ->fields([
                                  '订单号' => 'ORD-123',
                                  '金额' => '$99.99',
                              ]);
                });
}
                    

8. 自定义频道

如果内置频道不满足需求,你可以创建自定义频道。首先定义一个类,实现 send 方法:


namespace App\Notifications\Channels;

use Illuminate\Notifications\Notification;

class SmsChannel
{
    public function send($notifiable, Notification $notification)
    {
        $message = $notification->toSms($notifiable);
        // 发送短信逻辑...
    }
}
                    

然后在通知类的 via() 中返回自定义频道的名称:


public function via($notifiable)
{
    return [\App\Notifications\Channels\SmsChannel::class];
}

public function toSms($notifiable)
{
    return '您的订单已发货!';
}
                    

9. 队列通知(提升性能)

发送通知(尤其是邮件、短信)可能耗时较长,建议放入队列。只需让通知类实现 ShouldQueue 接口,并添加 Queueable trait:


use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Notification implements ShouldQueue
{
    use Queueable;

    // ...
}
                    

现在所有通过此通知类发送的操作都会自动推送到队列。你也可以在发送时延迟:


$user->notify((new OrderShipped($order))->delay(now()->addMinutes(10)));
                    

10. 最佳实践与常见问题

  • 避免在通知中直接传递模型: 如果使用队列,通知类会被序列化。建议传递模型 ID,在通知类内部查询,避免序列化问题。
  • 设置邮件发送者地址:config/mail.php 或通知中指定 from 地址。
  • 数据库通知分页: 用户可能有很多通知,使用 $user->notifications()->paginate(20) 分页。
  • 本地测试: 使用 log 频道或 mailtrap 测试邮件通知,避免真实发送。
  • 频道条件发送:via() 中可以动态决定发送哪些频道,例如根据用户偏好。
💡 提示: Laravel 通知系统还支持“通知路由”,允许你动态指定每个频道的接收地址(如邮件地址、手机号)。在通知类中定义 routeNotificationForMail()routeNotificationForVonage() 等方法即可。

示例:动态路由邮件地址


public function routeNotificationForMail($notification)
{
    return $this->email_address;
}
                    

11. 总结

Laravel 的通知系统提供了一个灵活、可扩展的框架,让你可以轻松地将通知发送到多种渠道。通过结合队列、数据库存储和实时广播,你可以构建出专业级的用户通知体验。掌握这些技能后,你可以应对大多数应用中的通知需求。

📖 官方文档: Laravel Notifications 提供了更详细的配置和高级用法。