介绍

除了支持 发送电子邮件 之外,Laravel还提供了支持通过多种传递渠道发送通知的功能,包括电子邮件、短信(通过 Vonage,前身为Nexmo)和 Slack。此外,已经创建了多种 社区构建的通知渠道,用于通过数十个不同的渠道发送通知!通知也可以存储在数据库中,以便在你的Web界面中显示。

通常,通知应该是简短的信息性消息,用于通知用户应用中发生的事情。例如,如果你正在编写一个账单应用,则可以通过邮件和短信频道向用户发送一个「支付凭证」通知。

创建通知

Laravel 中,通常每个通知都由一个存储在 php app/Notifications 目录下的一个类表示。如果在你的应用中没有看到这个目录,不要担心,当运行 php make:notification 命令时它将为你创建:

  1. php artisan make:notification InvoicePaid

这个命令会在 php app/Notifications 目录下生成一个新的通知类。每个通知类都包含一个 php via 方法以及一个或多个消息构建的方法比如 php toMailphp toDatabase,它们会针对特定的渠道把通知转换为对应的消息。

发送通知

使用 Notifiable Trait

通知可以通过两种方式发送: 使用 php Notifiable 特性的 php notify 方法或使用 php Notification facade。 该 php Notifiable 特性默认包含在应用程序的 php App\Models\User 模型中:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Foundation\Auth\User as Authenticatable;
  4. use Illuminate\Notifications\Notifiable;
  5. class User extends Authenticatable
  6. {
  7. use Notifiable;
  8. }

php notify 方法需要接收一个通知实例参数:

  1. use App\Notifications\InvoicePaid;
  2. $user->notify(new InvoicePaid($invoice));

技巧
请记住,你可以在任何模型中使用 php Notifiable trait。而不仅仅是在 php User 模型中。

使用 Notification Facade

另外,你可以通过 php Notification facade 来发送通知。它主要用在当你需要给多个可接收通知的实体发送的时候,比如给用户集合发送通知。使用 Facade 发送通知的话,要把可接收通知实例和通知实例传递给 php send 方法:

  1. use Illuminate\Support\Facades\Notification;
  2. Notification::send($users, new InvoicePaid($invoice));

你也可以使用 php sendNow 方法立即发送通知。即使通知实现了 php ShouldQueue 接口,该方法也会立即发送通知:

  1. Notification::sendNow($developers, new DeploymentCompleted($deployment));

发送指定频道

每个通知类都有一个 php via 方法,用于确定将在哪些通道上传递通知。通知可以在 php mailphp databasephp broadcastphp vonagephp slack 频道上发送。

提示
如果你想使用其他的频道,比如 Telegram 或者 Pusher,你可以去看下社区驱动的 Laravel 通知频道网站.

php via 方法接收一个 php $notifiable 实例,这个实例将是通知实际发送到的类的实例。你可以用 php $notifiable 来决定这个通知用哪些频道来发送:

  1. /**
  2. * 获取通知发送频道。
  3. *
  4. * @return array<int, string>
  5. */
  6. public function via(object $notifiable): array
  7. {
  8. return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];
  9. }

通知队列化

注意
使用通知队列前需要配置队列并 开启一个队列任务。

发送通知可能是耗时的,尤其是通道需要调用额外的 API 来传输通知。为了加速应用的响应时间,可以将通知推送到队列中异步发送,而要实现推送通知到队列,可以让对应通知类实现 php ShouldQueue 接口并使用 php Queueable trait。如果通知类是通过 make:notification 命令生成的,那么该接口和 trait 已经默认导入,你可以快速将它们添加到通知类:

  1. <?php
  2. namespace App\Notifications;
  3. use Illuminate\Bus\Queueable;
  4. use Illuminate\Contracts\Queue\ShouldQueue;
  5. use Illuminate\Notifications\Notification;
  6. class InvoicePaid extends Notification implements ShouldQueue
  7. {
  8. use Queueable;
  9. // ...
  10. }

一旦将 php ShouldQueue 接口添加到你的通知中,你就可以发送通知。 Laravel 将检测类上的 php ShouldQueue 接口并自动排队发送通知:

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

排队通知时,将为每个收件人和频道组合创建一个排队的作业。比如,如果你的通知有三个收件人和两个频道,则六个作业将被分配到队列中。

延迟通知
如果你需要延迟发送消息通知, 你可以在你的消息通知实例上添加 php delay 方法:

  1. $delay = now()->addMinutes(10);
  2. $user->notify((new InvoicePaid($invoice))->delay($delay));

多个通道的延迟通知
将一个数组传递给 php delay 方法来指定特定通道的延迟时间:

  1. $user->notify((new InvoicePaid($invoice))->delay([
  2. 'mail' => now()->addMinutes(5),
  3. 'sms' => now()->addMinutes(10),
  4. ]));

或者,你可以在通知类本身上定义一个 php withDelay 方法。 php withDelay 方法会返回包含通道名称和延迟值的数组:

  1. /**
  2. * 确定通知的传递延迟.
  3. *
  4. * @return array<string, \Illuminate\Support\Carbon>
  5. */
  6. public function withDelay(object $notifiable): array
  7. {
  8. return [
  9. 'mail' => now()->addMinutes(5),
  10. 'sms' => now()->addMinutes(10),
  11. ];
  12. }

自定义消息通知队列连接
默认情况下,排队的消息通知将使用应用程序的默认队列连接进行排队。如果你想指定一个不同的连接用于特定的通知,你可以在通知类上定义一个 php $connection 属性:

  1. /**
  2. * 排队通知时要使用的队列连接的名称.
  3. *
  4. * @var string
  5. */
  6. public $connection = 'redis';

