消息通知
介绍
除了支持 发送电子邮件 之外,Laravel还提供了支持通过多种传递渠道发送通知的功能,包括电子邮件、短信(通过 Vonage,前身为Nexmo)和 Slack。此外,已经创建了多种 社区构建的通知渠道,用于通过数十个不同的渠道发送通知!通知也可以存储在数据库中,以便在你的Web界面中显示。
通常,通知应该是简短的信息性消息,用于通知用户应用中发生的事情。例如,如果你正在编写一个账单应用,则可以通过邮件和短信频道向用户发送一个「支付凭证」通知。
创建通知
Laravel 中,通常每个通知都由一个存储在 app/Notifications
目录下的 一个类表示。如果在你的应用中没有看到这个目录,不要担心,当运行 make:notification
命令时它将为你创建:
php artisan make:notification InvoicePaid
这个命令会在 app/Notifications
目录下生成一个新的通知类。每个通知类都包含一个 via
方法以及一个或多个消息构建的方法比如 toMail
或 toDatabase
,它们会针对特定的渠道把通知转换为对应的消息。
发送通知
使用 Notifiable Trait
通知可以通过两种方式发送: 使用 Notifiable
特性的 notify
方法或使用 Notification
facade。 该 Notifiable
特性默认包含在应用程序的 App\Models\User
模型中:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
}
此 notify
方法需要接收一个通知实例参数:
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));
请记住,你可以在任何模型中使用 Notifiable
trait。而不仅仅是在 User
模型中。
使用 Notification Facade
另外,你可以通过 Notification
facade 来发送通知。它主要用在当你需要给多个可接收通知的实体发送的时候,比如给用户集合发送通知。使用 Facade 发送通知的话,要把可接收通知实例和通知实例传递给 send
方法:
use Illuminate\Support\Facades\Notification;
Notification::send($users, new InvoicePaid($invoice));
你也可以使用 sendNow
方法立即发送通知。即使通知实现了 ShouldQueue
接口,该方法也会立即发送通知:
Notification::sendNow($developers, new DeploymentCompleted($deployment));
发送指定频道
每个通知类都有一个 via
方法,用于确定将在哪些通道上传递通知。通知可以在 mail
、database
、broadcast
、vonage
和 slack
频道上发送。
如果你想使用其他的频道,比如 Telegram 或者 Pusher,你可以去看下社区驱动的 Laravel 通知频道网站.
via
方法接收一个 $notifiable
实例,这个实例将是通知实际发送到的类的实例。你可以用 $notifiable
来决定这个通知用哪些频道来发送:
/**
* 获取通知发送频道。
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return $notifiable->prefers_sms ? ['vonage'] : ['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),
]));
或者,你可以在通知类本身上定义一个 withDelay
方法。 withDelay
方法会返回包含通道名称和延迟值的数组:
/**
* 确定通知的传递延迟.
*
* @return array<string, \Illuminate\Support\Carbon>
*/
public function withDelay(object $notifiable): array
{
return [
'mail' => now()->addMinutes(5),
'sms' => now()->addMinutes(10),
];
}
自定义消息通知队列连接
默认情况下,排队的消息通知将使用应用程序的默认队列连接进行排队。如果你想指定一个不同的连接用于特定的通知,你可以在通知类上定义一个 $connection
属性:
/**
* 排队通知时要使用的队列连接的名称.
*
* @var string
*/
public $connection = 'redis';
或者,如果你想为每个通知通道都指定一个特定的队列连接,你可以在你的通知上定义一个 viaConnections
方法。这个方法应该返回一个通道名称 / 队列连接名称的数组。
/**
* 定义每个通知通道应该使用哪个连接。
*
* @return array<string, string>
*/
public function viaConnections(): array
{
return [
'mail' => 'redis',
'database' => 'sync',
];
}
自定义通知通道队列
如果你想为每个通知通道指定一个特定的队列,你可以在你的通知上定义一个 viaQueues
。 此方法应返回通道名称 / 队列名称对的数组:
/**
* 定义每个通知通道应使用哪条队列。
*
* @return array<string, string>
*/
public function viaQueues(): array
{
return [
'mail' => 'mail-queue',
'slack' => 'slack-queue',
];
}
队列通知 & 数据库事务
当队列通知在数 据库事务中被分发时,它们可能在数据库事务提交之前被队列处理。发生这种情况时,你在数据库事务期间对模型或数据库记录所做的任何更新可能尚未反映在数据库中。甚至,在事务中创建的任何模型或数据库记录可能不存在于数据库中。如果你的通知依赖于这些模型,那么在处理发送队列通知时可能会发生意外错误。
如果你的队列连接的 after_commit
配置选项设置为 false
,你仍然可以通过在发送通知时调用 afterCommit
方法来指示应在提交所有打开的数据库事务后发送特定的排队通知:
use App\Notifications\InvoicePaid;
$user->notify((new InvoicePaid($invoice))->afterCommit());
或者,你可以从通知的构造函数调用 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 function __construct()
{
$this->afterCommit();
}
}
要了解更多解决这些问题的方法,请查阅有关队列作业和 数据库事务 的文档。