消息通知 ####简介 除了支持 发送邮件 之外,Laravel 还支持通过多种频道发送通知,包括邮件、短信 (通过 Vonage,原来叫 Nexmo),以及 Slack。通知还能存储到数据库以便后续在 Web 页面中显示。 通常,通知应该是简短的信息性消息,用于通知用户应用中发生的事情。例如,如果你正在编写一个账单应用,则可以通过邮件和短信频道向用户发送一个 「支付凭证」 通知。 创建通知 Laravel 中,每个通知由一个类表示 (通常存放在 app/Notifications 文件夹下)。如果在你的应用中没有看到这个目录,不要担心,当运行 make:notification 命令时它就会被创建: ``` php artisan make:notification InvoicePaid ``` 这个命令会在 app/Notifications 目录下生成一个新的通知类。每个通知类都包含一个 via 方法以及一个或多个消息构建的方法(比如 toMail 或者 toDatabase),它们会针对特定的渠道把通知转换为对应的消息。 发送通知 使用 Notifiable Trait 通知可以通过两种方法发送: Notifiable trait 的 notify 方法或 Notification facade。首先,让我们来探索下使用 trait: ``` <?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; } ``` 这个 trait 由预设的 App\Models\User 模型使用,它含有一个可以用来发送通知的方法: notify。notify 方法需要接收一个通知实例参数: ``` 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 方法,它决定了通知会在哪个频道上发送。开箱即用的频道有 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 已经默认导入,你可以快速将它们添加到通知类: ``` <?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; 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)); ``` 自定义通知频道队列 如果你想针对通知支持的每一个频道指定应使用的特定队列,则可以在通知类中定义一个 viaQueues 方法。 ``` /** * 确定哪些队列应该被通知频道使用。 * * @return array */ public function viaQueues() { return [ 'mail' => 'mail-queue', 'slack' => 'slack-queue', ]; } ``` 按需通知 有时候你可能需要发送通知给某个用户,但是该用户不存在于应用的用户系统中,要实现这一目的,我们使用 Notification::route 方法, 在发送通知之前可以指定特定的通知路由: ``` Notification::route('mail', 'taylor@example.com') ->route('nexmo', '5555555555') ->route('slack', 'https://hooks.slack.com/services/...') ->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 对象提供的这些方法让格式化短小的事务邮件变得简单快捷。mail 通道会将消息组件转化为带有纯文本副本的漂亮的响应式 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] ); } ``` 你可以通过将视图名称作为数组第二个元素传给 MailMessage 的 view 方法,以此为邮件消息指定纯文本视图: ``` /** * 获取通知的邮件内容 * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage)->view( ['emails.name.html', 'emails.name.plain'], ['invoice' => $this->invoice] ); } ``` 此外,你可以从 toMail 方法中返回一个完整的 可邮寄对象 : ``` use App\Mail\InvoicePaid as Mailable; /** * 获取通知的邮件内容 * * @param mixed $notifiable * @return Mailable */ public function toMail($notifiable) { return (new Mailable($this->invoice))->to($notifiable->email); } ``` 错误消息 一些通知会告知用户错误信息,例如失败的订单支付。你可以在构建消息的时候调用 error 方法来指明这是一个关于错误的邮件消息。在邮件消息中使用 error 方法时,操作按钮将会变成红色,而不再是黑色: ``` /** * 获取通知邮件内容 * * @param mixed $notifiable * @return \Illuminate\Notifications\Message */ public function toMail($notifiable) { return (new MailMessage) ->error() ->subject('Notification Subject') ->line('...'); } ``` 自定义发送者 默认情况下,电子邮件的发件人 / 发件人地址 定义在 config/mail.php 配置文件中。 但是,你可以使用 from 方法指定特定通知的发件人地址: ``` /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->from('test@example.com', 'Example') ->line('...'); } ``` 自定义接收者 通过 mail 通道发送通知时,通知系统会自动在被通知实体上查找 email 属性,你可以通过在该实体上定义一个 routeNotificationForMail 来自定义使用哪个邮箱地址发送通知: ``` <?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; /** * 邮件通道通知的路由。 * * @param \Illuminate\Notifications\Notification $notification * @return array|string */ public function routeNotificationForMail($notification) { // 只返回邮件地址... return $this->email_address; // 返回名字和邮件地址... return [$this->email_address => $this->name]; } } ``` 自定义主题 默认情况下,邮件的主题就是格式为 「标题风格」 的通知类名,因此,如果通知类被命名为 InvoicePaid,邮件的主题就是 Invoice Paid,如果你想要为消息指定明确的主题,可以在构建消息的时候调用 subject 方法: ``` /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->subject('Notification Subject') ->line('...'); } ``` 自定义邮件发送驱动 默认情况下,邮件通知将使用 config/mail.php 配置文件中定义的默认驱动程序发送。但是,你可以在运行时通过在生成消息时调用 mailer 方法指定一个其他的邮件发送驱动: ``` /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->mailer('postmark') ->line('...'); } ``` 自定义模板 你可以通过发布通知扩展包的资源来修改邮件通知所使用的 HTML 和纯文本模板。运行完下面这个命令之后,邮件通知模板将会存放到 resources/views/vendor/notifications 目录: ``` php artisan vendor:publish --tag=laravel-notifications ``` 邮件通知预览 设计邮件通知模板时,可以像典型的 Blade 模板一样在浏览器中快速预览渲染的邮件。 因此,Laravel 允许您直接从路由闭包或控制器返回由邮件通知生成的任何邮件。 当一个 MailMessage 返回时,它将被渲染并显示在浏览器中,使您可以快速预览其设计,而无需将其发送到实际的邮箱地址: ``` Route::get('mail', function () { $invoice = App\Invoice::find(1); return (new App\Notifications\InvoicePaid($invoice)) ->toMail($invoice->user); }); ``` Markdown 邮件通知 Markdown 邮件通知允许您使用邮件内置的通知模板,从而让您可以自由地编写更长更具有个性化的消息。如果消息以 Markdown 的形式进行书写,Laravel 还可以为其渲染出颜值很高的、响应式的 HTML 模板,同时也会为其生成一份纯文本的副本。 生成消息 您可以在 make:notification Artisan 命令中添加 --markdown 选项来生成符合 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 和可选的 颜色 。可用的颜色有 blue , green 和 red 。您可以按需添加任意数量的按钮组件到通知中: ``` @component('mail::button', ['url' => $url, 'color' => 'green']) 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 通知组件到您自己的应用中以实现自定义。要导出组件,请使用 vendor:publish Artisan 命令来发布 laravel-mail 资产标签: ``` php artisan vendor:publish --tag=laravel-mail ``` 该命令将会发布 Markdown 邮件组件到 resources/views/vendor/mail 目录中。mail 目录将包含 html 和 text 两个子目录,每个子目录又包含各自支持的所有组件。您可以按照您的喜好来随意自定义它们。 自定义 CSS 在导出组件之后, resources/views/vendor/mail/html/themes 目录将会包含一个 default.css 文件。您可以在该文件中自定义您的样式,它将会自动应用于您的 Markdown 通知的 HTML 表现上。 如果您想要构建一个全新的 Laravel Markdown 组件的主题,您可以将 CSS 文件置于 html/themes 目录中。在命名和保存了您的 CSS 文件后,请更新 mail 配置文件中的 theme 选项以匹配新主题的名称。 您可以在构建通知邮件消息时调用 theme 方法来为单独一个通知自定义样式。theme 方法接受一个发送通知时要使用的主题的名称: ``` /** * 获取通知的邮件表现。 * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->theme('invoice') ->subject('Invoice Paid') ->markdown('mail.invoice.paid', ['url' => $url]); } ``` 数据库通知 先决条件 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 和 toArray toArray 还用于 broadcast 频道来确定要向 JavaScript 客户端广播哪些数据。如果希望为 database 和 broadcast 频道使用两种不同的数组表示形式,则应定义 toDatabase 方法而不是 toArray 方法。 访问通知 一旦通知存入数据库,就需要适当的方法从通知实体访问它们。 包含在 Lareval 的默认 App\User 模型带有 Illuminate\Notifications\Notifiable trait,它的 notifications Eloquent 关联方法能返回实体通知。要获取通知,可以像其它 Eloquent 关联方法一样访问此方法。默认情况下,通知按照 created_at 时间戳排序: ``` $user = App\Models\User::find(1); foreach ($user->notifications as $notification) { echo $notification->type; } ``` 若要只获取 「未读」通知,可以使用 unreadNotifications 关联方法。同样这些通知按照 created_at 时间戳排序:: ``` $user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { echo $notification->type; } ``` 技巧:若要从 JavaScript 客户端访问通知,需要为应用定义一个通知控制器,它返回可通知实体的通知,比如当前用户。可以从 JavaScript 客户端向该控制器 URI 发送 HTTP 请求。 标记通知已读 通常,在用户阅览一条通知之后,你会想将其标识为「已读」。 Illuminate\Notifications\Notifiable trait 提供了 markAsRead 方法,它更新数据库中通知记录的 read_at 列: ``` $user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { $notification->markAsRead(); } ``` 当然,您亦可在通知集合上使用 markAsRead 方法来代替遍历通知: ``` $user->unreadNotifications->markAsRead(); ``` 您亦可通过大规模更新查询(不指定 where 条件的更新)来将所有通知标记为已读,而不必将其从数据库检索出来: ``` $user = App\Models\User::find(1); $user->unreadNotifications()->update(['read_at' => now()]); ``` 您也可以使用 delete 方法来将其从数据库实体中删除: ``` $user->notifications()->delete(); ``` 广播通知 先决条件 在广播通知前,您应该配置与精通 Laravel 的 事件广播 服务。事件广播提供了在 JavaScript 客户端响应服务端发出的 Laravel 事件的方法。 格式化广播通知 broadcast 频道广播通知使用 Laravel 的 事件广播 服务,它允许您的 JavaScript 实时捕获通知。您可以在通知类中定义一个 toBroadcast 方法来让通知支持被广播。该方法接收一个 $notifiable 实体并返回一个 BroadcastMessage 实例。如果 toBroadcast 方法不存在,toArray 方法将用来收集广播数据。返回的数据将被编码为 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 域。如果您想要自定义提供给 JavaScript 的通知的 type 域,您可以在通知类中定义一个 broadcastType 方法: ``` use Illuminate\Notifications\Messages\BroadcastMessage; /** * 获取将要广播的通知的类型。 * * @return string */ public function broadcastType() { return 'broadcast.message'; } ``` 监听通知 通知将在使用 {notifiable}.{id} 形式格式化的私有频道上进行广播。因此,如果您要发送通知到 ID 为 1 的 App\Models\User 实例上,通知将在 App.User.1 私有频道上广播。当使用 Laravel Echo 时,您可以使用 notification 辅助函数来方便的监听通知: ``` Echo.private('App.User.' + userId) .notification((notification) => { console.log(notification.type); }); ``` 自定义通知频道 如果您想要自定义被通知实体在某个通道上接收广播通知,可以在被通知实体上定义一个 receivesBroadcastNotificationsOn 方法: ``` <?php namespace App\Models; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; /** * 用户接收广播通知的通道。 * * @return string */ public function receivesBroadcastNotificationsOn() { return 'users.'.$this->id; } } ``` 短信(SMS)通知 先决条件 Laravel 基于 Nexmo 发送短信通知,在使用 Nexmo 发送通知前,需要安装 laravel/nexmo-notification-channel Composer 扩展包: composer require laravel/nexmo-notification-channel 这也会安装 nexmo/laravel 扩展包。该扩展包包括 它自己的配置文件。你可以使用 NEXMO_KEY 和 NEXMO_SECRET 环境变量来设置 Nexmo 公钥和私钥。 接下来,你需要在配置文件 config/services.php 中添加一个配置选项,可以参考以下示例配置: ``` 'nexmo' => [ 'sms_from' => '15556666666', ], ``` sms_from 配置项就是用于发送短信消息的手机号码,你需要在 Nexmo 控制面板中为应用生成一个手机号码。 格式化短信通知 如果通知支持以短信方式发送,那么你需要在通知类上定义一个 toNexmo 方法,该方法接收一个 $notifiable 实体并返回 Illuminate\Notifications\Messages\NexmoMessage 实例: ``` /** * 获取通知的 Nexmo / SMS 表示形式。 * * @param mixed $notifiable * @return NexmoMessage */ public function toNexmo($notifiable) { return (new NexmoMessage) ->content('Your SMS message content'); } ``` 格式化简码通知 Laravel 还支持发送简码通知,这是你 Nexmo 帐户中的预定义消息模板。 你可以指定通知的类型(alert, 2fa, or marketing)以及将填充模板的自定义值: ``` /** * Get the Nexmo / Shortcode representation of the notification. * * @param mixed $notifiable * @return array */ public function toShortcode($notifiable) { return [ 'type' => 'alert', 'custom' => [ 'code' => 'ABC123', ]; ]; } ``` 技巧:类似于 短信通知路由 , 你应该在可通知模型上实现 routeNotificationForShortcode 方法。 Unicode 内容 如果你的短信消息包含 Unicode 字符,需要在构造 NexmoMessage 实例时调用 unicode 方法: ``` /** * Get the Nexmo / SMS representation of the notification. * * @param mixed $notifiable * @return NexmoMessage */ public function toNexmo($notifiable) { return (new NexmoMessage) ->content('Your unicode message') ->unicode(); } ``` 自定义发送者 “From” 号码 如果你要通过与配置文件 config/services.php 中指定的手机号不同的其他号码发送通知,可以使用 NexmoMessage 实例上的 from 方法: ``` /** * Get the Nexmo / SMS representation of the notification. * * @param mixed $notifiable * @return NexmoMessage */ public function toNexmo($notifiable) { return (new NexmoMessage) ->content('Your SMS message content') ->from('15554443333'); } ``` 短信通知路由 要将 Nexmo 通知路由到正确的电话号码,请在可通知实体上定义一个 routeNotificationForNexmo 方法: ``` <?php namespace App; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; /** * Route notifications for the Nexmo channel. * * @param \Illuminate\Notifications\Notification $notification * @return string */ public function routeNotificationForNexmo($notification) { return $this->phone_number; } } ``` Slack 通知 先决条件 在通过 Slack 发送通知前,必须通过 Composer 安装 Slack 通知通道: ``` composer require laravel/slack-notification-channel ``` 你还需要为 Slack 组配置一个 “Incoming Webhook” 集成。该集成会提供一个 URL,可以在 路由 Slack 通知 时使用。 格式化 Slack 通知 如果通知支持通过 Slack 消息发送,则需要在通知类上定义一个 toSlack 方法,该方法接收一个 $notifiable 实体并返回 Illuminate\Notifications\Messages\SlackMessage 实例,Slack 消息可以包含文本内容以及格式化附加文本或数组字段的 “附件”。让我们来看一个基本的 toSlack 使用示例: ``` /** * Get the Slack representation of the notification. * * @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 方法接收通道或用户名: ``` /** * Get the Slack representation of the notification. * * @param mixed $notifiable * @return SlackMessage */ public function toSlack($notifiable) { return (new SlackMessage) ->from('Ghost', ':ghost:') ->to('#other') ->content('This will be sent to #other'); } ``` 还可以使用图片作为 logo 用以取代 emoji: ``` /** * Get the Slack representation of the notification. * * @param mixed $notifiable * @return SlackMessage */ public function toSlack($notifiable) { return (new SlackMessage) ->from('Laravel') ->image('https://laravel.com/img/favicon/favicon.ico') ->content('This will display the Laravel logo next to the message'); } ``` Slack 附件 你还可以添加 “附件” 到 Slack 消息。相对简单文本消息,附件可以提供更加丰富的格式选项。在这个例子中,我们会发送一个在应用程序中出现的异常错误通知,包含查看更多异常细节的链接: ``` /** * Get the Slack representation of the notification. * * @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,可以使用 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 通知路由 要路由 Slack 通知到适当的位置,需要在可通知的实体上定义一个 routeNotificationForSlack 方法,这将会返回通知被发送到的 Webhook URL。Webhook URL 可通过在 Slack 组上添加一个 “Incoming Webhook” 服务来生成: ``` <?php namespace App; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; /** * Route notifications for the Slack channel. * * @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')); ``` 多个可通知实体的本地化也可通过 Notification Facade 实现: ``` Notification::locale('es')->send($users, new InvoicePaid($invoice)); ``` 用户首选语言区域设置 有些情况下,应用程序存储每个用户的首选语言区域设置。通过在可通知模型上实现 HasLocalePreference 契约,可以指示 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 事件,该事件实例包含被通知的实体(如用户)和通知实例本身。你可以在 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 // $event->response } ``` 自定义通道 Laravel 为我们提供了许多通知频道,但是您亦可编写自己驱动以通过其他频道来发送通知,这并不难。首先,请定义一个包含了 send 方法的类。该方法应该接收两个参数: $notifiable 和 $notification: ``` <?php 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 方法来返回类名: ``` <?php namespace App\Notifications; use App\Channels\Messages\VoiceMessage; use App\Channels\VoiceChannel; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Notification; 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) { // ... } } ```