或者,如果你想为每个通知通道都指定一个特定的队列连接,你可以在你的通知上定义一个 php viaConnections 方法。这个方法应该返回一个通道名称 / 队列连接名称的数组。

  1. /**
  2. * 定义每个通知通道应该使用哪个连接。
  3. *
  4. * @return array<string, string>
  5. */
  6. public function viaConnections(): array
  7. {
  8. return [
  9. 'mail' => 'redis',
  10. 'database' => 'sync',
  11. ];
  12. }

自定义通知通道队列
如果你想为每个通知通道指定一个特定的队列,你可以在你的通知上定义一个 php viaQueues 。 此方法应返回通道名称 / 队列名称对的数组:

  1. /**
  2. * 定义每个通知通道应使用哪条队列。
  3. *
  4. * @return array<string, string>
  5. */
  6. public function viaQueues(): array
  7. {
  8. return [
  9. 'mail' => 'mail-queue',
  10. 'slack' => 'slack-queue',
  11. ];
  12. }

队列通知 & 数据库事务
当队列通知在数据库事务中被分发时,它们可能在数据库事务提交之前被队列处理。发生这种情况时,你在数据库事务期间对模型或数据库记录所做的任何更新可能尚未反映在数据库中。甚至,在事务中创建的任何模型或数据库记录可能不存在于数据库中。如果你的通知依赖于这些模型,那么在处理发送队列通知时可能会发生意外错误。

如果你的队列连接的 php after_commit 配置选项设置为 php false,你仍然可以通过在发送通知时调用 php afterCommit 方法来指示应在提交所有打开的数据库事务后发送特定的排队通知:

  1. use App\Notifications\InvoicePaid;
  2. $user->notify((new InvoicePaid($invoice))->afterCommit());

或者,你可以从通知的构造函数调用 php afterCommit 方法:

  1. <?php
  2. namespace App\Notifications;
  3. use Illuminate\Bus\Queueable;
  4. use Illuminate\Contracts\Queue\ShouldQueue;
  5. use Illuminate\Notifications\Notification;
  6. class InvoicePaid extends Notification implements ShouldQueue
  7. {
  8. use Queueable;
  9. /**
  10. * 创建一个新的通知通知实例。
  11. */
  12. public function __construct()
  13. {
  14. $this->afterCommit();
  15. }
  16. }

注意
要了解更多解决这些问题的方法,请查阅有关队列作业和 数据库事务 的文档。

确定是否发送排队的通知
在将排队的通知分派到后台处理的队列之后,它通常会被队列工作进程接受并发送给其目标收件人。

然而,如果你想要在队列工作进程处理后最终确定是否发送排队的通知,你可以在通知类上定义一个 php shouldSend 方法。如果此方法返回 php false,则通知不会被发送:

  1. /**
  2. * 定义通知是否应该被发送。
  3. */
  4. public function shouldSend(object $notifiable, string $channel): bool
  5. {
  6. return $this->invoice->isPaid();
  7. }

按需通知

有时你需要向一些不属于你应用程序的「用户」发送通知。使用 php Notification 门面的 php route 方法,你可以在发送通知之前指定即时的通知路由信息:

  1. use Illuminate\Broadcasting\Channel;
  2. use Illuminate\Support\Facades\Notification;
  3. Notification::route('mail', 'taylor@example.com')
  4. ->route('vonage', '5555555555')
  5. ->route('slack', 'https://hooks.slack.com/services/...')
  6. ->route('broadcast', [new Channel('channel-name')])
  7. ->notify(new InvoicePaid($invoice));

如果你想在向 php mail 路由发送通知时指定收件人,你可以提供一个数组
电子邮件地址作为键,名字作为值。

  1. Notification::route('mail', [
  2. 'barrett@example.com' => 'Barrett Blair',
  3. ])->notify(new InvoicePaid($invoice));

邮件通知

格式化邮件

如果一个通知支持以电子邮件的形式发送,你应该在通知类中定义一个 php toMail 方法。这个方法将接收一个 php $notifiable 实体,并应该返回一个php Illuminate\Notifications\Messages\MailMessage 实例。

php MailMessage 类包含一些简单的方法来帮助你建立事务性的电子邮件信息。邮件信息可能包含几行文字以及一个「操作」。让我们来看看一个 php toMail 方法的例子。

  1. /**
  2. * 获取通知的邮件表示形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. $url = url('/invoice/'.$this->invoice->id);
  7. return (new MailMessage)
  8. ->greeting('你好!')
  9. ->line('你的一张发票已经付款了!')
  10. ->lineIf($this->amount > 0, "支出金额: {$this->amount}")
  11. ->action('查看发票', $url)
  12. ->line('感谢你使用我们的应用程序!');
  13. }

注意
注意我们在 php toMail 方法中使用 php $this->invoice->id。你可以在通知的构造函数中传递任何你的通知需要生成的信息数据。

在这个例子中,我们注册了一个问候语、一行文字、一个操作,然后是另一行文字。php MailMessage 对象所提供的这些方法使得邮件的格式化变得简单而快速。然后,邮件通道将把信息组件转换封装成一个漂亮的、响应式的HTML电子邮件模板,并有一个纯文本对应。
下面是一个由 php mail 通道生成的电子邮件的例子。

注意
当发送邮件通知时,请确保在你的 php config/app.php 配置文件中设置 php name 配置选项。
这个值将在你的邮件通知信息的标题和页脚中使用。

错误消息
一些通知会通知用户错误,比如支付失败的发票。你可以通过在构建消息时调用 php error 方法来指示邮件消息是关于错误的。当在邮件消息上使用 php error 方法时,操作按钮将会是红色而不是黑色:

  1. /**
  2. * 获取通知的邮件表示形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->error()
  8. ->subject('发票支付失败')
  9. ->line('...');
  10. }

其他邮件通知格式选项
你可以使用 php view 方法来指定应用于呈现通知电子邮件的自定义模板,而不是在通知类中定义文本「行」:

  1. /**
  2. * 获取通知的邮件表现形式
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)->view(
  7. 'emails.name', ['invoice' => $this->invoice]
  8. );
  9. }

你可以通过将视图名称作为数组的第二个元素传递给 php view 方法来指定邮件消息的纯文本视图:

  1. /**
  2. * 获取通知的邮件表现形式
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)->view(
  7. ['emails.name.html', 'emails.name.plain'],
  8. ['invoice' => $this->invoice]
  9. );
  10. }

自定义发件人

默认情况下,电子邮件的发件人/寄件人地址在 php config/mail.php 配置文件中定义。但是,你可以使用 php from 方法为特定的通知指定发件人地址:

  1. /**
  2. * 获取通知的邮件表现形式
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->from('barrett@example.com', 'Barrett Blair')
  8. ->line('...');
  9. }

自定义收件人

当通过 php mail 通道发送通知时,通知系统将自动查找可通知实体的 php email 属性。你可以通过在可通知实体上定义 php routeNotificationForMail 方法来自定义用于传递通知的电子邮件地址:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Foundation\Auth\User as Authenticatable;
  4. use Illuminate\Notifications\Notifiable;
  5. use Illuminate\Notifications\Notification;
  6. class User extends Authenticatable
  7. {
  8. use Notifiable;
  9. /**
  10. * 路由邮件通道的通知。
  11. *
  12. * @return array<string, string>|string
  13. */
  14. public function routeNotificationForMail(Notification $notification): array|string
  15. {
  16. // 只返回电子邮件地址...
  17. return $this->email_address;
  18. // 返回电子邮件地址和姓名...
  19. return [$this->email_address => $this->name];
  20. }
  21. }

