主题
通知
简介
除了支持发送电子邮件之外,Laravel 还支持通过多种投递渠道发送通知,包括电子邮件、短信(通过 Vonage,前身为 Nexmo)和 Slack。此外,社区还创建了各种社区构建的通知渠道,可以通过数十种不同的渠道发送通知!通知还可以存储在数据库中,以便在你的 Web 界面中显示。
通常,通知应该是简短的信息性消息,用于告知用户应用中发生的事情。例如,如果你正在编写一个计费应用,你可以通过电子邮件和短信渠道向用户发送"发票已支付"通知。
生成通知
在 Laravel 中,每个通知都由一个类表示,通常存储在 app/Notifications 目录中。如果你的应用中没有看到这个目录,不用担心 - 当你运行 make:notification Artisan 命令时,它会自动创建:
shell
php artisan make:notification InvoicePaid此命令会在 app/Notifications 目录中放置一个新的通知类。每个通知类包含一个 via 方法和若干消息构建方法,如 toMail 或 toDatabase,用于将通知转换为针对特定渠道定制的消息。
发送通知
使用 Notifiable Trait
通知可以通过两种方式发送:使用 Notifiable trait 的 notify 方法或使用 Notification facade。Notifiable trait 默认包含在你的应用的 App\Models\User 模型中:
php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
}此 trait 提供的 notify 方法期望接收一个通知实例:
php
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));NOTE
请记住,你可以在任何模型上使用 Notifiable trait。你不仅限于在 User 模型上使用它。
使用 Notification Facade
或者,你可以通过 Notification facade 发送通知。当你需要向多个可通知实体(如用户集合)发送通知时,这种方法很有用。要使用 facade 发送通知,请将所有可通知实体和通知实例传递给 send 方法:
php
use Illuminate\Support\Facades\Notification;
Notification::send($users, new InvoicePaid($invoice));你还可以使用 sendNow 方法立即发送通知。即使通知实现了 ShouldQueue 接口,此方法也会立即发送通知:
php
Notification::sendNow($developers, new DeploymentCompleted($deployment));指定投递渠道
每个通知类都有一个 via 方法,用于确定通知将通过哪些渠道投递。通知可以通过 mail、database、broadcast、vonage 和 slack 渠道发送。
NOTE
如果你想使用其他投递渠道(如 Telegram 或 Pusher),请查看社区驱动的 Laravel Notification Channels 网站。
via 方法接收一个 $notifiable 实例,该实例是通知要发送到的类的实例。你可以使用 $notifiable 来确定通知应该通过哪些渠道投递:
php
/**
* 获取通知的投递渠道。
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];
}队列通知
WARNING
在将通知加入队列之前,你应该配置队列并启动一个 worker。
发送通知可能需要时间,特别是当渠道需要进行外部 API 调用来投递通知时。为了加速应用的响应时间,可以通过向类添加 ShouldQueue 接口和 Queueable trait 来让通知加入队列。使用 make:notification 命令生成的所有通知已经导入了该接口和 trait,因此你可以立即将它们添加到通知类中:
php
<?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 接口并自动将通知的投递加入队列:
php
$user->notify(new InvoicePaid($invoice));当将通知加入队列时,会为每个接收者和渠道的组合创建一个队列任务。例如,如果你的通知有三个接收者和两个渠道,则会有六个任务被分发到队列中。
延迟通知
如果你想延迟通知的投递,可以在通知实例化时链式调用 delay 方法:
php
$delay = now()->plus(minutes: 10);
$user->notify((new InvoicePaid($invoice))->delay($delay));你可以将数组传递给 delay 方法,以指定特定渠道的延迟时间:
php
$user->notify((new InvoicePaid($invoice))->delay([
'mail' => now()->plus(minutes: 5),
'sms' => now()->plus(minutes: 10),
]));或者,你可以在通知类本身定义一个 withDelay 方法。withDelay 方法应返回一个包含渠道名称和延迟值的数组:
php
/**
* 确定通知的投递延迟。
*
* @return array<string, \Illuminate\Support\Carbon>
*/
public function withDelay(object $notifiable): array
{
return [
'mail' => now()->plus(minutes: 5),
'sms' => now()->plus(minutes: 10),
];
}自定义通知队列连接
默认情况下,队列通知将使用应用的默认队列连接进行排队。如果你想指定一个不同的连接用于特定通知,可以在通知的构造函数中调用 onConnection 方法:
php
<?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->onConnection('redis');
}
}或者,如果你想指定通知支持的每个通知渠道应使用的特定队列连接,可以在通知上定义一个 viaConnections 方法。此方法应返回一个渠道名称 / 队列连接名称的键值对数组:
php
/**
* 确定每个通知渠道应使用的连接。
*
* @return array<string, string>
*/
public function viaConnections(): array
{
return [
'mail' => 'redis',
'database' => 'sync',
];
}自定义通知渠道队列
如果你想指定通知支持的每个通知渠道应使用的特定队列,可以在通知上定义一个 viaQueues 方法。此方法应返回一个渠道名称 / 队列名称的键值对数组:
php
/**
* 确定每个通知渠道应使用的队列。
*
* @return array<string, string>
*/
public function viaQueues(): array
{
return [
'mail' => 'mail-queue',
'slack' => 'slack-queue',
];
}自定义队列通知任务属性
你可以通过在通知类上定义队列属性来自定义底层队列任务的行为。这些属性将被发送通知的队列任务继承:
php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\Attributes\MaxExceptions;
use Illuminate\Queue\Attributes\Timeout;
use Illuminate\Queue\Attributes\Tries;
#[Tries(5)]
#[Timeout(120)]
#[MaxExceptions(3)]
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// ...
}如果你想通过加密确保队列通知数据的隐私性和完整性,可以在通知类上添加 ShouldBeEncrypted 接口:
php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue, ShouldBeEncrypted
{
use Queueable;
// ...
}除了直接在通知类上定义这些属性外,你还可以定义 backoff 和 retryUntil 方法来指定队列通知任务的退避策略和重试超时时间:
php
use DateTime;
/**
* 计算重试通知前等待的秒数。
*/
public function backoff(): int
{
return 3;
}
/**
* 确定通知应超时的时间。
*/
public function retryUntil(): DateTime
{
return now()->plus(minutes: 5);
}NOTE
有关这些任务属性和方法的更多信息,请查看队列任务文档。
队列通知中间件
队列通知可以像队列任务一样定义中间件。要开始使用,请在通知类上定义一个 middleware 方法。middleware 方法将接收 $notifiable 和 $channel 变量,允许你根据通知的目标自定义返回的中间件:
php
use Illuminate\Queue\Middleware\RateLimited;
/**
* 获取通知任务应通过的中间件。
*
* @return array<int, object>
*/
public function middleware(object $notifiable, string $channel)
{
return match ($channel) {
'mail' => [new RateLimited('postmark')],
'slack' => [new RateLimited('slack')],
default => [],
};
}队列通知与数据库事务
当队列通知在数据库事务中被分发时,它们可能在数据库事务提交之前就被队列处理。当这种情况发生时,你在数据库事务期间对模型或数据库记录所做的任何更新可能尚未反映在数据库中。此外,在事务中创建的任何模型或数据库记录可能还不存在于数据库中。如果你的通知依赖于这些模型,当处理发送队列通知的任务时可能会出现意外错误。
如果队列连接的 after_commit 配置选项设置为 false,你仍然可以通过在发送通知时调用 afterCommit 方法来指示特定的队列通知应在所有打开的数据库事务提交后分发:
php
use App\Notifications\InvoicePaid;
$user->notify((new InvoicePaid($invoice))->afterCommit());或者,你可以在通知的构造函数中调用 afterCommit 方法:
php
<?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();
}
}NOTE
要了解更多关于解决这些问题的方法,请查看有关队列任务和数据库事务的文档。
确定是否应发送队列通知
在队列通知被分发到队列进行后台处理后,它通常会被队列 worker 接受并发送给预定的接收者。
但是,如果你想在队列 worker 处理后对是否应发送队列通知做最终决定,可以在通知类上定义一个 shouldSend 方法。如果此方法返回 false,通知将不会被发送:
php
/**
* 确定是否应发送通知。
*/
public function shouldSend(object $notifiable, string $channel): bool
{
return $this->invoice->isPaid();
}发送后回调
如果你想在通知发送后执行代码,可以在通知类上定义一个 afterSending 方法。此方法将接收可通知实体、渠道名称和渠道的响应:
php
/**
* 处理通知发送后的操作。
*/
public function afterSending(object $notifiable, string $channel, mixed $response): void
{
// ...
}按需通知
有时你可能需要向未存储为应用"用户"的人发送通知。使用 Notification facade 的 route 方法,你可以在发送通知之前指定临时的通知路由信息:
php
use Illuminate\Broadcasting\Channel;
use Illuminate\Support\Facades\Notification;
Notification::route('mail', 'taylor@example.com')
->route('vonage', '5555555555')
->route('slack', '#slack-channel')
->route('broadcast', [new Channel('channel-name')])
->notify(new InvoicePaid($invoice));如果你想在向 mail 路由发送按需通知时提供收件人的名称,可以提供一个数组,其中电子邮件地址作为键,名称作为数组第一个元素的值:
php
Notification::route('mail', [
'barrett@example.com' => 'Barrett Blair',
])->notify(new InvoicePaid($invoice));使用 routes 方法,你可以一次性为多个通知渠道提供临时路由信息:
php
Notification::routes([
'mail' => ['barrett@example.com' => 'Barrett Blair'],
'vonage' => '5555555555',
])->notify(new InvoicePaid($invoice));邮件通知
格式化邮件消息
如果通知支持以电子邮件形式发送,你应该在通知类上定义一个 toMail 方法。此方法将接收一个 $notifiable 实体,并应返回一个 Illuminate\Notifications\Messages\MailMessage 实例。
MailMessage 类包含一些简单的方法来帮助你构建事务性电子邮件消息。邮件消息可以包含文本行以及"行动号召"。让我们看一个 toMail 方法的示例:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->lineIf($this->amount > 0, "Amount paid: {$this->amount}")
->action('View Invoice', $url)
->line('Thank you for using our application!');
}NOTE
注意我们在 toMail 方法中使用了 $this->invoice->id。你可以将通知生成消息所需的任何数据传递到通知的构造函数中。
在此示例中,我们注册了一个问候语、一行文本、一个行动号召,然后是另一行文本。MailMessage 对象提供的这些方法使得格式化小型事务性电子邮件变得简单快速。然后,邮件渠道会将消息组件转换为精美的响应式 HTML 电子邮件模板,并附带纯文本副本。以下是由 mail 渠道生成的电子邮件示例:

NOTE
发送邮件通知时,请确保在 config/app.php 配置文件中设置了 name 配置选项。此值将用于邮件通知消息的页眉和页脚。
错误消息
某些通知会通知用户发生了错误,例如发票支付失败。你可以在构建消息时调用 error 方法来指示邮件消息与错误有关。在邮件消息上使用 error 方法时,行动号召按钮将变为红色而不是黑色:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->error()
->subject('Invoice Payment Failed')
->line('...');
}其他邮件通知格式化选项
你可以使用 view 方法指定一个自定义模板来渲染通知电子邮件,而不是在通知类中定义文本"行":
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->view(
'mail.invoice.paid', ['invoice' => $this->invoice]
);
}你可以通过将视图名称作为传递给 view 方法的数组的第二个元素来为邮件消息指定纯文本视图:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->view(
['mail.invoice.paid', 'mail.invoice.paid-text'],
['invoice' => $this->invoice]
);
}或者,如果你的消息只有纯文本视图,可以使用 text 方法:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->text(
'mail.invoice.paid-text', ['invoice' => $this->invoice]
);
}自定义发件人
默认情况下,电子邮件的发件人/发件地址在 config/mail.php 配置文件中定义。但是,你可以使用 from 方法为特定通知指定发件地址:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->from('barrett@example.com', 'Barrett Blair')
->line('...');
}自定义收件人
通过 mail 渠道发送通知时,通知系统会自动在你的可通知实体上查找 email 属性。你可以通过在可通知实体上定义 routeNotificationForMail 方法来自定义用于投递通知的电子邮件地址:
php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* 为邮件渠道路由通知。
*
* @return array<string, string>|string
*/
public function routeNotificationForMail(Notification $notification): array|string
{
// 仅返回电子邮件地址...
return $this->email_address;
// 返回电子邮件地址和名称...
return [$this->email_address => $this->name];
}
}自定义主题
默认情况下,电子邮件的主题是通知的类名格式化为"标题大小写"。因此,如果你的通知类名为 InvoicePaid,电子邮件的主题将是 Invoice Paid。如果你想为消息指定不同的主题,可以在构建消息时调用 subject 方法:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Notification Subject')
->line('...');
}自定义邮件程序
默认情况下,电子邮件通知将使用 config/mail.php 配置文件中定义的默认邮件程序发送。但是,你可以在构建消息时通过调用 mailer 方法在运行时指定不同的邮件程序:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->mailer('postmark')
->line('...');
}自定义模板
你可以通过发布通知包的资源来修改邮件通知使用的 HTML 和纯文本模板。运行此命令后,邮件通知模板将位于 resources/views/vendor/notifications 目录中:
shell
php artisan vendor:publish --tag=laravel-notifications附件
要向电子邮件通知添加附件,请在构建消息时使用 attach 方法。attach 方法接受文件的绝对路径作为其第一个参数:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file');
}将文件附加到消息时,你还可以通过将 array 作为 attach 方法的第二个参数来指定显示名称和/或 MIME 类型:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}与在 mailable 对象中附加文件不同,你不能使用 attachFromStorage 直接从存储磁盘附加文件。你应该使用 attach 方法并提供存储磁盘上文件的绝对路径。或者,你可以从 toMail 方法返回一个 mailable:
php
use App\Mail\InvoicePaid as InvoicePaidMailable;
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): Mailable
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email)
->attachFromStorage('/path/to/file');
}如有需要,可以使用 attachMany 方法将多个文件附加到消息:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attachMany([
'/path/to/forge.svg',
'/path/to/vapor.svg' => [
'as' => 'Logo.svg',
'mime' => 'image/svg+xml',
],
]);
}原始数据附件
attachData 方法可用于将原始字节字符串作为附件附加。调用 attachData 方法时,你应该提供应分配给附件的文件名:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}添加标签和元数据
一些第三方电子邮件提供商(如 Mailgun 和 Postmark)支持消息"标签"和"元数据",可用于对应用发送的电子邮件进行分组和跟踪。你可以通过 tag 和 metadata 方法向电子邮件消息添加标签和元数据:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Comment Upvoted!')
->tag('upvote')
->metadata('comment_id', $this->comment->id);
}如果你的应用使用 Mailgun 驱动,可以查阅 Mailgun 的文档以获取有关标签和元数据的更多信息。同样,也可以查阅 Postmark 文档以获取有关其对标签和元数据支持的更多信息。
如果你的应用使用 Amazon SES 发送电子邮件,则应使用 metadata 方法将 SES "标签" 附加到消息。
自定义 Symfony 消息
MailMessage 类的 withSymfonyMessage 方法允许你注册一个闭包,该闭包将在发送消息之前使用 Symfony Message 实例调用。这使你有机会在投递消息之前深度自定义消息:
php
use Symfony\Component\Mime\Email;
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->withSymfonyMessage(function (Email $message) {
$message->getHeaders()->addTextHeader(
'Custom-Header', 'Header Value'
);
});
}使用 Mailable
如果需要,你可以从通知的 toMail 方法返回一个完整的 mailable 对象。当返回 Mailable 而不是 MailMessage 时,你需要使用 mailable 对象的 to 方法指定消息接收者:
php
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Mail\Mailable;
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): Mailable
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email);
}Mailable 和按需通知
如果你正在发送按需通知,则传递给 toMail 方法的 $notifiable 实例将是 Illuminate\Notifications\AnonymousNotifiable 的实例,该实例提供了一个 routeNotificationFor 方法,可用于检索按需通知应发送到的电子邮件地址:
php
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Notifications\AnonymousNotifiable;
use Illuminate\Mail\Mailable;
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): Mailable
{
$address = $notifiable instanceof AnonymousNotifiable
? $notifiable->routeNotificationFor('mail')
: $notifiable->email;
return (new InvoicePaidMailable($this->invoice))
->to($address);
}预览邮件通知
设计邮件通知模板时,像典型的 Blade 模板一样在浏览器中快速预览渲染的邮件消息很方便。因此,Laravel 允许你直接从路由闭包或控制器返回邮件通知生成的任何邮件消息。当返回 MailMessage 时,它将在浏览器中渲染和显示,让你无需将其发送到实际电子邮件地址即可快速预览其设计:
php
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 模板,同时自动生成纯文本副本。
生成消息
要生成具有相应 Markdown 模板的通知,可以使用 make:notification Artisan 命令的 --markdown 选项:
shell
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid与所有其他邮件通知一样,使用 Markdown 模板的通知应在其通知类上定义 toMail 方法。但是,不要使用 line 和 action 方法来构造通知,而是使用 markdown 方法来指定应使用的 Markdown 模板的名称。你希望提供给模板的数据数组可以作为该方法的第二个参数传递:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}编写消息
Markdown 邮件通知使用 Blade 组件和 Markdown 语法的组合,使你能够在利用 Laravel 预制通知组件的同时轻松构建通知:
blade
<x-mail::message>
# Invoice Paid
Your invoice has been paid!
<x-mail::button :url="$url">
View Invoice
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>NOTE
编写 Markdown 电子邮件时不要使用过多缩进。根据 Markdown 标准,Markdown 解析器会将缩进内容渲染为代码块。
按钮组件
按钮组件渲染一个居中的按钮链接。该组件接受两个参数:url 和一个可选的 color。支持的颜色有 primary、green 和 red。你可以根据需要向通知添加任意数量的按钮组件:
blade
<x-mail::button :url="$url" color="green">
View Invoice
</x-mail::button>面板组件
面板组件将给定的文本块渲染在一个背景颜色与通知其余部分略有不同的面板中。这允许你将注意力引向给定的文本块:
blade
<x-mail::panel>
This is the panel content.
</x-mail::panel>表格组件
表格组件允许你将 Markdown 表格转换为 HTML 表格。该组件接受 Markdown 表格作为其内容。支持使用默认的 Markdown 表格对齐语法进行列对齐:
blade
<x-mail::table>
| Laravel | Table | Example |
| ------------- | :-----------: | ------------: |
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
</x-mail::table>自定义组件
你可以将所有 Markdown 通知组件导出到你自己的应用中进行自定义。要导出组件,请使用 vendor:publish Artisan 命令发布 laravel-mail 资源标签:
shell
php artisan vendor:publish --tag=laravel-mail此命令会将 Markdown 邮件组件发布到 resources/views/vendor/mail 目录。mail 目录将包含一个 html 和一个 text 目录,每个目录包含每个可用组件的各自表示。你可以随意自定义这些组件。
自定义 CSS
导出组件后,resources/views/vendor/mail/html/themes 目录将包含一个 default.css 文件。你可以自定义此文件中的 CSS,你的样式将自动内联到 Markdown 通知的 HTML 表示中。
如果你想为 Laravel 的 Markdown 组件构建一个全新的主题,可以在 html/themes 目录中放置一个 CSS 文件。命名并保存 CSS 文件后,更新 mail 配置文件的 theme 选项以匹配你的新主题名称。
要为单个通知自定义主题,可以在构建通知的邮件消息时调用 theme 方法。theme 方法接受发送通知时应使用的主题名称:
php
/**
* 获取通知的邮件表示。
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->theme('invoice')
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}数据库通知
前提条件
database 通知渠道将通知信息存储在数据库表中。此表将包含诸如通知类型以及描述通知的 JSON 数据结构等信息。
你可以查询该表以在应用的用户界面中显示通知。但在此之前,你需要创建一个数据库表来保存通知。你可以使用 make:notifications-table 命令生成一个具有适当表结构的迁移:
shell
php artisan make:notifications-table
php artisan migrateNOTE
如果你的可通知模型使用 UUID 或 ULID 主键,你应该在通知表迁移中将 morphs 方法替换为 uuidMorphs 或 ulidMorphs。
格式化数据库通知
如果通知支持存储在数据库表中,你应该在通知类上定义 toDatabase 或 toArray 方法。此方法将接收一个 $notifiable 实体,并应返回一个普通的 PHP 数组。返回的数组将被编码为 JSON 并存储在 notifications 表的 data 列中。让我们看一个 toArray 方法的示例:
php
/**
* 获取通知的数组表示。
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
];
}当通知存储在应用的数据库中时,type 列默认将设置为通知的类名,read_at 列将为 null。但是,你可以通过在通知类中定义 databaseType 和 initialDatabaseReadAtValue 方法来自定义此行为:
php
use Illuminate\Support\Carbon;
/**
* 获取通知的数据库类型。
*/
public function databaseType(object $notifiable): string
{
return 'invoice-paid';
}
/**
* 获取 "read_at" 列的初始值。
*/
public function initialDatabaseReadAtValue(): ?Carbon
{
return null;
}toDatabase 与 toArray
toArray 方法也被 broadcast 渠道用于确定向 JavaScript 前端广播的数据。如果你想为 database 和 broadcast 渠道提供两种不同的数组表示,应该定义 toDatabase 方法而不是 toArray 方法。
访问通知
一旦通知存储在数据库中,你需要一种方便的方式从可通知实体中访问它们。Laravel 默认的 App\Models\User 模型中包含的 Illuminate\Notifications\Notifiable trait 包含一个 notifications Eloquent 关联,用于返回该实体的通知。要获取通知,你可以像访问任何其他 Eloquent 关联一样访问此方法。默认情况下,通知将按 created_at 时间戳排序,最新的通知位于集合的开头:
php
$user = App\Models\User::find(1);
foreach ($user->notifications as $notification) {
echo $notification->type;
}如果你只想检索"未读"通知,可以使用 unreadNotifications 关联。同样,这些通知将按 created_at 时间戳排序,最新的通知位于集合的开头:
php
$user = App\Models\User::find(1);
foreach ($user->unreadNotifications as $notification) {
echo $notification->type;
}如果你只想检索"已读"通知,可以使用 readNotifications 关联:
php
$user = App\Models\User::find(1);
foreach ($user->readNotifications as $notification) {
echo $notification->type;
}NOTE
要从 JavaScript 客户端访问通知,你应该为应用定义一个通知控制器,该控制器返回可通知实体(如当前用户)的通知。然后你可以从 JavaScript 客户端向该控制器的 URL 发起 HTTP 请求。
将通知标记为已读
通常,你会希望在用户查看通知时将其标记为"已读"。Illuminate\Notifications\Notifiable trait 提供了一个 markAsRead 方法,该方法会更新通知数据库记录上的 read_at 列:
php
$user = App\Models\User::find(1);
foreach ($user->unreadNotifications as $notification) {
$notification->markAsRead();
}但是,你可以直接在通知集合上使用 markAsRead 方法,而不是循环遍历每个通知:
php
$user->unreadNotifications->markAsRead();你还可以使用批量更新查询将所有通知标记为已读,而无需从数据库中检索它们:
php
$user = App\Models\User::find(1);
$user->unreadNotifications()->update(['read_at' => now()]);你可以 delete 通知以将其从表中完全移除:
php
$user->notifications()->delete();广播通知
前提条件
在广播通知之前,你应该配置并熟悉 Laravel 的事件广播服务。事件广播提供了一种从 JavaScript 前端响应服务端 Laravel 事件的方式。
格式化广播通知
broadcast 渠道使用 Laravel 的事件广播服务广播通知,允许你的 JavaScript 前端实时接收通知。如果通知支持广播,你可以在通知类上定义一个 toBroadcast 方法。此方法将接收一个 $notifiable 实体,并应返回一个 BroadcastMessage 实例。如果 toBroadcast 方法不存在,将使用 toArray 方法来收集应广播的数据。返回的数据将被编码为 JSON 并广播到你的 JavaScript 前端。让我们看一个 toBroadcast 方法的示例:
php
use Illuminate\Notifications\Messages\BroadcastMessage;
/**
* 获取通知的可广播表示。
*/
public function toBroadcast(object $notifiable): BroadcastMessage
{
return new BroadcastMessage([
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
]);
}广播队列配置
所有广播通知都会排队等待广播。如果你想配置用于排队广播操作的队列连接或队列名称,可以使用 BroadcastMessage 的 onConnection 和 onQueue 方法:
php
return (new BroadcastMessage($data))
->onConnection('sqs')
->onQueue('broadcasts');自定义通知类型
除了你指定的数据外,所有广播通知还有一个 type 字段,包含通知的完整类名。如果你想自定义通知 type,可以在通知类上定义一个 broadcastType 方法:
php
/**
* 获取正在广播的通知的类型。
*/
public function broadcastType(): string
{
return 'broadcast.message';
}监听通知
通知将在使用 {notifiable}.{id} 约定格式化的私有频道上广播。因此,如果你向 ID 为 1 的 App\Models\User 实例发送通知,该通知将在 App.Models.User.1 私有频道上广播。使用 Laravel Echo 时,你可以使用 notification 方法轻松监听频道上的通知:
js
Echo.private('App.Models.User.' + userId)
.notification((notification) => {
console.log(notification.type);
});使用 React 或 Vue
Laravel Echo 包含 React 和 Vue hooks,使监听通知变得轻松。要开始使用,请调用 useEchoNotification hook,该 hook 用于监听通知。当使用该 hook 的组件被卸载时,useEchoNotification hook 将自动离开频道:
js
import { useEchoNotification } from "@laravel/echo-react";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
);vue
<script setup lang="ts">
import { useEchoNotification } from "@laravel/echo-vue";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
);
</script>默认情况下,hook 监听所有通知。要指定你想监听的通知类型,可以向 useEchoNotification 提供字符串或类型数组:
js
import { useEchoNotification } from "@laravel/echo-react";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);vue
<script setup lang="ts">
import { useEchoNotification } from "@laravel/echo-vue";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);
</script>你还可以指定通知负载数据的形状,提供更好的类型安全性和编辑便利性:
ts
type InvoicePaidNotification = {
invoice_id: number;
created_at: string;
};
useEchoNotification<InvoicePaidNotification>(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.invoice_id);
console.log(notification.created_at);
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);自定义通知频道
如果你想自定义实体的广播通知所广播的频道,可以在可通知实体上定义一个 receivesBroadcastNotificationsOn 方法:
php
<?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;
/**
* 用户接收通知广播的频道。
*/
public function receivesBroadcastNotificationsOn(): string
{
return 'users.'.$this->id;
}
}短信通知
前提条件
Laravel 中的短信通知由 Vonage(前身为 Nexmo)驱动。在通过 Vonage 发送通知之前,你需要安装 laravel/vonage-notification-channel 和 guzzlehttp/guzzle 包:
shell
composer require laravel/vonage-notification-channel guzzlehttp/guzzle该包包含一个配置文件。但是,你不需要将此配置文件导出到自己的应用中。你只需使用 VONAGE_KEY 和 VONAGE_SECRET 环境变量来定义你的 Vonage 公钥和密钥。
定义密钥后,你应该设置一个 VONAGE_SMS_FROM 环境变量,定义默认发送短信消息的电话号码。你可以在 Vonage 控制面板中生成此电话号码:
ini
VONAGE_SMS_FROM=15556666666格式化短信通知
如果通知支持以短信形式发送,你应该在通知类上定义一个 toVonage 方法。此方法将接收一个 $notifiable 实体,并应返回一个 Illuminate\Notifications\Messages\VonageMessage 实例:
php
use Illuminate\Notifications\Messages\VonageMessage;
/**
* 获取通知的 Vonage / SMS 表示。
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->content('Your SMS message content');
}Unicode 内容
如果你的短信消息将包含 unicode 字符,你应该在构造 VonageMessage 实例时调用 unicode 方法:
php
use Illuminate\Notifications\Messages\VonageMessage;
/**
* 获取通知的 Vonage / SMS 表示。
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->content('Your unicode message')
->unicode();
}自定义"发件"号码
如果你想从与 VONAGE_SMS_FROM 环境变量指定的电话号码不同的号码发送某些通知,可以在 VonageMessage 实例上调用 from 方法:
php
use Illuminate\Notifications\Messages\VonageMessage;
/**
* 获取通知的 Vonage / SMS 表示。
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->content('Your SMS message content')
->from('15554443333');
}添加客户端引用
如果你想按用户、团队或客户跟踪费用,可以在通知中添加"客户端引用"。Vonage 将允许你使用此客户端引用生成报告,以便你更好地了解特定客户的短信使用情况。客户端引用可以是任何不超过 40 个字符的字符串:
php
use Illuminate\Notifications\Messages\VonageMessage;
/**
* 获取通知的 Vonage / SMS 表示。
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->clientReference((string) $notifiable->id)
->content('Your SMS message content');
}路由短信通知
要将 Vonage 通知路由到正确的电话号码,请在你的可通知实体上定义一个 routeNotificationForVonage 方法:
php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* 为 Vonage 渠道路由通知。
*/
public function routeNotificationForVonage(Notification $notification): string
{
return $this->phone_number;
}
}Slack 通知
前提条件
在发送 Slack 通知之前,你应该通过 Composer 安装 Slack 通知渠道:
shell
composer require laravel/slack-notification-channel此外,你必须为你的 Slack 工作区创建一个 Slack App。
如果你只需要向创建应用的同一 Slack 工作区发送通知,你应该确保你的应用具有 chat:write、chat:write.public 和 chat:write.customize 作用域。这些作用域可以从 Slack 的"OAuth & Permissions"应用管理选项卡中添加。
接下来,复制应用的"Bot User OAuth Token"并将其放在应用的 services.php 配置文件中的 slack 配置数组中。此 token 可以在 Slack 的"OAuth & Permissions"选项卡中找到:
php
'slack' => [
'notifications' => [
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
],
],应用分发
如果你的应用将向应用用户拥有的外部 Slack 工作区发送通知,你需要通过 Slack "分发"你的应用。应用分发可以从 Slack 中应用的"Manage Distribution"选项卡进行管理。一旦你的应用被分发,你可以使用 Socialite 代表应用用户获取 Slack Bot tokens。
格式化 Slack 通知
如果通知支持作为 Slack 消息发送,你应该在通知类上定义一个 toSlack 方法。此方法将接收一个 $notifiable 实体,并应返回一个 Illuminate\Notifications\Slack\SlackMessage 实例。你可以使用 Slack 的 Block Kit API 构建丰富的通知。以下示例可以在 Slack 的 Block Kit 构建器中预览:
php
use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\SlackMessage;
/**
* 获取通知的 Slack 表示。
*/
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->contextBlock(function (ContextBlock $block) {
$block->text('Customer #1234');
})
->sectionBlock(function (SectionBlock $block) {
$block->text('An invoice has been paid.');
$block->field("*Invoice No:*\n1000")->markdown();
$block->field("*Invoice Recipient:*\ntaylor@laravel.com")->markdown();
})
->dividerBlock()
->sectionBlock(function (SectionBlock $block) {
$block->text('Congratulations!');
});
}使用 Slack 的 Block Kit 构建器模板
你可以将 Slack 的 Block Kit Builder 生成的原始 JSON 负载提供给 usingBlockKitTemplate 方法,而不是使用流式消息构建器方法来构建 Block Kit 消息:
php
use Illuminate\Notifications\Slack\SlackMessage;
use Illuminate\Support\Str;
/**
* 获取通知的 Slack 表示。
*/
public function toSlack(object $notifiable): SlackMessage
{
$template = <<<JSON
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Team Announcement"
}
},
{
"type": "section",
"text": {
"type": "plain_text",
"text": "We are hiring!"
}
}
]
}
JSON;
return (new SlackMessage)
->usingBlockKitTemplate($template);
}Slack 交互性
Slack 的 Block Kit 通知系统提供了强大的功能来处理用户交互。要使用这些功能,你的 Slack 应用应启用"Interactivity"并配置一个指向你的应用提供的 URL 的"Request URL"。这些设置可以从 Slack 的"Interactivity & Shortcuts"应用管理选项卡进行管理。
在以下使用 actionsBlock 方法的示例中,Slack 将向你的"Request URL"发送一个 POST 请求,其中包含点击按钮的 Slack 用户、被点击按钮的 ID 等负载。然后你的应用可以根据负载确定要执行的操作。你还应该验证请求是否由 Slack 发出:
php
use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\SlackMessage;
/**
* 获取通知的 Slack 表示。
*/
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->contextBlock(function (ContextBlock $block) {
$block->text('Customer #1234');
})
->sectionBlock(function (SectionBlock $block) {
$block->text('An invoice has been paid.');
})
->actionsBlock(function (ActionsBlock $block) {
// ID 默认为 "button_acknowledge_invoice"...
$block->button('Acknowledge Invoice')->primary();
// 手动配置 ID...
$block->button('Deny')->danger()->id('deny_invoice');
});
}确认对话框
如果你希望用户在执行操作之前必须确认,可以在定义按钮时调用 confirm 方法。confirm 方法接受一条消息和一个接收 ConfirmObject 实例的闭包:
php
use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject;
use Illuminate\Notifications\Slack\SlackMessage;
/**
* 获取通知的 Slack 表示。
*/
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->contextBlock(function (ContextBlock $block) {
$block->text('Customer #1234');
})
->sectionBlock(function (SectionBlock $block) {
$block->text('An invoice has been paid.');
})
->actionsBlock(function (ActionsBlock $block) {
$block->button('Acknowledge Invoice')
->primary()
->confirm(
'Acknowledge the payment and send a thank you email?',
function (ConfirmObject $dialog) {
$dialog->confirm('Yes');
$dialog->deny('No');
}
);
});
}检查 Slack Blocks
如果你想快速检查你正在构建的 blocks,可以在 SlackMessage 实例上调用 dd 方法。dd 方法将生成并转储一个指向 Slack 的 Block Kit Builder 的 URL,该 URL 在浏览器中显示负载和通知的预览。你可以将 true 传递给 dd 方法以转储原始负载:
php
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->dd();路由 Slack 通知
要将 Slack 通知定向到适当的 Slack 团队和频道,请在你的可通知模型上定义一个 routeNotificationForSlack 方法。此方法可以返回以下三个值之一:
null- 将路由推迟到通知本身配置的频道。你可以在构建SlackMessage时使用to方法在通知内部配置频道。- 一个指定要发送通知的 Slack 频道的字符串,例如
#support-channel。 - 一个
SlackRoute实例,允许你指定 OAuth token 和频道名称,例如SlackRoute::make($this->slack_channel, $this->slack_token)。此方法应用于向外部工作区发送通知。
例如,从 routeNotificationForSlack 方法返回 #support-channel 将会把通知发送到与应用 services.php 配置文件中的 Bot User OAuth token 关联的工作区的 #support-channel 频道:
php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* 为 Slack 渠道路由通知。
*/
public function routeNotificationForSlack(Notification $notification): mixed
{
return '#support-channel';
}
}通知外部 Slack 工作区
NOTE
在向外部 Slack 工作区发送通知之前,你的 Slack 应用必须已分发。
当然,你通常会想要向应用用户拥有的 Slack 工作区发送通知。为此,你首先需要为用户获取一个 Slack OAuth token。值得庆幸的是,Laravel Socialite 包含一个 Slack 驱动,允许你轻松地使用 Slack 对应用用户进行身份验证并获取 bot token。
获取 bot token 并将其存储在应用的数据库中后,你可以使用 SlackRoute::make 方法将通知路由到用户的工作区。此外,你的应用可能需要为用户提供指定通知应发送到哪个频道的机会:
php
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Slack\SlackRoute;
class User extends Authenticatable
{
use Notifiable;
/**
* 为 Slack 渠道路由通知。
*/
public function routeNotificationForSlack(Notification $notification): mixed
{
return SlackRoute::make($this->slack_channel, $this->slack_token);
}
}本地化通知
Laravel 允许你以 HTTP 请求当前语言环境之外的语言环境发送通知,即使通知被加入队列也会记住此语言环境。
为此,Illuminate\Notifications\Notification 类提供了一个 locale 方法来设置所需的语言。当通知被评估时,应用将切换到此语言环境,然后在评估完成后恢复到之前的语言环境:
php
$user->notify((new InvoicePaid($invoice))->locale('es'));也可以通过 Notification facade 实现多个可通知条目的本地化:
php
Notification::locale('es')->send(
$users, new InvoicePaid($invoice)
);用户首选语言环境
有时,应用会存储每个用户的首选语言环境。通过在你的可通知模型上实现 HasLocalePreference 契约,你可以指示 Laravel 在发送通知时使用此存储的语言环境:
php
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Model implements HasLocalePreference
{
/**
* 获取用户的首选语言环境。
*/
public function preferredLocale(): string
{
return $this->locale;
}
}一旦你实现了该接口,Laravel 将在向该模型发送通知和 mailable 时自动使用首选语言环境。因此,使用此接口时无需调用 locale 方法:
php
$user->notify(new InvoicePaid($invoice));测试
你可以使用 Notification facade 的 fake 方法来阻止通知被发送。通常,发送通知与你实际测试的代码无关。大多数情况下,只需断言 Laravel 被指示发送了给定的通知就足够了。
调用 Notification facade 的 fake 方法后,你可以断言通知被指示发送给了用户,甚至可以检查通知接收到的数据:
php
<?php
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
test('orders can be shipped', function () {
Notification::fake();
// 执行订单发货...
// 断言没有通知被发送...
Notification::assertNothingSent();
// 断言通知被发送给了指定用户...
Notification::assertSentTo(
[$user], OrderShipped::class
);
// 断言通知未被发送...
Notification::assertNotSentTo(
[$user], AnotherNotification::class
);
// 断言通知被发送了两次...
Notification::assertSentTimes(WeeklyReminder::class, 2);
// 断言发送了指定数量的通知...
Notification::assertCount(3);
});php
<?php
namespace Tests\Feature;
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_orders_can_be_shipped(): void
{
Notification::fake();
// 执行订单发货...
// 断言没有通知被发送...
Notification::assertNothingSent();
// 断言通知被发送给了指定用户...
Notification::assertSentTo(
[$user], OrderShipped::class
);
// 断言通知未被发送...
Notification::assertNotSentTo(
[$user], AnotherNotification::class
);
// 断言通知被发送了两次...
Notification::assertSentTimes(WeeklyReminder::class, 2);
// 断言发送了指定数量的通知...
Notification::assertCount(3);
}
}你可以向 assertSentTo 或 assertNotSentTo 方法传递一个闭包,以断言发送的通知通过了给定的"真值测试"。如果至少有一个通知通过了给定的真值测试,则断言将成功:
php
Notification::assertSentTo(
$user,
function (OrderShipped $notification, array $channels) use ($order) {
return $notification->order->id === $order->id;
}
);按需通知
如果你正在测试的代码发送了按需通知,你可以通过 assertSentOnDemand 方法测试按需通知是否已发送:
php
Notification::assertSentOnDemand(OrderShipped::class);通过将闭包作为 assertSentOnDemand 方法的第二个参数传递,你可以确定按需通知是否被发送到了正确的"路由"地址:
php
Notification::assertSentOnDemand(
OrderShipped::class,
function (OrderShipped $notification, array $channels, object $notifiable) use ($user) {
return $notifiable->routes['mail'] === $user->email;
}
);通知事件
通知发送中事件
当通知正在发送时,通知系统会分发 Illuminate\Notifications\Events\NotificationSending 事件。该事件包含"可通知"实体和通知实例本身。你可以在应用中为此事件创建事件监听器:
php
use Illuminate\Notifications\Events\NotificationSending;
class CheckNotificationStatus
{
/**
* 处理事件。
*/
public function handle(NotificationSending $event): void
{
// ...
}
}如果 NotificationSending 事件的事件监听器从其 handle 方法返回 false,则通知将不会被发送:
php
/**
* 处理事件。
*/
public function handle(NotificationSending $event): bool
{
return false;
}在事件监听器中,你可以访问事件的 notifiable、notification 和 channel 属性,以了解有关通知接收者或通知本身的更多信息:
php
/**
* 处理事件。
*/
public function handle(NotificationSending $event): void
{
// $event->channel
// $event->notifiable
// $event->notification
}通知已发送事件
当通知被发送时,通知系统会分发 Illuminate\Notifications\Events\NotificationSent 事件。该事件包含"可通知"实体和通知实例本身。你可以在应用中为此事件创建事件监听器:
php
use Illuminate\Notifications\Events\NotificationSent;
class LogNotification
{
/**
* 处理事件。
*/
public function handle(NotificationSent $event): void
{
// ...
}
}在事件监听器中,你可以访问事件的 notifiable、notification、channel 和 response 属性,以了解有关通知接收者或通知本身的更多信息:
php
/**
* 处理事件。
*/
public function handle(NotificationSent $event): void
{
// $event->channel
// $event->notifiable
// $event->notification
// $event->response
}自定义渠道
Laravel 附带了一些通知渠道,但你可能想要编写自己的驱动来通过其他渠道投递通知。Laravel 使这变得简单。要开始,定义一个包含 send 方法的类。该方法应接收两个参数:一个 $notifiable 和一个 $notification。
在 send 方法中,你可以调用通知上的方法来检索渠道理解的消息对象,然后按你的意愿将通知发送给 $notifiable 实例:
php
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notification;
class VoiceChannel
{
/**
* 发送给定的通知。
*/
public function send(object $notifiable, Notification $notification): void
{
$message = $notification->toVoice($notifiable);
// 将通知发送给 $notifiable 实例...
}
}一旦定义了通知渠道类,你就可以从任何通知的 via 方法返回该类名。在此示例中,通知的 toVoice 方法可以返回你选择的任何对象来表示语音消息。例如,你可以定义自己的 VoiceMessage 类来表示这些消息:
php
<?php
namespace App\Notifications;
use App\Notifications\Messages\VoiceMessage;
use App\Notifications\VoiceChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification
{
use Queueable;
/**
* 获取通知渠道。
*/
public function via(object $notifiable): string
{
return VoiceChannel::class;
}
/**
* 获取通知的语音表示。
*/
public function toVoice(object $notifiable): VoiceMessage
{
// ...
}
}