除了支持 发送邮件,Laravel 还支持通过各种渠道发送通知,包括邮件,短信(通过 Nexmo) 和 Slack。通知还可以存储在数据库中,以便在 Web 页面显示。
通常情况下,通知应该是简要的信息,通知用户应用中发生的事情。例如,如果您编写一个结算应用,可能会通过邮件或短信渠道发送一个「账单已支付」的通知给用户。
在 Laravel 中,每个通知用一个类表示(通常存储在 app/Notifications 目录中)。如果在应用中没有看到此目录也不要担心,它会在运行 Artisan 命令 make:notification 时自动创建:
php artisan make:notification InvoicePaid此命令会在 app/Notifications 中创建一个新的通知类。每个通知类都包含一个 via 方法和几个信息构建方法(例如 toMail 或 toDatabase),这些方法会将通知转换成为特定渠道优化的信息。
通知可以通过两种方式发送:使用 Notifiable Trait 的 notify 方法或使用 Notification facade。首先,我们研究下使用 Trait:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
}默认的 App\User 模型中使用了此 Trait,它包含一个可用于发送通知的方法:notify。notify 方法接收一个通知实例:
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));注意,可以在任何模型中使用
Illuminate\Notifications\NotifiableTrait。而不仅限于在User模型中引入它。
或者,也可以通过 Notification facade。当需要给多个通知实体(例如一个用户集合)发送通知时,非常有用。使用 Facade 发送通知,可以传递所有通知实体和通知实例给 send 方法:
Notification::send($users, new InvoicePaid($invoice));每个通知类都有一个 via 方法,决定通知要发送的渠道。开箱即用的通知渠道有 mail,database,broadcast,nexmo 和 slack。
如果要使用其它渠道发送,如 Telegram 或 Pusher,可以查看社区驱动的 Laravel 通知渠道网站。
via 方法接收一个要发送的通知类的实例 $notifiable。可以使用 $notifiable 来决定通知应该发送的渠道:
/**
* 获取通知发送渠道
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database'];
}使用队列发送通知前,应该配置队列并 启动队列进程。
发送通知可能会花很长时间,尤其是渠道需要调用外部 API 来发送通知时。为了加快应用的响应时间,可以通过 ShouldQueue 接口和 Queueable Trait 让通知在队列中进行。使用 make:notification 生成的所有通知都已引入了上述接口和 Trait,因此可以将其立即添加到通知类:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// ...
}ShouldQueue 接口添加到通知后,就可以像平时一样发送通知了。Laravel 会检测通知类是否实现了 ShouldQueue 接口并自动将通知添加到队列发送:
$user->notify(new InvoicePaid($invoice));如果要延迟发送通知,可以在通知实例化时链式调用 delay 方法:
$when = now()->addMinutes(10);
$user->notify((new InvoicePaid($invoice))->delay($when));有时可能要给应用中未存储的「用户」发送通知。使用 Notification::route 方法,可以在发送通知前指定临时通知路由:
Notification::route('mail', 'taylor@example.com')
->route('nexmo', '5555555555')
->notify(new InvoicePaid($invoice));如果通知支持作为邮件发送,则应在通知类中定义一个 toMail 方法。此方法接收一个 $notifiable 实体并返回一个 Illuminate\Notifications\Messages\MailMessage 实例。邮件信息可能包含文本行和一个「点击操作」。我们看一个 toMail 方法示例:
/**
* 获取邮件形式的通知
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->action('View Invoice', $url)
->line('Thank you for using our application!');
}注意我们在
toMail方法中使用了$this->invoice->id。可以在通知的构造函数中传递生成通知信息所需的任何数据。
在上述示例中,我们添加了一个问候语,一行文字,一个点击操作,然后是另一行文字。MailMessage 对象提供的这些方法可以简单快速地格式化小型业务邮件。邮件渠道会将信息组件翻译为漂亮的、响应式的 HTML 邮件模板以及一个纯文本的副本。以下是一个 mail 渠道生成的邮件示例:

当发送邮件通知时,确保在
config/app.php配置文件中设置了name值。此值会用在邮件通知信息的头部和底部。
除了在通知类中定义文本「行」,还可以使用 view 方法指定一个用于渲染通知邮件的自定义模板:
/**
* 获取邮件形式的通知
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)->view(
'emails.name', ['invoice' => $this->invoice]
);
}此外,还可以在 toMail 方法中返回一个 Mailable 对象:
use App\Mail\InvoicePaid as Mailable;
/**
* 获取邮件形式的通知
*
* @param mixed $notifiable
* @return Mailable
*/
public function toMail($notifiable)
{
return (new Mailable($this->invoice))->to($this->user->email);
}一些通知会通知用户错误信息,例如账单支付失败。可以在构建通知信息时调用 error 方法来表明这是关于错误信息的。当在邮件信息中使用 error 方法时,点击操作的按钮会是红色而不是蓝色:
/**
* 获取邮件形式的通知
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Message
*/
public function toMail($notifiable)
{
return (new MailMessage)
->error()
->subject('Notification Subject')
->line('...');
}通过 mail 渠道发送通知时,通知系统会自动在通知实体上查找 email 属性。可以通过在通知实体上定义 routeNotificationForMail 方法自定义用于接收通知的邮件地址:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* 获取用于接收邮件通知的邮件地址
*
* @param \Illuminate\Notifications\Notification $notification
* @return string
*/
public function routeNotificationForMail($notification)
{
return $this->email_address;
}
}默认情况下,邮件主题是「首字母大写」的通知类名。因此,如果通知类被命名为 InvoicePaid,邮件的主题会是 Invoice Paid。如果要明确指定邮件信息的主题,可以在构建信息时调用 subject 方法:
/**
* 获取邮件形式的通知
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Notification Subject')
->line('...');
}可以通过发布通知扩展包的资源修改邮件通知使用 HTML 模板和纯文本模板。运行如下命令后,邮件通知模板会位于 resources/views/vendor/notifications 目录下:
php artisan vendor:publish --tag=laravel-notificationsMarkdown 邮件通知允许您利用预先构建的邮件通知模板,同时允许您更自由地编写更长的自定义信息。由于信息是用 Markdown 编写的,因此 Laravel 能够将信息渲染为漂亮的、响应式的 HTML 模板,还会自动生成纯文本副本。
要生成通知和对应的 Markdown 模板,可以在使用 Artisan 命令 make:notification 的 --markdown 选项:
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid与其它邮件通知一样,Markdown 邮件通知应该在通知类中定义一个 toMail 方法。但是,不使用 line 和 action 方法构造通知,而是使用 markdown 方法指定要使用的 Markdown 模板的名称:
/**
* 获取邮件形式的通知
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}Markdown 邮件将 Blade 组件和 Markdown 语法结合使用,使您可以利用 Laravel 预制的通知组件轻松构建通知:
@component('mail::message')
# Invoice Paid
Your invoice has been paid!
@component('mail::button', ['url' => $url])
View Invoice
@endcomponent
Thanks,<br>
{{ config('app.name') }}
@endcomponent按钮组件渲染为一个居中对齐的按钮链接。此组件接收两个参数,一个 url 和一个可选的 color。支持的颜色有 primary,success 和 error。可以根据需要添加多个按钮组件:
@component('mail::button', ['url' => $url, 'color' => 'success'])
View Invoice
@endcomponent面板组件在面板中渲染给定的文本块,其背景颜色与信息的其余部分略有不同。可以引起您对给定文本块的注意:
@component('mail::panel')
This is the panel content.
@endcomponent表格组件允许您将 Markdown 表格转换为 HTML 表格。此组件接收 Markdown 表格作为其内容。表格列对齐支持使用默认的 Markdown 表格对齐语法:
@component('mail::table')
| Laravel | Table | Example |
| ------------- |:-------------:| --------:|
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
@endcomponent可以在应用中导出所有 Markdown 邮件组件进行自定义。要导出组件,可以使用 Artisan 命令 vendor:publish 发布 laravel-mail 的资源:
php artisan vendor:publish --tag=laravel-mail此命令会将 Markdown 邮件组件发布到 resources/views/vendor/mail 目录中。mail 目录包含一个 html 和一个 markdown 目录,每个目录中包含每个组件相应的内容。可以随意自定义这些组件。
导出组件后,resources/views/vendor/mail/html/themes 目录会包含一个 default.css 文件。可以自定义此文件中的 CSS,样式会自动内嵌到 Markdown 通知的 HTML 内容中。
如果要为 Markdown 组件构建一个全新的主题,可以在
html/themes目录中编写一个新的 CSS 文件并更改theme选项。
database 通知渠道将通知信息存储到一张数据表中。此表包含了如通知类型和自定义 JSON 数据等描述通知的信息。
可以查询此表,然后在应用的用户界面中显示通知。但是,在此之前,需要创建一张数据表来存放通知。可以使用 notifications:table 命令生成对应表结构的迁移:
php artisan notifications:table
php artisan migrate如果通知支持存储在数据表中,则应在通知类中定义一个 toDatabase 或 toArray 方法。此方法接收一个 $notifiable 实体并返回一个 PHP 数组。返回的数据将被转换为 JSON 后存储在 notifications 表的 data 字段中。我们看一个 toArray 方法的示例:
/**
* 获取数组形式的通知
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
];
}toDatabase Vs. toArraytoArray 方法还用在 broadcast 渠道中,决定广播到 JavaScript 客户端的数据。如果要为 database 和 broadcast 渠道定义两个不同形式的数组,那么应该定义 toDatabase 方法而不是 toArray 方法。
通知存储在数据库后,通知实体还需要一个便捷的方式来访问它们。包含在 Laravel 的默认 App\User 模型中的 Illuminate\Notifications\Notifiable Trait 包含了一个返回实体的通知的 Eloquent 关联 notifications。可以像访问其它 Eloquent 关联一样访问此方法来获取通知。默认情况下,通知通过 created_at 时间戳排序:
$user = App\User::find(1);
foreach ($user->notifications as $notification) {
echo $notification->type;
}如果只想获取「未读」通知,可以使用 unreadNotifications 关联。同样,这些通知会通过 created_at 时间戳排序:
$user = App\User::find(1);
foreach ($user->unreadNotifications as $notification) {
echo $notification->type;
}要从 JavaScript 客户端中获取通知,应该为应用定义一个通知控制器来返回通知实体(例如当前用户)对应的通知。然后在 JavaScript 客户端中发起到此控制器 URI 的 HTTP 请求。
通常情况下,当用户查看通知后要将其标记为「已读」。Illuminate\Notifications\Notifiable Trait 提供了一个 markAsRead 方法,用于在通知的数据库记录上更新 read_at 字段:
$user = App\User::find(1);
foreach ($user->unreadNotifications as $notification) {
$notification->markAsRead();
}不过,可直接在通知集合上使用 markAsRead 方法,而不用循环遍历每个通知:
$user->unreadNotifications->markAsRead();还可以使用批量更新语句将所有通知标记为已读,而无需从数据库中获取它们:
$user = App\User::find(1);
$user->unreadNotifications()->update(['read_at' => now()]);当然,可以使用 delete 从数据表中删除所有通知:
$user->notifications()->delete();广播通知前,您应该配置并熟悉了 Laravel 的 事件广播。事件广播提供了一种从 JavaScript 客户端对服务端触发的 Laravel 事件作出反应的方法。
broadcast 渠道使用 Laravel 的 事件广播 广播通知,允许 JavaScript 客户端实时获取通知。如果通知支持广播,那么应该在通知类中定义一个 toBroadcast 方法。此方法接收一个 $notifiable 实体并返回一个 BroadcastMessage 实例。返回的数据将被转换为 JSON 后广播到 JavaScript 客户端。我们看一个 toBroadcast 方法的示例:
use Illuminate\Notifications\Messages\BroadcastMessage;
/**
* 获取广播形式的通知
*
* @param mixed $notifiable
* @return BroadcastMessage
*/
public function toBroadcast($notifiable)
{
return new BroadcastMessage([
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
]);
}所有广播通知都使用队列广播。如果要配置用于广播操作的队列的队列连接或队列名称,可以使用 BroadcastMessage 的 onConnection 和 onQueue 方法:
return (new BroadcastMessage($data))
->onConnection('sqs')
->onQueue('broadcasts');除了您指定的数据外,广播通知还包含一个
type字段,该字段包含了通知的类名。
通知将广播到一个私有频道上,频道格式使用 {notifiable}.{id} 约定。因此,如果给 ID 为 1 的 App\User 实例发送了一个通知,此通知会被广播到 App.User.1 私有频道上。当使用 Laravel Echo 时,可以使用 notification 辅助方法轻松监听指定频道上的通知:
Echo.private('App.User.' + userId)
.notification((notification) => {
console.log(notification.type);
});如果要自定义通知实体接收广播通知的频道,可以在通知实体上定义一个 receivesBroadcastNotificationsOn 方法:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* 用户接收广播通知的频道
*
* @return string
*/
public function receivesBroadcastNotificationsOn()
{
return 'users.'.$this->id;
}
}Laravel 中发送短信通知使用 Nexmo 驱动。在通过 Nexmo 发送通知之前,需要使用 Composer 包管理器安装 nexmo/client 并添加一些配置选项到 config/services.php 配置文件中。可以复制以下示例配置快速开始:
'nexmo' => [
'key' => env('NEXMO_KEY'),
'secret' => env('NEXMO_SECRET'),
'sms_from' => '15556666666',
],sms_from 选项是短信发出的电话号码。应该在 Nexmo 的控制面板中为应用生成一个电话号码。
如果通知支持使用短信发送,则应在通知类中定义一个 toNexmo 方法。此方法接收一个 $notifiable 实体并返回一个 Illuminate\Notifications\Messages\MailMessage 实例。
/**
* 获取 Nexmo/短信形式的通知
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Your SMS message content');
}如果短信中包含 Unicode 字符,则应该在构造 NexmoMessage 实例时调用 unicode 方法:
/**
* 获取 Nexmo/短信形式的通知
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Your unicode message')
->unicode();
}如果要使用一个与 config/services.php 文件中指定的电话号码不同的电话号码发送一些通知,可以在 NexmoMessage 实例上使用 from 方法:
/**
* 获取 Nexmo/短信形式的通知
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Your SMS message content')
->from('15554443333');
}当通过 nexmo 渠道发送通知时,通知系统会自动在通知实体上查找 phone_number 属性。如果要自定义接收短信通知的电话号码,可以在实体上定义一个 routeNotificationForNexmo 方法:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* 获取用于接收短信通知的电话号码
*
* @param \Illuminate\Notifications\Notification $notification
* @return string
*/
public function routeNotificationForNexmo($notification)
{
return $this->phone;
}
}在通过 Slack 发送通知之前,必须使用 Composer 安装 Guzzle HTTP 库:
composer require guzzlehttp/guzzle还需要为 Slack 团队配置 Incoming Webhook 集成。此集成会在 获取 Slack 通知的 URL 时提供 URL。
如果通知支持使用 Slack 消息发送,则应该通知类中定义一个 toSlack 方法。此方法接收一个 $notifiable 实体并返回一个 Illuminate\Notifications\Messages\MailMessage 实例。Slack 消息可以包含文本内容和一个格式化其它文本或数组字段的「附加信息」。我们看一个基本的 toSlack 示例:
/**
* 获取 Slack 形式的通知
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->content('One of your invoices has been paid!');
}在此示例中,我们只发送了单行文本到 Slack,它会创建如下消息:

可以使用 from 和 to 方法自定义发送者和接收者。from 方法接收一个用户名和 emoji 表情符号,而 to 方法接收一个频道或用户名:
/**
* 获取 Slack 形式的通知
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->from('Ghost', ':ghost:')
->to('#other')
->content('This will be sent to #other');
}也可以使用一张图片,而不是一个表情:
/**
* 获取 Slack 形式的通知
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->from('Laravel')
->image('https://laravel.com/favicon.png')
->content('This will display the Laravel logo next to the message');
}还可以添加「附件信息」到 Slack 消息。附加信息提供了比简单的文本消息更丰富的格式化选项。在此示例中,我们将发送一个有关应用中发生的异常的错误通知,包括一个查看异常详情的链接:
/**
* 获取 Slack 形式的通知
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable)
{
$url = url('/exceptions/'.$this->exception->id);
return (new SlackMessage)
->error()
->content('Whoops! Something went wrong.')
->attachment(function ($attachment) use ($url) {
$attachment->title('Exception: File Not Found', $url)
->content('File [background.jpg] was not found.');
});
}上述示例生成的 Slack 消息看起来像这样:

附加信息也支持指定一个显示给用户的数组数据。给定的数据将以表格形式显示方便阅读:
/**
* 获取 Slack 形式的通知
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable)
{
$url = url('/invoices/'.$this->invoice->id);
return (new SlackMessage)
->success()
->content('One of your invoices has been paid!')
->attachment(function ($attachment) use ($url) {
$attachment->title('Invoice 1322', $url)
->fields([
'Title' => 'Server Expenses',
'Amount' => '$1,234',
'Via' => 'American Express',
'Was Overdue' => ':-1:',
]);
});
}上述示例生成的 Slack 消息看起来像这样:

如果一些附加内容字段包含 Markdown,可以使用 markdown 方法指示 Slack 将给定附加内容解析并显示 Markdown 格式的文本。此方法接收的值有:pretext,text 和/或 fields。有关 Slack 附加内容格式的更多信息,请查看 Slack API 文档:
/**
* 获取 Slack 形式的通知
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable)
{
$url = url('/exceptions/'.$this->exception->id);
return (new SlackMessage)
->error()
->content('Whoops! Something went wrong.')
->attachment(function ($attachment) use ($url) {
$attachment->title('Exception: File Not Found', $url)
->content('File [background.jpg] was *not found*.')
->markdown(['text']);
});
}要将 Slack 通知路由到正确的位置,可以在通知实体上定义一个 routeNotificationForSlack 方法。此方法应该返回一个通知被发送的 webhook URL。Webhook URL 可以通过添加一个 「Incoming Webhook」服务到 Slack 团队生成:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* 获取 Slack 渠道接收通知的 URL
*
* @param \Illuminate\Notifications\Notification $notification
* @return string
*/
public function routeNotificationForSlack($notification)
{
return 'https://hooks.slack.com/services/...';
}
}Laravel 允许发送通知时使用当前语言以外的语言,甚至通知在队列中也会记住此语言。
为此,Illuminate\Notifications\Notification 类提供了一个 locale 方法用来设置要使用的语言。在格式化通知时应用会自动切换到该语言,格式化完成后恢复为之前的语言:
$user->notify((new InvoicePaid($invoice))->locale('es'));Localization of multiple notifiable entries may also be achieved via the Notification facade:
Notification::locale('es')->send($users, new InvoicePaid($invoice));有时,应用存储了每个用户的首选语言。通过在一个模型或更多模型上实现 HasLocalePreference Contract,可以指示 Laravel 在发送通知时使用存储的首选语言:
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Model implements HasLocalePreference
{
/**
* 获取用户的首选语言
*
* @return string
*/
public function preferredLocale()
{
return $this->locale;
}
}实现此接口后,Laravel 会在发送通知和邮件给模型时自动使用首选语言。因此,当使用此接口时就不用调用 locale 方法了:
$user->notify(new InvoicePaid($invoice));发送通知时,通知系统触发了 Illuminate\Notifications\Events\NotificationSent 事件。此事件包含「notifiable」实体和通知实例自身。可以在 EventServiceProvider 中为该事件注册监听器:
/**
* 应用的事件监听器映射
*
* @var array
*/
protected $listen = [
'Illuminate\Notifications\Events\NotificationSent' => [
'App\Listeners\LogNotification',
],
];在
EventServiceProvider中注册监听器后,可以使用 Artisan 命令event:generate快速生成监听器类。
在事件监听器中,可以访问事件的 notifiable,notification 和 channel 属性了解通知接收者或通知自身的更多信息:
/**
* 处理事件
*
* @param NotificationSent $event
* @return void
*/
public function handle(NotificationSent $event)
{
// $event->channel
// $event->notifiable
// $event->notification
}Laravel 自带了一些通知渠道,但是您可能希望编写自己的驱动通过其它渠道发送通知。Laravel 中很容易实现。首先,定义一个包含 send 方法的类。此方法应接收两个参数:$notifiable 和 $notification:
namespace App\Channels;
use Illuminate\Notifications\Notification;
class VoiceChannel
{
/**
* 发送给定通知
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @return void
*/
public function send($notifiable, Notification $notification)
{
$message = $notification->toVoice($notifiable);
// 向 $notifiable 实例发送通知
}
}定义通知渠道类后,就可以从 via 方法中返回任何通知的类名了:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use App\Channels\VoiceChannel;
use App\Channels\Messages\VoiceMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoicePaid extends Notification
{
use Queueable;
/**
* 获取通知渠道
*
* @param mixed $notifiable
* @return array|string
*/
public function via($notifiable)
{
return [VoiceChannel::class];
}
/**
* 获取语音形式的通知
*
* @param mixed $notifiable
* @return VoiceMessage
*/
public function toVoice($notifiable)
{
// ...
}
}