自定义主题

默认情况下,邮件的主题是通知类的类名格式化为「标题案例」(Title Case)。因此,如果你的通知类命名为 php InvoicePaid,则邮件的主题将是 php Invoice Paid。如果你想为消息指定不同的主题,可以在构建消息时调用 php subject 方法:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->subject('通知标题')
  8. ->line('...');
  9. }

自定义邮件程序

默认情况下,邮件通知将使用 php config/mail.php 配置文件中定义的默认邮件程序进行发送。但是,你可以在运行时通过在构建消息时调用 php mailer 方法来指定不同的邮件程序:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->mailer('postmark')
  8. ->line('...');
  9. }

自定义模板

你可以通过发布通知包的资源来修改邮件通知使用的 HTML 和纯文本模板。运行此命令后,邮件通知模板将位于 php resources/views/vendor/notifications 目录中:

  1. php artisan vendor:publish --tag=laravel-notifications

附件

要在电子邮件通知中添加附件,可以在构建消息时使用 php attach 方法。php attach 方法接受文件的绝对路径作为其第一个参数:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->greeting('你好!')
  8. ->attach('/path/to/file');
  9. }

注意
通知邮件消息提供的 php attach 方法还接受 可附加对象。请查阅全面的 可附加对象 文档以了解更多信息。

当附加文件到消息时,你还可以通过将 php array 作为 php attach 方法的第二个参数来指定显示名称和/或 MIME 类型:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->greeting('你好!')
  8. ->attach('/path/to/file', [
  9. 'as' => 'name.pdf',
  10. 'mime' => 'application/pdf',
  11. ]);
  12. }

与在可邮寄对象中附加文件不同,你不能使用 php attachFromStorage 直接从存储磁盘附加文件。相反,你应该使用 php attach 方法,并提供存储磁盘上文件的绝对路径。或者,你可以从 php toMail 方法中返回一个 可邮寄对象:

  1. use App\Mail\InvoicePaid as InvoicePaidMailable;
  2. /**
  3. * 获取通知的邮件表现形式。
  4. */
  5. public function toMail(object $notifiable): Mailable
  6. {
  7. return (new InvoicePaidMailable($this->invoice))
  8. ->to($notifiable->email)
  9. ->attachFromStorage('/path/to/file');
  10. }

必要时,可以使用 php attachMany 方法将多个文件附加到消息中:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->greeting('你好!')
  8. ->attachMany([
  9. '/path/to/forge.svg',
  10. '/path/to/vapor.svg' => [
  11. 'as' => 'Logo.svg',
  12. 'mime' => 'image/svg+xml',
  13. ],
  14. ]);
  15. }

原始数据附件
php attachData 方法可以用于将原始字节数组附加为附件。在调用 php attachData 方法时,应提供应分配给附件的文件名:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->greeting('你好!')
  8. ->attachData($this->pdf, 'name.pdf', [
  9. 'mime' => 'application/pdf',
  10. ]);
  11. }

添加标签和元数据

一些第三方电子邮件提供商(如 Mailgun 和 Postmark)支持消息「标签」和「元数据」,可用于分组和跟踪应用程序发送的电子邮件。可以通过 php tagphp metadata 方法将标签和元数据添加到电子邮件消息中:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->greeting('评论点赞!')
  8. ->tag('点赞')
  9. ->metadata('comment_id', $this->comment->id);
  10. }

如果你的应用程序使用 Mailgun 驱动程序,则可以查阅 Mailgun 的文档以获取有关 标签元数据 的更多信息。同样,也可以参考 Postmark 文档了解他们对 标签元数据 的支持。

如果你的应用程序使用 Amazon SES 发送电子邮件,则应使用 php metadata 方法将 SES 「标签」附加到消息。

自定义 Symfony 消息

php MailMessage类的php withSymfonyMessage方法允许你注册一个闭包,在发送消息之前将调用Symfony Message实例。这给你在传递消息之前有深度自定义消息的机会:

  1. use Symfony\Component\Mime\Email;
  2. /**
  3. * 获取通知的邮件表示形式。
  4. */
  5. public function toMail(object $notifiable): MailMessage
  6. {
  7. return (new MailMessage)
  8. ->withSymfonyMessage(function (Email $message) {
  9. $message->getHeaders()->addTextHeader(
  10. 'Custom-Header', 'Header Value'
  11. );
  12. });
  13. }

