扩展laravel通知渠道需三步:创建channel类、在appserviceprovider中注册、配置services.php;via()返回的渠道名必须与注册名完全一致,否则静默失败;totwilio()必须返回结构化数组而非字符串,以符合channel职责分离原则。

扩展 Laravel 通知渠道,本质是注册一个新 Channel 类,并确保 via() 返回它的标识名、toXxx() 方法存在且返回格式合法——不是写个类就完事,漏掉任一环节都会静默失败。
如何注册自定义短信 Channel(如 Twilio)
官方没内置统一短信抽象,所以你得自己封装。核心动作有三步:写 Channel 类、在服务提供者里注册、配置 config/services.php。
- 创建
app/Channels/TwilioChannel.php,实现send()方法,接收$notifiable和$notification,调用 Twilio SDK 发送 - 在
App\Providers\AppServiceProvider::boot()中调用Notification::extend('twilio', function () { return new TwilioChannel(); }); - 往
config/services.php加配置项:'twilio' => ['sid' => env('TWILIO_SID'), 'token' => env('TWILIO_TOKEN'), 'from' => '+1234567890']
注意:注册名 'twilio' 必须和 via() 返回的字符串完全一致,大小写敏感;否则 Laravel 直接跳过该渠道,不报错也不发。
via() 返回空数组或非法渠道名会怎样
通知彻底静默——不发邮件、不存库、不报异常、不写日志。这是最常踩的坑。
-
via()返回[]或['mails'](多了一个 s),Laravel 就当没这回事 - 写了
['vonage']但没装laravel/vonage-notification-channel包,也没在config/services.php配vonage键,同样无效 - 正确写法只接受已注册的字符串:如
['mail', 'database', 'twilio'],每个都必须能被 Laravel 解析为真实 Channel 实例
调试时可临时在 via() 里加 Log::debug('channels: ' . json_encode($this->via($user))) 确认返回值是否符合预期。
为什么 toTwilio() 必须返回数组而不是字符串
因为 Channel 的 send() 方法约定接收一个结构化载荷,不是原始文本。Laravel 原生 MailChannel 要 MailMessage 对象,DatabaseChannel 要数组,自定义 Channel 同理。
-
toTwilio($notifiable)应返回类似:['to' => $notifiable->phone, 'from' => config('services.twilio.from'), 'body' => '订单已发货'] - 如果返回纯字符串
'订单已发货',你的TwilioChannel::send()就得额外做解析,违背了 Channel 职责分离原则 - 这个数组会被直接传给
TwilioChannel::send(),由它决定怎么映射到 Twilio SDK 的参数(比如to→to,body→body)
同理,微信通知扩展包(如 laravel-notification-wechat)要求 toWeChat() 返回 Text 或 Template 实例,不是数组也不是字符串——接口契约由具体 Channel 定义。
数据库渠道的索引缺失会导致查询卡死
启用 database 渠道后,$user->unreadNotifications 拉得慢,大概率不是代码问题,是缺索引。
- Laravel 迁移只建了
id主键,没加查询必需的联合索引 - 必须手动补上:
$table->index(['notifiable_id', 'notifiable_type'])(查某用户所有通知) - 如果还常用
unreadNotifications()->where('type', '...'),建议再加:$table->index(['notifiable_id', 'notifiable_type', 'read_at'])
别等线上慢了才加——notifications 表一旦数据过万,没索引的 WHERE notifiable_id = ? AND notifiable_type = ? 查询会全表扫,前端加载未读数直接超时。











