消息通知
消息通知
简介
除了支持 发送邮件 之外,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
方法:
use Illuminate\Support\Facades\Notification;
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
方法:
$delay = now()->addMinutes(10);
$user->notify((new InvoicePaid($invoice))->delay($delay));
您可以传递一个数组给 delay
方法,以指定特定通道的延迟时间:
$user->notify((new InvoicePaid($invoice))->delay([
'mail' => now()->addMinutes(5),
'sms' => now()->addMinutes(10),
]));
队列通知时,将为每个收件人和通道组合创建一个队列任务。例如,如果通知消息有三个收件人和两个通道,则将分派六个任务到队列中。
自定义通知队列连接
默认情况下,消息调整队列将使用应用程序的默认队列连接。如果要指定用于特定通知的其他连接,可以在通知类上自定义 $connection
属性:
/**
* 将通知使用队列时要的队列连接名称.
*
* @var string
*/
public $connection = 'redis';
自定义通知频道队列
如果你想针对通知支持的每一个频道指定应使用的特定队列,则可以在通知类中定义一个 viaQueues
方法。此方法应返回通道名称/队列名称对的数组:
/**
* Determine which queues should be used for each notification channel.
*
* @return array
*/
public function viaQueues()
{
return [
'mail' => 'mail-queue',
'slack' => 'slack-queue',
];
}
队列通知和数据库事务
在数据库事务中调度队列通知时,队列可能会在提交数据库事务提交之前对其进行处理。发生这种情况时,您在数据库事务期间对模型或数据库记录所做的任何更新可能尚未保存到数据库中。此外,在事务中创建的任何模型或数据库记录也可能不存在于数据库中。如果队列通知依赖于这些模型,则在处理发送队列通知的任务时,可能会发生意外错误。
如果队列连接的 after_commit
配置选项设置为 false
,您仍然可以通过在通知类上自定义 $afterCommit
属性来设置所有打开的数据库事务提交之后再调度特定的队列通知任务:
<?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;
public $afterCommit = true;
}
技巧:要了解有关解决这些问题的更多信息,请查看有关队列任务和数据库事务的文档.
按需通知
有时候你可能需要发送通知给某个用户,但是该用户不存在于应用的用户系统中,要实现这一目的,我们使用 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
实例。
MailMessage
类包含几个简单的方法来帮助您构建事务性电子邮件。邮件消息可以包含多行文本以及对「动作的调用」。 让我们来看一个 toMail
方法的示例:
/**
* Get the mail representation of the notification.
*
* @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]
);
}
错误消息
一些通知会告知用户错误信息,例如失败的订单支付。你可以在构建消息的时候调用 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
方法指定特定通知的发件人地址:
/**
* 获取通知邮件内容
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->from('barrett@example.com', 'Barrett Blair')
->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
方法:
/**
* 获取通知的邮件
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Notification Subject')
->line('...');
}
自定义邮件发送驱动
默认情况下,邮件通知将使用 config/mail.php
配置文件中定义的默认驱动程序发送。但是,你可以在运行时通过在生成消息时调用 mailer
方法指定一个其他的邮件发送驱动:
/**
* 获取通知的邮件
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->mailer('postmark')
->line('...');
}
自定义模板
通过发布 notifications 包的资源,可以修改邮件通知使用的HTML和纯文本模板。运行此命令后,邮件通知模板将位于 resources/views/vendor/notifications
目录中:
php artisan vendor:publish --tag=laravel-notifications
附件
若要向通知邮件添加附件,请在生成邮件时使用 attach
方法。attach
方法接受文件的绝对路径作为其第一个参数:
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file');
}
将文件附加到消息邮件时,还可以传递一个数组作为第二个参数来指定显示名称和 MIME 类型:
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
与 mailable 对象中附加文件不同,您不能使用 attachFromStorage
直接从存储磁盘附加文件。您应该使用带有存储磁盘上文件的绝对路径的 attach
方法。或者,您可以从toMail
方法返回[mailable](/cndocs/8.x/mail#generating mailables):
generating
use App\Mail\InvoicePaid as InvoicePaidMailable;
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Mailable
*/
public function toMail($notifiable)
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email)
->attachFromStorage('/path/to/file');
}
原始数据附件
attachData
方法可用于将原始字节字符串作为附件附加。调用attachData
方法时,应提供附件的文件名:
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Hello!')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
使用 Mailables 对象
如果需要,您可以从通知的 toMail
方法返回完整的mailable object。返回 Mailable
而不是 MailMessage
时,需要使用 Mailable
对象的 to
方法指定邮件收件人:
use App\Mail\InvoicePaid as InvoicePaidMailable;
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Mailable
*/
public function toMail($notifiable)
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email);
}
Mailables & 按需通知
如果您正在发送[按需通知消息](#on-demand notifications),则提供给 toMail
方法的$notifiable
实例将是 illighte\notifications\AnonymousNotifiable
的实例,该实例提供了一个 routeNotificationFor
方法,可用于检索按需通知应发送到的电子邮件地址:
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Notifications\AnonymousNotifiable;
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Mailable
*/
public function toMail($notifiable)
{
$address = $notifiable instanceof AnonymousNotifiable
? $notifiable->routeNotificationFor('mail')
: $notifiable->email;
return (new InvoicePaidMailable($this->invoice))
->to($address);
}
预览通知邮件
设计邮件通知模板时,可以像典型的 Blade 模板一样在浏览器中快速预览渲染的邮件。 因此,Laravel 允许您直接从路由闭包或控制器返回由邮件通知生成的任何邮件。 当一个 MailMessage 返回时,它将被渲染并显示在浏览器中,使您可以快速预览其设计,而无需将其发送到实际的邮箱地址:
use App\Models\Invoice;
use App\Notifications\InvoicePaid;
Route::get('/notification', function () {
$invoice = Invoice::find(1);
return (new 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
方法接受一个发送通知时要使用的主题的名称:
/**
* Get the mail representation of the notification.
*
* @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
方法的例子:
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
];
}
<code>toDatabase</code> Vs. <code>toArray</code>
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.Models.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 基于 Vonage (曾经叫 Nexmo
) 发送短信通知,在使用 Nexmo 发送通知前,需要安装 laravel/nexmo-notification-channel
和 nexmo/laravel
Composer 扩展包:
composer require laravel/nexmo-notification-channel nexmo/laravel
这也会安装 nexmo/laravel
扩展包。该扩展包包括 它自己的配置文件的配置文件。你可以使用 NEXMO_KEY
和 NEXMO_SECRET
环境变量来设置 Nexmo
公钥和私钥。
接下来,你需要在配置文件 config/services.php
中添加一个 nexmo
配置项,可以参考以下示例配置:
'nexmo' => [
'sms_from' => '15556666666',
],
sms_from
配置项就是用于发送短信消息的手机号码,你需要在 Nexmo 控制面板中为应用生成一个手机号码。
格式化短信通知
如果通知支持以短信方式发送,那么你需要在通知类上定义一个 toNexmo
方法,该方法接收一个 $notifiable
实体并返回 Illuminate\Notifications\Messages\NexmoMessage
实例:
/**
* Get the Vonage / SMS representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Your SMS message content');
}
Unicode 内容
如果 SMS 消息将包含 unicode 字符,则在构造 NexmomeMessage
实例时应调用 unicode
方法:
/**
* Get the Vonage / SMS representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Your unicode message')
->unicode();
}
格式化简码通知
Laravel 还支持发送短代码通知,这是 Vonage 帐户中预定义的消息模板。要发送短代码 SMS 通知,应在通知类上定义 toShortcode
方法。在此方法中,您可以返回一个数组,指定通知的类型(alert
, 2fa
, or marketing
)以及将填充模板的自定义值:
/**
* Get the Vonage / Shortcode representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toShortcode($notifiable)
{
return [
'type' => 'alert',
'custom' => [
'code' => 'ABC123',
];
];
}
技巧:类似于 短信通知路由, 你应该在可通知模型上实现
routeNotificationForShortcode
方法
自定义发送者 “From” 号码
如果你要通过与配置文件 config/services.php
中指定的手机号不同的其他号码发送通知,可以使用 NexmoMessage
实例上的 from
方法:
/**
* Get the Vonage / SMS representation of the notification.
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable)
{
return (new NexmoMessage)
->content('Your SMS message content')
->from('15554443333');
}
短信通知路由
要将 Vonage 通知路由到正确的电话号码,请在可通知实体上定义一个routeNotificationForNexmo
方法:
<?php
namespace App\Models;
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 \Illuminate\Notifications\Messages\SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->content('One of your invoices has been paid!');
}
自定义发送者和接收者
你可以使用 from
和 to
方法自定义发送者和接收者, from
方法接收一个用户名和 emoji 标识,而 to
方法接收通道或用户名:
/**
* Get the Slack representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\SlackMessage
*/
public function toSlack($notifiable)
{
return (new SlackMessage)
->from('Ghost', ':ghost:')
->to('#bots')
->content('This will be sent to #bots');
}
还可以使用图片作为 logo 用以取代 emoji:
/**
* Get the Slack representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\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 \Illuminate\Notifications\Messages\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 形式的通知。
*
* @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:',
]);
});
}
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\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* 为Slack通道路由通知
*
* @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
event 事件,该事件实例包含被通知的实体(如用户)和通知实例本身。你可以在 EventServiceProvider
中为该事件注册监听器:
/**
* 应用程序的事件监听器映射。
*
* @var array
*/
protected $listen = [
'Illuminate\Notifications\Events\NotificationSent' => [
'App\Listeners\LogNotification',
],
];
技巧:在
EventServiceProvider
中注册监听器之后,使用 Artisan 命令event:generate
可以快速生成监听器类。
在事件监听器中,可以访问事件的 notifiable
、 notification
和 channel
属性以了解通知接收者和通知本身的更多信息:
/**
* 处理事件。
*
* @param \Illuminate\Notifications\Events\NotificationSent $event
* @return void
*/
public function handle(NotificationSent $event)
{
// $event->channel
// $event->notifiable
// $event->notification
// $event->response
}
自定义通道
Laravel 为我们提供了许多通知通道,但是你也可以编写自己的驱动以通过其他通道来发送通知,这并不难。首先,请定义一个包含了 send
方法的类。该方法应该接收两个参数: $notifiable
和 $notification
:
在send
方法中,您可以调用通知上的方法来检索通知可以理解的消息对象,然后将通知发送到你想要的$notifiable
实例:
<?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
方法来返回类名,在本例中,通知的toVoice
方法可以返回您选择用来表示语音消息的任何对象。例如,您可以定义自己的VoiceMessage
类来表示这些消息:
<?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)
{
// ...
}
}