使用可邮寄对象

如果需要,你可以从通知的 php toMail 方法返回完整的 mailable 对象。当返回 php Mailable 而不是 php MailMessage 时,你需要使用可邮寄对象的 php to 方法指定消息接收者:

  1. use App\Mail\InvoicePaid as InvoicePaidMailable;
  2. use Illuminate\Mail\Mailable;
  3. /**
  4. * 获取通知的邮件表现形式。
  5. */
  6. public function toMail(object $notifiable): Mailable
  7. {
  8. return (new InvoicePaidMailable($this->invoice))
  9. ->to($notifiable->email);
  10. }

可邮寄对象和按需通知
如果你正在发送按需通知,则提供给php toMail方法的php $notifiable实例将是php Illuminate\Notifications\AnonymousNotifiable的一个实例,它提供了一个php routeNotificationFor方法,该方法可用于检索应将按需通知发送到的电子邮件地址:

  1. use App\Mail\InvoicePaid as InvoicePaidMailable;
  2. use Illuminate\Notifications\AnonymousNotifiable;
  3. use Illuminate\Mail\Mailable;
  4. /**
  5. * 获取通知的邮件表现形式。
  6. */
  7. public function toMail(object $notifiable): Mailable
  8. {
  9. $address = $notifiable instanceof AnonymousNotifiable
  10. ? $notifiable->routeNotificationFor('mail')
  11. : $notifiable->email;
  12. return (new InvoicePaidMailable($this->invoice))
  13. ->to($address);
  14. }

预览邮件通知

设计邮件通知模板时,可以像典型的 Blade 模板一样在浏览器中快速预览呈现的邮件消息。出于这个原因,Laravel 允许你直接从路由闭包或控制器返回由邮件通知生成的任何邮件消息。当返回一个 php MailMessage 时,它将在浏览器中呈现和显示,让你可以快速预览其设计,无需将其发送到实际的电子邮件地址:

  1. use App\Models\Invoice;
  2. use App\Notifications\InvoicePaid;
  3. Route::get('/notification', function () {
  4. $invoice = Invoice::find(1);
  5. return (new InvoicePaid($invoice))
  6. ->toMail($invoice->user);
  7. });

Markdown 邮件通知

Markdown 邮件通知允许你利用邮件通知的预构建模板,同时为你提供编写更长、定制化消息的自由。由于这些消息是用 Markdown 写的,因此 Laravel 能够为消息呈现漂亮、响应式的 HTML 模板,同时还会自动生成一个纯文本的副本。

生成消息

要生成具有相应 Markdown 模板的通知,可以使用 php make:notification Artisan 命令的 php --markdown 选项:

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

与所有其他邮件通知一样,使用 Markdown 模板的通知应该在其通知类上定义一个 php toMail 方法。但是,不要使用 php linephp action 方法构建通知,而是使用 php markdown 方法指定应该使用的 Markdown 模板的名称。你希望提供给模板的数据数组可以作为该方法的第二个参数传递:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. $url = url('/invoice/'.$this->invoice->id);
  7. return (new MailMessage)
  8. ->subject('发票支付')
  9. ->markdown('mail.invoice.paid', ['url' => $url]);
  10. }

编写消息

Markdown 邮件通知使用 Blade 组件和 Markdown 语法的组合,可以让你在利用 Laravel 的预构建通知组件的同时,轻松构建通知:

  1. <x-mail::message>
  2. # 发票支付
  3. 你的发票已支付!
  4. <x-mail::button :url="$url">
  5. 查看发票
  6. </x-mail::button>
  7. 谢谢,<br>
  8. {{ config('app.name') }}
  9. </x-mail::message>

Button 组件
Button 组件会呈现一个居中的按钮链接。该组件接受两个参数,php url 和一个可选的 php color。支持的颜色有 php primaryphp greenphp red。你可以在通知中添加任意数量的 Button 组件:

  1. <x-mail::button :url="$url" color="green">
  2. 查看发票
  3. </x-mail::button>

Panel 组件
Panel 组件会在通知中呈现给定的文本块,并在面板中以稍微不同的背景颜色呈现。这让你可以引起读者对特定文本块的注意:

  1. <x-mail::panel>
  2. 这是面板内容。
  3. </x-mail::panel>

Table 组件
Table 组件允许你将 Markdown 表格转换为 HTML 表格。该组件接受 Markdown 表格作为其内容。可以使用默认的 Markdown 表格对齐语法来支持表格列对齐:

  1. <x-mail::table>
  2. | Laravel | Table | Example |
  3. | ------------- |:-------------:| --------:|
  4. | Col 2 is | Centered | $10 |
  5. | Col 3 is | Right-Aligned | $20 |
  6. </x-mail::table>

定制组件

你可以将所有的 Markdown 通知组件导出到自己的应用程序进行定制。要导出组件,请使用 php vendor:publish Artisan 命令来发布 php laravel-mail 资源标记:

这个命令会将 Markdown 邮件组件发布到 php resources/views/vendor/mail 目录下。php mail 目录将包含一个 php html 和一个 php text 目录,每个目录都包含其可用组件的各自表示形式。你可以自由地按照自己的喜好定制这些组件。

定制 CSS 样式
在导出组件之后,php resources/views/vendor/mail/html/themes 目录将包含一个 php default.css 文件。你可以在此文件中自定义 CSS 样式,你的样式将自动被内联到 Markdown 通知的 HTML 表示中。

如果你想为 Laravel 的 Markdown 组件构建一个全新的主题,可以在 php html/themes 目录中放置一个 CSS 文件。命名并保存 CSS 文件后,更新 php mail 配置文件的 php theme 选项以匹配你的新主题的名称。

