通知

简介

除了支持 发送邮件,Laravel 还支持通过各种渠道发送通知,包括邮件,短信(通过 Nexmo) 和 Slack。通知还可以存储在数据库中,以便在 Web 页面显示。

通常情况下,通知应该是简要的信息,通知用户应用中发生的事情。例如,如果您编写一个结算应用,可能会通过邮件或短信渠道发送一个「账单已支付」的通知给用户。

创建通知

在 Laravel 中,每个通知用一个类表示(通常存储在 app/Notifications 目录中)。如果在应用中没有看到此目录也不要担心,它会在运行 Artisan 命令 make:notification 时自动创建:

php artisan make:notification InvoicePaid

此命令会在 app/Notifications 中创建一个新的通知类。每个通知类都包含一个 via 方法和几个信息构建方法(例如 toMailtoDatabase),这些方法会将通知转换成为特定渠道优化的信息。

发送通知

使用 Notifiable Trait

通知可以通过两种方式发送:使用 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,它包含一个可用于发送通知的方法:notifynotify 方法接收一个通知实例:

use App\Notifications\InvoicePaid;

$user->notify(new InvoicePaid($invoice));

注意,可以在任何模型中使用 Illuminate\Notifications\Notifiable Trait。而不仅限于在 User 模型中引入它。

使用 Notification Facade

或者,也可以通过 Notification facade。当需要给多个通知实体(例如一个用户集合)发送通知时,非常有用。使用 Facade 发送通知,可以传递所有通知实体和通知实例给 send 方法:

Notification::send($users, new InvoicePaid($invoice));

指定发送渠道

每个通知类都有一个 via 方法,决定通知要发送的渠道。开箱即用的通知渠道有 maildatabasebroadcastnexmoslack

如果要使用其它渠道发送,如 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 渠道生成的邮件示例:

file

当发送邮件通知时,确保在 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-notifications

Markdown 邮件通知

Markdown 邮件通知允许您利用预先构建的邮件通知模板,同时允许您更自由地编写更长的自定义信息。由于信息是用 Markdown 编写的,因此 Laravel 能够将信息渲染为漂亮的、响应式的 HTML 模板,还会自动生成纯文本副本。

生成信息

要生成通知和对应的 Markdown 模板,可以在使用 Artisan 命令 make:notification--markdown 选项:

php artisan make:notification InvoicePaid --markdown=mail.invoice.paid

与其它邮件通知一样,Markdown 邮件通知应该在通知类中定义一个 toMail 方法。但是,不使用 lineaction 方法构造通知,而是使用 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。支持的颜色有 primarysuccesserror。可以根据需要添加多个按钮组件:

@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 目录,每个目录中包含每个组件相应的内容。可以随意自定义这些组件。

自定义 CSS

导出组件后,resources/views/vendor/mail/html/themes 目录会包含一个 default.css 文件。可以自定义此文件中的 CSS,样式会自动内嵌到 Markdown 通知的 HTML 内容中。

如果要为 Markdown 组件构建一个全新的主题,可以在 html/themes 目录中编写一个新的 CSS 文件并更改 mail 配置文件中的 theme 选项。

数据库通知

前提

database 通知渠道将通知信息存储到一张数据表中。此表包含了如通知类型和自定义 JSON 数据等描述通知的信息。

可以查询此表,然后在应用的用户界面中显示通知。但是,在此之前,需要创建一张数据表来存放通知。可以使用 notifications:table 命令生成对应表结构的迁移:

php artisan notifications:table

php artisan migrate

格式化数据通知

如果通知支持存储在数据表中,则应在通知类中定义一个 toDatabasetoArray 方法。此方法接收一个 $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. toArray

toArray 方法还用在 broadcast 渠道中,决定广播到 JavaScript 客户端的数据。如果要为 databasebroadcast 渠道定义两个不同形式的数组,那么应该定义 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,
    ]);
}

广播队列配置

所有广播通知都使用队列广播。如果要配置用于广播操作的队列的队列连接或队列名称,可以使用 BroadcastMessageonConnectiononQueue 方法:

return (new BroadcastMessage($data))
                ->onConnection('sqs')
                ->onQueue('broadcasts');

除了您指定的数据外,广播通知还包含一个 type 字段,该字段包含了通知的类名。

监听通知

通知将广播到一个私有频道上,频道格式使用 {notifiable}.{id} 约定。因此,如果给 ID 为 1App\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 内容

如果短信中包含 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 通知

前提

在通过 Slack 发送通知之前,必须使用 Composer 安装 Guzzle HTTP 库:

composer require guzzlehttp/guzzle

还需要为 Slack 团队配置 Incoming Webhook 集成。此集成会在 获取 Slack 通知的 URL 时提供 URL。

格式化 Slack 通知

如果通知支持使用 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,它会创建如下消息:

file

自定义发送者 & 接收者

可以使用 fromto 方法自定义发送者和接收者。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 消息。附加信息提供了比简单的文本消息更丰富的格式化选项。在此示例中,我们将发送一个有关应用中发生的异常的错误通知,包括一个查看异常详情的链接:

/**
 * 获取 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 消息看起来像这样:

file

附加信息也支持指定一个显示给用户的数组数据。给定的数据将以表格形式显示方便阅读:

/**
 * 获取 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 消息看起来像这样:

file

Markdown 附加内容

如果一些附加内容字段包含 Markdown,可以使用 markdown 方法指示 Slack 将给定附加内容解析并显示 Markdown 格式的文本。此方法接收的值有:pretexttext 和/或 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 通知接收地址

要将 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 快速生成监听器类。

在事件监听器中,可以访问事件的 notifiablenotificationchannel 属性了解通知接收者或通知自身的更多信息:

/**
 * 处理事件
 *
 * @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)
    {
        // ...
    }
}