使用 Laravel 发送通知
发布于 作者 Steve McDougall
在大多数应用程序中,我们需要发送通知,无论是应用内通知、电子邮件还是 Slack 通知 - 这些通常是事务性通知,用于提醒用户应用程序中的一些操作或事件。让我们深入研究一下。
当您想要向用户发送通知时,首先需要考虑的是传递机制。我们想要发送一封简短的电子邮件吗?或者这是一个系统级通知,我们想要将数据发送到 Slack 频道?或者可能是应用内通知,因为有人喜欢了你猫的照片?
无论哪种方式,传递都是任何通知的基础,当然,在 Laravel 中,您可以从一个通知传递到多个频道。我们通过在 Notification 类本身的 via
方法中使用该方法来完成此操作,并指定要发送通知的频道数组。
开箱即用,您可以发送 Slack、电子邮件和应用内通知,无需任何其他包。但是,如今在通知频道方面有很多选择。幸运的是,一个 社区维护的网站 展示了您可以选择的方式、安装说明以及如何通过许多不同的频道发送通知。
让我们逐步了解发送通知的基本示例。我们有一个系统,人们可以在其中预订会议,比如 Calendly 或 SavvyCal。无论是 API、网络交互还是 CLI,我们始终希望获得相同的结果。如果有人预订了会议,我们应该通知那个人,让他们知道会议已预订,并附带日历邀请。我们还想让预订会议的人知道,以便他们可以意识到。我们可能还想在第三方系统上更新一些内容以管理可用性。
首先,让我们使用 artisan 控制台生成一个通知
php artisan make:notification UserMeetingBookedNotification --test
让我们分解一下该命令。我们要创建一个通知,这部分很清楚,并且在生成代码时适合大多数 artisan 命令。然后,我们为通知本身提供一个名称。您可以使用命名空间来进一步对通知进行分组,使用“\”或“/”来分隔命名空间。我们还添加了 --test
选项,以便 Laravel 将为该特定通知生成一个测试;这将是一个功能测试。我使用 pestPHP 作为我的测试框架,所以我通常会发布存根以自定义生成的测试输出。
生成完通知代码后,我们应该关注必须传递给构造函数的属性(如果有)以及我们要传递的频道。因此,让我们假设我们想要接受通知的名称和电子邮件,以便我们可以提醒预订了与他们会议的用户。
让我们开始构建我们的通知
declare(strict_types=1); namespace App\Notifications; use Carbon\CarbonInterface;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Notification; final class UserMeetingBookedNotification extends Notification implements ShouldQueue{ use Queueable; public function __construct( public readonly string $name, public readonly string $email, public readonly CarbonInterface $datetime, ) {}}
现在我们可以构建我们的通知以进行传递。我们需要决定一个频道。在本教程中,我将重点介绍默认情况下可用的选项,但 Laravel Notification Channels 提供了很多您可以用于替代频道的相关信息。
我们将使用此通知通过电子邮件通知用户他们已经预订了会议。因此,我们需要添加 via
方法并声明我们要使用 mail
频道。
declare(strict_types=1); namespace App\Notifications; use Carbon\CarbonInterface;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Notification; final class UserMeetingBookedNotification extends Notification implements ShouldQueue{ use Queueable; public function __construct( public readonly string $name, public readonly string $email, public readonly CarbonInterface $datetime, ) {} public function via(mixed $notifiable): array { return ['mail']; }}
添加完 via
方法后,我们需要描述将发送的邮件信息。我们通过 toMail
方法来完成此操作。这里的一般规则是,每个频道都需要一个 to
方法,在其中我们用 to
作为前缀来加上大写的频道名称。
declare(strict_types=1); namespace App\Notifications; use Carbon\CarbonInterface;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification; final class UserMeetingBookedNotification extends Notification implements ShouldQueue{ use Queueable; public function __construct( public readonly string $name, public readonly string $email, public readonly CarbonInterface $datetime, ) {} public function via(mixed $notifiable): array { return ['mail']; } public function toMail(mixed $notifiable): MailMessage { return (new MailMessage) ->subject('New Booking Received.') ->greeting('Booking received') ->line("{$this->name} has booked a meeting with you.") ->line("This has been booked for {$this->datetime->format('l jS \\of F Y h:i:s A')}") ->line("You can email them on {$this->email} if you need to organise anything."); }}
就是这样;这将向用户发送一封简单明了的电子邮件,提醒他们如何联系以及他们收到预订的事实。
假设我们现在需要将其添加到 Slack 频道,可能是出于跟踪原因。我们仍然想要发送电子邮件通知,但要添加一个频道。
首先,我们应该确保测试我们已经构建的内容。与项目的所有方面一样,除非您测试它们,否则您无法保证它们可以正常工作。让我们首先编写围绕发送电子邮件通知的测试。然后我们可以进行更改。
it('can send an email notification when a booking is made', function () { Notification::fake(); $user = User::factory()->create(); expect( Bookings::query()->count(), )->toEqual(0); $action = app()->make( abstract: CreateNewBookingAction::class, ); $action->handle( user: $user->id, name: 'Test User', time: now()->addHours(12), ); expect( Bookings::query()->count(), )->toEqual(1); Notification::assertSentTo( [$user], UserMeetingBookedNotification::class, );});
我们在 Laravel 中模拟通知驱动程序,以便通知不会路由到任何人。然后,我们创建一个我们要通知的用户并从容器中解析我们的逻辑 - 抽象此逻辑使测试变得更加容易。我们想要确保当我们进行预订时,它会被保存,但随后我们想要确保通知按预期发送,只是从未传递。
我们可以在我们的测试中添加另一个检查,以确保我们的测试发送到正确的频道
it('sends the notification to the correct channels', function () { Notification::fake(); $user = User::factory()->create(); $action = app()->make( abstract: CreateNewBookingAction::class, ); $action->handle( user: $user->id, name: 'Test User', time: now()->addHours(12), ); Notification::assertSentTo( [$user], UserMeetingBookedNotification::class, function (mixed $notification, array $channels): bool { return in_array('mail', $channels); }, );});
与我们的初始测试类似,但这次我们在 assertSentTo
调用中添加了第三个参数,其中包含一个可调用函数,我们希望确保我们在发送到我们的邮件频道。
现在我们对测试覆盖率很满意。我们知道当处理该操作时,将发送通知,并且当它被发送时,频道将包括邮件频道 - 这意味着我们的电子邮件将被传递。
让我们回到添加下一个频道:Slack。我在下面的代码示例中隐藏了 toMail
方法,以更方便地查看正在执行的操作
declare(strict_types=1); namespace App\Notifications; use Carbon\CarbonInterface;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Messages\MailMessage;Illuminate\Notifications\Messages\SlackMessage;use Illuminate\Notifications\Notification; final class UserMeetingBookedNotification extends Notification implements ShouldQueue{ use Queueable; public function __construct( public readonly string $name, public readonly string $email, public readonly CarbonInterface $datetime, ) {} public function via(mixed $notifiable): array { return ['mail', 'slack']; } public function toSlack(mixed $notifiable): SlackMessage { return (new SlackMessage) ->success() ->content("{$this->name} just booked a meeting for {$this->datetime->format('l jS \\of F Y h:i:s A')}."); }}
但是,为了使此操作正常工作,我们需要确保安装 Laravel 团队提供的第一个通知包
composer require laravel/slack-notification-channel
现在已经完成,我们可以修改我们的测试以确保我们也将其发送到 Slack 频道
it('sends the notification to the correct channels', function () { Notification::fake(); $user = User::factory()->create(); $action = app()->make( abstract: CreateNewBookingAction::class, ); $action->handle( user: $user->id, name: 'Test User', time: now()->addHours(12), ); Notification::assertSentTo( [$user], UserMeetingBookedNotification::class, function (mixed $notification, array $channels): bool { return in_array('mail', $channels) & in_array('slack', $channels); }, );});
我们可以对通知进行更多测试,但这对于入门来说是一个很好的地方,不会过于复杂。我们知道我们将在正确的时间向正确用户在正确频道发送正确的通知。
需要注意的是,通知不必排队。这些也可以同步发送。
因此,现在我们知道如何创建和测试通知;让我们看看如何发送它们。
在默认的 Laravel 应用程序中,您的 User 模型实现了 Notifiable
特性,这使您可以执行以下操作
auth()->user()->notify(new UserMeetingBookedNotification( name: $request->get('name'), email: $request->('email'),));
这很棒,但可通知特性依赖于模型是否具有可访问的电子邮件属性。当我们的用例不完全符合这种方法时,该怎么办?那么可通知特性对我们来说就没有太大用处了。这就是我认为 Notification 门面是您最好的朋友的地方。您可以使用 Notification 门面 手动路由通知,而不是依赖特性本身。让我们看一个示例
Notification::send(['email address one', 'email address two'], new EmailNotification($arguments));
上面的示例将使您能够以快速简便的方式以编程方式将通知发送到电子邮件地址数组。执行此操作的一种稍微干净的方法是使用按需通知。假设我们想要能够以编程方式将通知作为 artisan 命令的一部分发送。您可以为频道提供一个参数,并以编程方式选择如何发送通知。
它从 Notification 门面开始。然后,您告诉它使用频道和参数 route
通知。
Notification::route('slack', 'slack-webhook-url') ->notify(new SlackNotification($argument));
Notification 门面非常强大且灵活,使您能够按需发送通知并快速测试它们。
您如何在 Laravel 应用程序中使用通知?您最喜欢的频道是什么?请在 Twitter 上告诉我们!