要为单个通知自定义主题,可以在构建通知的邮件消息时调用 php theme 方法。php theme 方法接受应该在发送通知时使用的主题名称:

  1. /**
  2. * 获取通知的邮件表现形式。
  3. */
  4. public function toMail(object $notifiable): MailMessage
  5. {
  6. return (new MailMessage)
  7. ->theme('发票')
  8. ->subject('发票支付')
  9. ->markdown('mail.invoice.paid', ['url' => $url]);
  10. }

数据库通知

前提条件

php database 通知渠道将通知信息存储在一个数据库表中。该表将包含通知类型以及描述通知的 JSON 数据结构等信息。

你可以查询该表,在你的应用程序用户界面中显示通知。但是,在此之前,你需要创建一个数据库表来保存你的通知。你可以使用 php notifications:table 命令生成一个适当的表模式的 迁移:

  1. php artisan notifications:table
  2. php artisan migrate

格式化数据库通知

如果一个通知支持被存储在一个数据库表中,你应该在通知类上定义一个 php toDatabasephp toArray 方法。这个方法将接收一个 php $notifiable 实体,并应该返回一个普通的 PHP 数组。返回的数组将被编码为 JSON,并存储在你的 php notifications 表的 php data 列中。让我们看一个 php toArray 方法的例子:

  1. /**
  2. * 获取通知的数组表示形式。
  3. *
  4. * @return array<string, mixed>
  5. */
  6. public function toArray(object $notifiable): array
  7. {
  8. return [
  9. 'invoice_id' => $this->invoice->id,
  10. 'amount' => $this->invoice->amount,
  11. ];
  12. }

toDatabase Vs. toArray
php toArray 方法也被 php broadcast 频道用来确定要广播到你的 JavaScript 前端的数据。如果你想为 php databasephp broadcast 频道定义两个不同的数组表示形式,你应该定义一个 php toDatabase 方法,而不是一个 php toArray 方法。

访问通知

一旦通知被存储在数据库中,你需要一个方便的方式从你的可通知实体中访问它们。php Illuminate\Notifications\Notifiable trait 包含在 Laravel 的默认 php App\Models\User 模型中,它包括一个 php notifications Eloquent 关联,返回实体的通知。要获取通知,你可以像访问任何其他 Eloquent 关系一样访问此方法。默认情况下,通知将按照 php created_at 时间戳排序,最新的通知位于集合的开头:

  1. $user = App\Models\User::find(1);
  2. foreach ($user->notifications as $notification) {
  3. echo $notification->type;
  4. }

如果你想要只检索「未读」的通知,你可以使用 php unreadNotifications 关系。同样,这些通知将按照 php created_at 时间戳排序,最新的通知位于集合的开头:

  1. $user = App\Models\User::find(1);
  2. foreach ($user->unreadNotifications as $notification) {
  3. echo $notification->type;
  4. }

注意
要从你的 JavaScript 客户端访问你的通知,你应该为你的应用程序定义一个通知控制器,该控制器返回一个可通知实体的通知,如当前用户。然后,你可以从你的 JavaScript 客户端向该控制器的 URL 发送 HTTP 请求。

将通知标记为已读

通常,当用户查看通知时,你希望将通知标记为「已读」。php Illuminate\Notifications\Notifiable trait 提供了一个 php markAsRead 方法,该方法将更新通知的数据库记录上的 php read_at 列:

  1. $user = App\Models\User::find(1);
  2. foreach ($user->unreadNotifications as $notification) {
  3. $notification->markAsRead();
  4. }

然而,你可以直接在通知集合上使用 php markAsRead 方法,而不是遍历每个通知:

  1. $user->unreadNotifications->markAsRead();

你也可以使用批量更新查询将所有通知标记为已读而不必从数据库中检索它们:

  1. $user = App\Models\User::find(1);
  2. $user->unreadNotifications()->update(['read_at' => now()]);

你可以使用 php delete 方法将通知删除并从表中完全移除:

  1. $user->notifications()->delete();

广播通知

前提条件

在广播通知之前,你应该配置并熟悉 Laravel 的 事件广播 服务。事件广播提供了一种从你的 JavaScript 前端响应服务器端 Laravel 事件的方法。

格式化广播通知

php broadcast 频道使用 Laravel 的 事件广播 服务来广播通知,允许你的 JavaScript 前端实时捕获通知。如果通知支持广播,你可以在通知类上定义一个 php toBroadcast 方法。该方法将接收一个 php $notifiable 实体,并应该返回一个 php BroadcastMessage 实例。如果 php toBroadcast 方法不存在,则将使用 php toArray 方法来收集应该广播的数据。返回的数据将被编码为 JSON 并广播到你的 JavaScript 前端。让我们看一个 php toBroadcast 方法的示例:

  1. use Illuminate\Notifications\Messages\BroadcastMessage;
  2. /**
  3. * 获取通知的可广播表示形式。
  4. */
  5. public function toBroadcast(object $notifiable): BroadcastMessage
  6. {
  7. return new BroadcastMessage([
  8. 'invoice_id' => $this->invoice->id,
  9. 'amount' => $this->invoice->amount,
  10. ]);
  11. }

广播队列配置
所有广播通知都会被排队等待广播。如果你想配置用于排队广播操作的队列连接或队列名称,你可以使用 php BroadcastMessagephp onConnectionphp onQueue 方法:

  1. return (new BroadcastMessage($data))
  2. ->onConnection('sqs')
  3. ->onQueue('broadcasts');

自定义通知类型
除了你指定的数据之外,所有广播通知还包含一个 php type 字段,其中包含通知的完整类名。如果你想要自定义通知的 php type,可以在通知类上定义一个 php broadcastType 方法:

  1. /**
  2. * 获取正在广播的通知类型。
  3. */
  4. public function broadcastType(): string
  5. {
  6. return 'broadcast.message';
  7. }

监听通知

通知会以 php {notifiable}.{id} 的格式在一个私有频道上广播。因此,如果你向一个 ID 为 php 1php App\Models\User 实例发送通知,通知将在 php App.Models.User.1 私有频道上广播。当使用 Laravel Echo 时,你可以使用 php notification 方法轻松地在频道上监听通知:

  1. Echo.private('App.Models.User.' + userId)
  2. .notification((notification) => {
  3. console.log(notification.type);
  4. });

自定义通知频道
如果你想自定义实体的广播通知在哪个频道上广播,可以在可通知实体上定义一个 php receivesBroadcastNotificationsOn 方法:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Broadcasting\PrivateChannel;
  4. use Illuminate\Foundation\Auth\User as Authenticatable;
  5. use Illuminate\Notifications\Notifiable;
  6. class User extends Authenticatable
  7. {
  8. use Notifiable;
  9. /**
  10. * 用户接收通知广播的频道。
  11. */
  12. public function receivesBroadcastNotificationsOn(): string
  13. {
  14. return 'users.'.$this->id;
  15. }
  16. }

短信通知

先决条件

Laravel 中发送短信通知是由 Vonage(之前称为 Nexmo)驱动的。在通过 Vonage 发送通知之前,你需要安装 php laravel/vonage-notification-channelphp guzzlehttp/guzzle 包:

  1. composer require laravel/vonage-notification-channel guzzlehttp/guzzle

该包包括一个 配置文件。但是,你不需要将此配置文件导出到自己的应用程序。你可以简单地使用 php VONAGE_KEYphp VONAGE_SECRET 环境变量来定义 Vonage 的公共和私有密钥。

定义好密钥后,你可以设置一个 php VONAGE_SMS_FROM 环境变量,该变量定义了你发送 SMS 消息的默认电话号码。你可以在 Vonage 控制面板中生成此电话号码:

  1. VONAGE_SMS_FROM=15556666666

格式化短信通知

如果通知支持作为 SMS 发送,你应该在通知类上定义一个 php toVonage 方法。此方法将接收一个 php $notifiable 实体并应返回一个 php Illuminate\Notifications\Messages\VonageMessage 实例:

  1. use Illuminate\Notifications\Messages\VonageMessage;
  2. /**
  3. * 获取通知的 Vonage / SMS 表达式。
  4. */
  5. public function toVonage(object $notifiable): VonageMessage
  6. {
  7. return (new VonageMessage)
  8. ->content('你的短信内容');
  9. }

Unicode 内容
如果你的 SMS 消息将包含 unicode 字符,你应该在构造 php VonageMessage 实例时调用 php unicode 方法:

  1. use Illuminate\Notifications\Messages\VonageMessage;
  2. /**
  3. * 获取通知的 Vonage / SMS 表达式。
  4. */
  5. public function toVonage(object $notifiable): VonageMessage
  6. {
  7. return (new VonageMessage)
  8. ->content('你的统一码消息')
  9. ->unicode();
  10. }

自定义「来源」号码

如果你想从一个不同于 php VONAGE_SMS_FROM 环境变量所指定的电话号码发送通知,你可以在 php VonageMessage 实例上调用 php from 方法:

  1. use Illuminate\Notifications\Messages\VonageMessage;
  2. /**
  3. * 获取通知的 Vonage / SMS 表达式。
  4. */
  5. public function toVonage(object $notifiable): VonageMessage
  6. {
  7. return (new VonageMessage)
  8. ->content('您的短信内容')
  9. ->from('15554443333');
  10. }

添加客户关联

如果你想跟踪每个用户、团队或客户的消费,你可以在通知中添加「客户关联」。Vonage 将允许你使用这个客户关联生成报告,以便你能更好地了解特定客户的短信使用情况。客户关联可以是任何字符串,最多 40 个字符。

  1. use Illuminate\Notifications\Messages\VonageMessage;
  2. /**
  3. * 获取通知的 Vonage / SMS 表达式。
  4. */
  5. public function toVonage(object $notifiable): VonageMessage
  6. {
  7. return (new VonageMessage)
  8. ->clientReference((string) $notifiable->id)
  9. ->content('你的短信内容');
  10. }

路由短信通知

要将 Vonage 通知路由到正确的电话号码,请在你的通知实体上定义 php routeNotificationForVonage 方法:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Foundation\Auth\User as Authenticatable;
  4. use Illuminate\Notifications\Notifiable;
  5. use Illuminate\Notifications\Notification;
  6. class User extends Authenticatable
  7. {
  8. use Notifiable;
  9. /**
  10. * Vonage 通道的路由通知。
  11. */
  12. public function routeNotificationForVonage(Notification $notification): string
  13. {
  14. return $this->phone_number;
  15. }
  16. }

Slack 通知

先决条件

在你可以通过 Slack 发送通知之前,你必须通过 Composer 安装 Slack 通知通道:

  1. composer require laravel/slack-notification-channel

你还需要为你的团队创建一个 Slack 应用。创建应用后,你应该为工作区配置一个「传入 Webhook」。 然后,Slack 将为你提供一个 webhook URL,你可以在 路由 Slack 通知 时使用该 URL。

格式化 Slack 通知

如果通知支持作为 Slack 消息发送,你应在通知类上定义 php toSlack 方法。此方法将接收一个 php $notifiable 实体并应返回一个 php Illuminate\Notifications\Messages\SlackMessage 实例。Slack 消息可能包含文本内容以及格式化附加文本或字段数组的「附件」。 让我们看一个基本的 php toSlack 示例:

  1. use Illuminate\Notifications\Messages\SlackMessage;
  2. /**
  3. * 获取通知的 Slack 表达式。
  4. */
  5. public function toSlack(object $notifiable): SlackMessage
  6. {
  7. return (new SlackMessage)
  8. ->content('你的一张发票已经付款了!');
  9. }

Slack 附件

你还可以向 Slack 消息添加「附件」。附件提供比简单文本消息更丰富的格式选项。在这个例子中,我们将发送一个关于应用程序中发生的异常的错误通知,包括一个链接,以查看有关异常的更多详细信息:

  1. use Illuminate\Notifications\Messages\SlackAttachment;
  2. use Illuminate\Notifications\Messages\SlackMessage;
  3. /**
  4. * 获取通知的 Slack 表示形式。
  5. */
  6. public function toSlack(object $notifiable): SlackMessage
  7. {
  8. $url = url('/exceptions/'.$this->exception->id);
  9. return (new SlackMessage)
  10. ->error()
  11. ->content('哎呀!出了问题。')
  12. ->attachment(function (SlackAttachment $attachment) use ($url) {
  13. $attachment->title('例外:文件未找到', $url)
  14. ->content('文件 [background.jpg] 未找到。');
  15. });
  16. }

附件还允许你指定应呈现给用户的数据数组。 给定的数据将以表格形式呈现,以便于阅读:

  1. use Illuminate\Notifications\Messages\SlackAttachment;
  2. use Illuminate\Notifications\Messages\SlackMessage;
  3. /**
  4. * 获取通知的 Slack 表示形式。
  5. */
  6. public function toSlack(object $notifiable): SlackMessage
  7. {
  8. $url = url('/invoices/'.$this->invoice->id);
  9. return (new SlackMessage)
  10. ->success()
  11. ->content('你的一张发票已经付款了!')
  12. ->attachment(function (SlackAttachment $attachment) use ($url) {
  13. $attachment->title('Invoice 1322', $url)
  14. ->fields([
  15. 'Title' => 'Server Expenses',
  16. 'Amount' => '$1,234',
  17. 'Via' => 'American Express',
  18. 'Was Overdue' => ':-1:',
  19. ]);
  20. });
  21. }

Markdown 附件内容
如果你的附件字段中包含 Markdown,则可以使用 php markdown 方法指示 Slack 解析和显示给定的附件字段为 Markdown 格式的文本。此方法接受的值是:php pretextphp text和/或php fields。有关 Slack 附件格式的更多信息,请查看 Slack API 文档

  1. use Illuminate\Notifications\Messages\SlackAttachment;
  2. use Illuminate\Notifications\Messages\SlackMessage;
  3. /**
  4. * 获取通知的 Slack 表示形式。
  5. */
  6. public function toSlack(object $notifiable): SlackMessage
  7. {
  8. $url = url('/exceptions/'.$this->exception->id);
  9. return (new SlackMessage)
  10. ->error()
  11. ->content('Whoops! Something went wrong.')
  12. ->attachment(function (SlackAttachment $attachment) use ($url) {
  13. $attachment->title('Exception: File Not Found', $url)
  14. ->content('File [background.jpg] was *not found*.')
  15. ->markdown(['text']);
  16. });
  17. }

路由 Slack 通知

为了将 Slack 通知路由到正确的 Slack 团队和频道,请在你的通知实体上定义一个 php routeNotificationForSlack 方法。它应该返回要传送通知的 Webhook URL。Webhook URL 可以通过向你的 Slack 团队添加「传入 Webhook」服务来生成:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Foundation\Auth\User as Authenticatable;
  4. use Illuminate\Notifications\Notifiable;
  5. use Illuminate\Notifications\Notification;
  6. class User extends Authenticatable
  7. {
  8. use Notifiable;
  9. /**
  10. * 路由 Slack 频道的通知。
  11. */
  12. public function routeNotificationForSlack(Notification $notification): string
  13. {
  14. return 'https://hooks.slack.com/services/...';
  15. }
  16. }

本地化通知

Laravel 允许你在除了当前请求语言环境之外的其他语言环境中发送通知,甚至在通知被队列化的情况下也能记住此语言环境。

为了实现这一功能,php Illuminate\Notifications\Notification 类提供了 php locale 方法来设置所需的语言环境。在通知被评估时,应用程序将切换到此语言环境,然后在评估完成后恢复到以前的语言环境:

  1. $user->notify((new InvoicePaid($invoice))->locale('es'));

通过 php Notification 门面,也可以实现多个通知实体的本地化:

  1. Notification::locale('es')->send(
  2. $users, new InvoicePaid($invoice)
  3. );

用户首选语言环境

有时,应用程序会存储每个用户的首选区域设置。通过在你的可通知模型上实现 php HasLocalePreference 合同,你可以指示 Laravel 在发送通知时使用此存储的区域设置:

  1. use Illuminate\Contracts\Translation\HasLocalePreference;
  2. class User extends Model implements HasLocalePreference
  3. {
  4. /**
  5. * 获取用户的首选语言环境。
  6. */
  7. public function preferredLocale(): string
  8. {
  9. return $this->locale;
  10. }
  11. }

翻译:一旦你实现了这个接口,当发送通知和邮件到该模型时,Laravel 会自动使用首选语言环境。因此,在使用此接口时不需要调用php locale方法:

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

测试

你可以使用 php Notification 门面的 php fake 方法来阻止通知被发送。通常情况下,发送通知与你实际测试的代码无关。很可能,只需要断言 Laravel 被指示发送了给定的通知即可。

在调用 php Notification 门面的 php fake 方法后,你可以断言已经被告知将通知发送给用户,甚至检查通知接收到的数据:

  1. <?php
  2. namespace Tests\Feature;
  3. use App\Notifications\OrderShipped;
  4. use Illuminate\Support\Facades\Notification;
  5. use Tests\TestCase;
  6. class ExampleTest extends TestCase
  7. {
  8. public function test_orders_can_be_shipped(): void
  9. {
  10. Notification::fake();
  11. // 执行订单发货...
  12. // 断言没有发送通知...
  13. Notification::assertNothingSent();
  14. // 断言通知已发送给给定用户...
  15. Notification::assertSentTo(
  16. [$user], OrderShipped::class
  17. );
  18. // 断言未发送通知...
  19. Notification::assertNotSentTo(
  20. [$user], AnotherNotification::class
  21. );
  22. // 断言已发送给定数量的通知...
  23. Notification::assertCount(3);
  24. }
  25. }

你可以通过向 php assertSentTophp assertNotSentTo 方法传递一个闭包来断言发送了符合给定「真实性测试」的通知。如果发送了至少一个符合给定真实性测试的通知,则断言将成功:

  1. Notification::assertSentTo(
  2. $user,
  3. function (OrderShipped $notification, array $channels) use ($order) {
  4. return $notification->order->id === $order->id;
  5. }
  6. );

按需通知
如果你正在测试的代码发送 即时通知,你可以使用 php assertSentOnDemand 方法测试是否发送了即时通知:

  1. Notification::assertSentOnDemand(OrderShipped::class);

通过将闭包作为 php assertSentOnDemand 方法的第二个参数传递,你可以确定是否将即时通知发送到了正确的 「route」 地址:

  1. Notification::assertSentOnDemand(
  2. OrderShipped::class,
  3. function (OrderShipped $notification, array $channels, object $notifiable) use ($user) {
  4. return $notifiable->routes['mail'] === $user->email;
  5. }
  6. );

通知事件

通知发送事件
发送通知时,通知系统会调度 php Illuminate\Notifications\Events\NotificationSending 事件。 这包含「可通知」实体和通知实例本身。 你可以在应用程序的 php EventServiceProvider 中为该事件注册监听器:

  1. use App\Listeners\CheckNotificationStatus;
  2. use Illuminate\Notifications\Events\NotificationSending;
  3. /**
  4. * 应用程序的事件侦听器映射。
  5. *
  6. * @var array
  7. */
  8. protected $listen = [
  9. NotificationSending::class => [
  10. CheckNotificationStatus::class,
  11. ],
  12. ];

如果 php NotificationSending 事件的监听器从它的 php handle 方法返回 php false,通知将不会被发送:

  1. use Illuminate\Notifications\Events\NotificationSending;
  2. /**
  3. * 处理事件。
  4. */
  5. public function handle(NotificationSending $event): void
  6. {
  7. return false;
  8. }

在事件监听器中,你可以访问事件的 php notifiablephp notificationphp channel 属性,以了解有关通知接收者或通知本身的更多信息。

  1. /**
  2. * 处理事件。
  3. */
  4. public function handle(NotificationSending $event): void
  5. {
  6. // $event->channel
  7. // $event->notifiable
  8. // $event->notification
  9. }

通知发送事件
当通知被发送时,通知系统会触发 php Illuminate\Notifications\Events\NotificationSent 事件,其中包含 「notifiable」 实体和通知实例本身。你可以在 php EventServiceProvider 中注册此事件的监听器:

  1. use App\Listeners\LogNotification;
  2. use Illuminate\Notifications\Events\NotificationSent;
  3. /**
  4. * 应用程序的事件侦听器映射。
  5. *
  6. * @var array
  7. */
  8. protected $listen = [
  9. NotificationSent::class => [
  10. LogNotification::class,
  11. ],
  12. ];

注意
php EventServiceProvider 中注册了监听器之后,可以使用 event:generate Artisan 命令快速生成监听器类。

在事件监听器中,你可以访问事件上的 php notifiablephp notificationphp channelphp response 属性,以了解更多有关通知收件人或通知本身的信息:

  1. /**
  2. * 处理事件。
  3. */
  4. public function handle(NotificationSent $event): void
  5. {
  6. // $event->channel
  7. // $event->notifiable
  8. // $event->notification
  9. // $event->response
  10. }

自定义频道

Laravel 提供了一些通知频道,但你可能想编写自己的驱动程序,以通过其他频道传递通知。Laravel 让这变得简单。要开始,定义一个包含 php send 方法的类。该方法应接收两个参数:php $notifiablephp $notification

php send 方法中,你可以调用通知上的方法来检索一个由你的频道理解的消息对象,然后按照你希望的方式将通知发送给 php $notifiable 实例:

  1. <?php
  2. namespace App\Notifications;
  3. use Illuminate\Notifications\Notification;
  4. class VoiceChannel
  5. {
  6. /**
  7. * 发送给定的通知
  8. */
  9. public function send(object $notifiable, Notification $notification): void
  10. {
  11. $message = $notification->toVoice($notifiable);
  12. // 将通知发送给 $notifiable 实例...
  13. }
  14. }

一旦你定义了你的通知频道类,你可以从你的任何通知的 php via 方法返回该类的名称。在这个例子中,你的通知的 php toVoice 方法可以返回你选择来表示语音消息的任何对象。例如,你可以定义自己的 php VoiceMessage 类来表示这些消息:

  1. <?php
  2. namespace App\Notifications;
  3. use App\Notifications\Messages\VoiceMessage;
  4. use App\Notifications\VoiceChannel;
  5. use Illuminate\Bus\Queueable;
  6. use Illuminate\Contracts\Queue\ShouldQueue;
  7. use Illuminate\Notifications\Notification;
  8. class InvoicePaid extends Notification
  9. {
  10. use Queueable;
  11. /**
  12. * 获取通知频道
  13. */
  14. public function via(object $notifiable): string
  15. {
  16. return VoiceChannel::class;
  17. }
  18. /**
  19. * 获取通知的语音表示形式
  20. */
  21. public function toVoice(object $notifiable): VoiceMessage
  22. {
  23. // ...
  24. }
  25. }