通知
簡介
除了支援傳送電子郵件外,Laravel 還支援透過多種頻道傳送通知,包括電子郵件、簡訊(透過 Vonage,原名 Nexmo)和 Slack。此外,社群還建立了各種社群構建的通知頻道,用於透過數十種不同的頻道傳送通知!通知還可以儲存在資料庫中,以便在您的 Web 介面中展示。
通常情況下,通知應該是簡短的資訊,告知使用者應用程式中發生的事件。例如,如果您正在編寫一個計費應用程式,您可能會透過電子郵件和簡訊頻道向用戶傳送“發票已支付”通知。
生成通知
在 Laravel 中,每個通知都由一個類表示,通常儲存在 app/Notifications 目錄中。如果您的應用程式中沒有此目錄,不用擔心——當您執行 make:notification Artisan 命令時,它會自動為您建立。
1php artisan make:notification InvoicePaid
此命令將在您的 app/Notifications 目錄中放置一個新的通知類。每個通知類都包含一個 via 方法和若干個訊息構建方法(例如 toMail 或 toDatabase),這些方法將通知轉換為適合特定頻道的訊息。
傳送通知
使用 Notifiable Trait
傳送通知有兩種方式:使用 Notifiable trait 的 notify 方法,或使用 Notification 門面。Notifiable trait 預設包含在應用程式的 App\Models\User 模型中。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Foundation\Auth\User as Authenticatable; 6use Illuminate\Notifications\Notifiable; 7 8class User extends Authenticatable 9{10 use Notifiable;11}
此 trait 提供的 notify 方法期望接收一個通知例項。
1use App\Notifications\InvoicePaid;2 3$user->notify(new InvoicePaid($invoice));
請記住,您可以在任何模型上使用 Notifiable trait。您不僅限於在 User 模型上使用它。
使用 Notification 門面 (Facade)
或者,您可以透過 Notification 門面傳送通知。當您需要向多個可通知實體(例如一組使用者)傳送通知時,此方法非常有用。要使用門面傳送通知,請將所有可通知實體和通知例項傳遞給 send 方法。
1use Illuminate\Support\Facades\Notification;2 3Notification::send($users, new InvoicePaid($invoice));
您也可以使用 sendNow 方法立即傳送通知。即使通知實現了 ShouldQueue 介面,此方法也會立即傳送通知。
1Notification::sendNow($developers, new DeploymentCompleted($deployment));
指定傳送頻道
每個通知類都有一個 via 方法,該方法決定通知將透過哪些頻道傳送。通知可以透過 mail、database、broadcast、vonage 和 slack 頻道傳送。
如果您想使用其他傳送頻道(例如 Telegram 或 Pusher),請檢視社群驅動的 Laravel 通知頻道網站。
via 方法接收一個 $notifiable 例項,即傳送該通知的目標類例項。您可以使用 $notifiable 來決定通知應透過哪些頻道傳送。
1/**2 * Get the notification's delivery channels.3 *4 * @return array<int, string>5 */6public function via(object $notifiable): array7{8 return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];9}
佇列化通知
在佇列化通知之前,您應該配置佇列並啟動 worker。
傳送通知可能需要時間,特別是當頻道需要進行外部 API 呼叫來發送通知時。為了加快應用程式的響應速度,可以透過將 ShouldQueue 介面和 Queueable trait 新增到類中來讓通知排隊。對於使用 make:notification 命令生成的通知,該介面和 trait 已經預設匯入,因此您可以立即將它們新增到通知類中。
1<?php 2 3namespace App\Notifications; 4 5use Illuminate\Bus\Queueable; 6use Illuminate\Contracts\Queue\ShouldQueue; 7use Illuminate\Notifications\Notification; 8 9class InvoicePaid extends Notification implements ShouldQueue10{11 use Queueable;12 13 // ...14}
一旦通知添加了 ShouldQueue 介面,您就可以像往常一樣傳送通知。Laravel 會檢測到類上的 ShouldQueue 介面並自動將通知的傳送加入佇列。
1$user->notify(new InvoicePaid($invoice));
在排隊通知時,將為每個接收者和頻道組合建立一個排隊的作業。例如,如果您的通知有三個接收者和兩個頻道,則會向佇列分發六個作業。
延遲通知
如果您想延遲傳送通知,可以在通知例項化時鏈式呼叫 delay 方法。
1$delay = now()->plus(minutes: 10);2 3$user->notify((new InvoicePaid($invoice))->delay($delay));
您可以將陣列傳遞給 delay 方法,為特定頻道指定延遲量。
1$user->notify((new InvoicePaid($invoice))->delay([2 'mail' => now()->plus(minutes: 5),3 'sms' => now()->plus(minutes: 10),4]));
或者,您可以在通知類本身上定義 withDelay 方法。withDelay 方法應返回頻道名稱和延遲值的陣列。
1/** 2 * Determine the notification's delivery delay. 3 * 4 * @return array<string, \Illuminate\Support\Carbon> 5 */ 6public function withDelay(object $notifiable): array 7{ 8 return [ 9 'mail' => now()->plus(minutes: 5),10 'sms' => now()->plus(minutes: 10),11 ];12}
自定義通知佇列連線
預設情況下,排隊的通知將使用應用程式的預設佇列連線進行排隊。如果您想為特定通知指定不同的連線,可以在通知的建構函式中呼叫 onConnection 方法。
1<?php 2 3namespace App\Notifications; 4 5use Illuminate\Bus\Queueable; 6use Illuminate\Contracts\Queue\ShouldQueue; 7use Illuminate\Notifications\Notification; 8 9class InvoicePaid extends Notification implements ShouldQueue10{11 use Queueable;12 13 /**14 * Create a new notification instance.15 */16 public function __construct()17 {18 $this->onConnection('redis');19 }20}
或者,如果您想為通知支援的每個通知頻道指定特定的佇列連線,可以在通知上定義 viaConnections 方法。此方法應返回頻道名稱 / 佇列連線名稱的陣列。
1/** 2 * Determine which connections should be used for each notification channel. 3 * 4 * @return array<string, string> 5 */ 6public function viaConnections(): array 7{ 8 return [ 9 'mail' => 'redis',10 'database' => 'sync',11 ];12}
自定義通知頻道佇列
如果您想為通知支援的每個通知頻道指定特定的佇列,可以在通知上定義 viaQueues 方法。此方法應返回頻道名稱 / 佇列名稱的陣列。
1/** 2 * Determine which queues should be used for each notification channel. 3 * 4 * @return array<string, string> 5 */ 6public function viaQueues(): array 7{ 8 return [ 9 'mail' => 'mail-queue',10 'slack' => 'slack-queue',11 ];12}
自定義排隊通知的作業屬性
您可以透過在通知類上定義佇列屬性來自定義底層排隊作業的行為。這些屬性將被髮送通知的排隊作業繼承。
1<?php 2 3namespace App\Notifications; 4 5use Illuminate\Bus\Queueable; 6use Illuminate\Contracts\Queue\ShouldQueue; 7use Illuminate\Notifications\Notification; 8use Illuminate\Queue\Attributes\MaxExceptions; 9use Illuminate\Queue\Attributes\Timeout;10use Illuminate\Queue\Attributes\Tries;11 12#[Tries(5)]13#[Timeout(120)]14#[MaxExceptions(3)]15class InvoicePaid extends Notification implements ShouldQueue16{17 use Queueable;18 19 // ...20}
如果您想透過加密確保排隊通知資料的隱私和完整性,請將 ShouldBeEncrypted 介面新增到您的通知類中。
1<?php 2 3namespace App\Notifications; 4 5use Illuminate\Bus\Queueable; 6use Illuminate\Contracts\Queue\ShouldBeEncrypted; 7use Illuminate\Contracts\Queue\ShouldQueue; 8use Illuminate\Notifications\Notification; 9 10class InvoicePaid extends Notification implements ShouldQueue, ShouldBeEncrypted11{12 use Queueable;13 14 // ...15}
除了直接在通知類上定義這些屬性外,您還可以定義 backoff 和 retryUntil 方法來指定排隊通知作業的退避策略和重試超時時間。
1use DateTime; 2 3/** 4 * Calculate the number of seconds to wait before retrying the notification. 5 */ 6public function backoff(): int 7{ 8 return 3; 9}10 11/**12 * Determine the time at which the notification should timeout.13 */14public function retryUntil(): DateTime15{16 return now()->plus(minutes: 5);17}
有關這些作業屬性和方法的更多資訊,請檢視關於排隊作業的文件。
排隊通知中介軟體
排隊通知可以像排隊作業一樣定義中介軟體。首先,在您的通知類上定義一個 middleware 方法。middleware 方法將接收 $notifiable 和 $channel 變數,允許您根據通知的目標自定義返回的中介軟體。
1use Illuminate\Queue\Middleware\RateLimited; 2 3/** 4 * Get the middleware the notification job should pass through. 5 * 6 * @return array<int, object> 7 */ 8public function middleware(object $notifiable, string $channel) 9{10 return match ($channel) {11 'mail' => [new RateLimited('postmark')],12 'slack' => [new RateLimited('slack')],13 default => [],14 };15}
排隊通知與資料庫事務
當排隊通知在資料庫事務中被分發時,它們可能會在資料庫事務提交之前被佇列處理。發生這種情況時,您在資料庫事務期間對模型或資料庫記錄所做的任何更新可能尚未反映在資料庫中。此外,在事務中建立的任何模型或資料庫記錄可能在資料庫中還不存在。如果您的通知依賴於這些模型,則在處理傳送排隊通知的作業時可能會出現意外錯誤。
如果您的佇列連線的 after_commit 配置選項設定為 false,您仍然可以透過在傳送通知時呼叫 afterCommit 方法,表明特定的排隊通知應在所有開啟的資料庫事務提交後分發。
1use App\Notifications\InvoicePaid;2 3$user->notify((new InvoicePaid($invoice))->afterCommit());
或者,您可以從通知的建構函式中呼叫 afterCommit 方法。
1<?php 2 3namespace App\Notifications; 4 5use Illuminate\Bus\Queueable; 6use Illuminate\Contracts\Queue\ShouldQueue; 7use Illuminate\Notifications\Notification; 8 9class InvoicePaid extends Notification implements ShouldQueue10{11 use Queueable;12 13 /**14 * Create a new notification instance.15 */16 public function __construct()17 {18 $this->afterCommit();19 }20}
要了解更多關於解決這些問題的資訊,請檢視關於排隊作業與資料庫事務的文件。
確定是否應該傳送排隊通知
在排隊通知被分發到佇列進行後臺處理後,它通常會被佇列 worker 接收併發送給預期的接收者。
但是,如果您想在佇列 worker 處理排隊通知後,最終決定是否應該傳送該通知,可以在通知類上定義一個 shouldSend 方法。如果此方法返回 false,則通知將不會發送。
1/**2 * Determine if the notification should be sent.3 */4public function shouldSend(object $notifiable, string $channel): bool5{6 return $this->invoice->isPaid();7}
傳送通知後
如果您想在通知傳送後執行程式碼,可以定義一個 afterSending 方法。此方法將接收可通知實體、頻道名稱和來自頻道的響應。
1/**2 * Handle the notification after it has been sent.3 */4public function afterSending(object $notifiable, string $channel, mixed $response): void5{6 // ...7}
按需通知 (On-Demand Notifications)
有時,您可能需要向未儲存為應用程式“使用者”的人傳送通知。使用 Notification 門面的 route 方法,您可以在傳送通知之前指定即時(ad-hoc)的通知路由資訊。
1use Illuminate\Broadcasting\Channel;2use Illuminate\Support\Facades\Notification;3 5 ->route('vonage', '5555555555')6 ->route('slack', '#slack-channel')7 ->route('broadcast', [new Channel('channel-name')])8 ->notify(new InvoicePaid($invoice));
如果您想在向 mail 路由傳送即時通知時提供收件人姓名,您可以提供一個數組,其中電子郵件地址作為鍵,姓名為第一個元素的值。
1Notification::route('mail', [3])->notify(new InvoicePaid($invoice));
使用 routes 方法,您可以一次為多個通知頻道提供即時路由資訊。
1Notification::routes([3 'vonage' => '5555555555',4])->notify(new InvoicePaid($invoice));
郵件通知
格式化郵件訊息
如果通知支援以電子郵件形式傳送,則應在通知類上定義 toMail 方法。此方法接收一個 $notifiable 實體,並應返回一個 Illuminate\Notifications\Messages\MailMessage 例項。
MailMessage 類包含幾個簡單的方法,幫助您構建事務性電子郵件。郵件訊息可以包含文字行以及“號召性用語”(call to action)。讓我們看一個 toMail 方法的例子。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 $url = url('/invoice/'.$this->invoice->id); 7 8 return (new MailMessage) 9 ->greeting('Hello!')10 ->line('One of your invoices has been paid!')11 ->lineIf($this->amount > 0, "Amount paid: {$this->amount}")12 ->action('View Invoice', $url)13 ->line('Thank you for using our application!');14}
請注意,我們在 toMail 方法中使用了 $this->invoice->id。您可以將通知生成訊息所需的任何資料傳遞給通知的建構函式。
在此示例中,我們註冊了一個問候語、一行文字、一個號召性用語,然後是另一行文字。MailMessage 物件提供的這些方法使格式化小型事務性電子郵件變得簡單快捷。郵件頻道隨後會將訊息元件轉換為精美的、響應式的 HTML 郵件模板,並附帶純文字版本。這是由 mail 頻道生成的電子郵件示例。
傳送郵件通知時,請確保在 config/app.php 配置檔案中設定了 name 配置選項。此值將用於郵件通知訊息的頁首和頁尾。
錯誤訊息
一些通知會告知使用者錯誤,例如發票支付失敗。您可以透過在構建訊息時呼叫 error 方法來指示郵件訊息涉及錯誤。當對郵件訊息使用 error 方法時,號召性用語按鈕將變為紅色而不是黑色。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage) 7 ->error() 8 ->subject('Invoice Payment Failed') 9 ->line('...');10}
其他郵件通知格式化選項
除了在通知類中定義文字“行”外,您還可以使用 view 方法來指定用於渲染通知郵件的自定義模板。
1/**2 * Get the mail representation of the notification.3 */4public function toMail(object $notifiable): MailMessage5{6 return (new MailMessage)->view(7 'mail.invoice.paid', ['invoice' => $this->invoice]8 );9}
您可以將檢視名稱作為傳遞給 view 方法的陣列的第二個元素,從而為郵件訊息指定純文字檢視。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage)->view( 7 ['mail.invoice.paid', 'mail.invoice.paid-text'], 8 ['invoice' => $this->invoice] 9 );10}
或者,如果您的訊息僅具有純文字檢視,則可以使用 text 方法。
1/**2 * Get the mail representation of the notification.3 */4public function toMail(object $notifiable): MailMessage5{6 return (new MailMessage)->text(7 'mail.invoice.paid-text', ['invoice' => $this->invoice]8 );9}
自定義發件人
預設情況下,電子郵件的傳送者/發件人地址是在 config/mail.php 配置檔案中定義的。但是,您可以使用 from 方法為特定通知指定發件人地址。
1/**2 * Get the mail representation of the notification.3 */4public function toMail(object $notifiable): MailMessage5{6 return (new MailMessage)8 ->line('...');9}
自定義收件人
透過 mail 頻道傳送通知時,通知系統會自動在您的可通知實體上查詢 email 屬性。您可以透過在可通知實體上定義 routeNotificationForMail 方法來自定義用於傳送通知的電子郵件地址。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Foundation\Auth\User as Authenticatable; 6use Illuminate\Notifications\Notifiable; 7use Illuminate\Notifications\Notification; 8 9class User extends Authenticatable10{11 use Notifiable;12 13 /**14 * Route notifications for the mail channel.15 *16 * @return array<string, string>|string17 */18 public function routeNotificationForMail(Notification $notification): array|string19 {20 // Return email address only...21 return $this->email_address;22 23 // Return email address and name...24 return [$this->email_address => $this->name];25 }26}
自定義主題
預設情況下,電子郵件的主題是格式化為“標題大小寫”的通知類名稱。因此,如果您的通知類名為 InvoicePaid,電子郵件的主題將為 Invoice Paid。如果您想為訊息指定不同的主題,可以在構建訊息時呼叫 subject 方法。
1/**2 * Get the mail representation of the notification.3 */4public function toMail(object $notifiable): MailMessage5{6 return (new MailMessage)7 ->subject('Notification Subject')8 ->line('...');9}
自定義郵件驅動 (Mailer)
預設情況下,郵件通知將使用 config/mail.php 配置檔案中定義的預設郵件驅動傳送。但是,您可以透過在構建訊息時呼叫 mailer 方法在執行時指定不同的郵件驅動。
1/**2 * Get the mail representation of the notification.3 */4public function toMail(object $notifiable): MailMessage5{6 return (new MailMessage)7 ->mailer('postmark')8 ->line('...');9}
自定義模板
您可以透過釋出通知包的資源來修改郵件通知使用的 HTML 和純文字模板。執行此命令後,郵件通知模板將位於 resources/views/vendor/notifications 目錄中。
1php artisan vendor:publish --tag=laravel-notifications
附件
要將附件新增到郵件通知中,請在構建訊息時使用 attach 方法。attach 方法接受檔案的絕對路徑作為其第一個引數。
1/**2 * Get the mail representation of the notification.3 */4public function toMail(object $notifiable): MailMessage5{6 return (new MailMessage)7 ->greeting('Hello!')8 ->attach('/path/to/file');9}
將檔案附加到訊息時,您還可以透過將 array 作為 attach 方法的第二個引數傳遞來指定顯示名稱和/或 MIME 型別。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage) 7 ->greeting('Hello!') 8 ->attach('/path/to/file', [ 9 'as' => 'name.pdf',10 'mime' => 'application/pdf',11 ]);12}
與在 Mailable 物件中附加檔案不同,您不能使用 attachFromStorage 直接從儲存磁碟附加檔案。您應該使用 attach 方法並提供儲存磁碟上檔案的絕對路徑。或者,您可以從 toMail 方法返回一個 mailable。
1use App\Mail\InvoicePaid as InvoicePaidMailable; 2 3/** 4 * Get the mail representation of the notification. 5 */ 6public function toMail(object $notifiable): Mailable 7{ 8 return (new InvoicePaidMailable($this->invoice)) 9 ->to($notifiable->email)10 ->attachFromStorage('/path/to/file');11}
必要時,可以使用 attachMany 方法將多個檔案附加到訊息中。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage) 7 ->greeting('Hello!') 8 ->attachMany([ 9 '/path/to/forge.svg',10 '/path/to/vapor.svg' => [11 'as' => 'Logo.svg',12 'mime' => 'image/svg+xml',13 ],14 ]);15}
原始資料附件
attachData 方法可用於將原始位元組字串作為附件附加。呼叫 attachData 方法時,應提供應分配給附件的檔名。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage) 7 ->greeting('Hello!') 8 ->attachData($this->pdf, 'name.pdf', [ 9 'mime' => 'application/pdf',10 ]);11}
新增標籤和元資料
某些第三方電子郵件提供商(如 Mailgun 和 Postmark)支援訊息“標籤”和“元資料”,可用於對應用程式傳送的電子郵件進行分組和跟蹤。您可以透過 tag 和 metadata 方法將標籤和元資料新增到電子郵件訊息中。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage) 7 ->greeting('Comment Upvoted!') 8 ->tag('upvote') 9 ->metadata('comment_id', $this->comment->id);10}
如果您的應用程式正在使用 Mailgun 驅動程式,您可以查閱 Mailgun 的文件以獲取有關標籤和元資料的更多資訊。同樣,也可以查閱 Postmark 的文件,以獲取有關其對標籤和元資料支援的更多資訊。
如果您的應用程式正在使用 Amazon SES 傳送電子郵件,則應使用 metadata 方法將 SES “標籤”附加到訊息中。
自定義 Symfony 訊息
MailMessage 類的 withSymfonyMessage 方法允許您註冊一個閉包,該閉包將在傳送訊息之前使用 Symfony 訊息例項被呼叫。這使您有機會在訊息傳送之前對其進行深入自定義。
1use Symfony\Component\Mime\Email; 2 3/** 4 * Get the mail representation of the notification. 5 */ 6public function toMail(object $notifiable): MailMessage 7{ 8 return (new MailMessage) 9 ->withSymfonyMessage(function (Email $message) {10 $message->getHeaders()->addTextHeader(11 'Custom-Header', 'Header Value'12 );13 });14}
使用 Mailable 類
如果需要,您可以從通知的 toMail 方法中返回一個完整的 mailable 物件。當返回 Mailable 而不是 MailMessage 時,您需要使用 mailable 物件的 to 方法指定訊息收件人。
1use App\Mail\InvoicePaid as InvoicePaidMailable; 2use Illuminate\Mail\Mailable; 3 4/** 5 * Get the mail representation of the notification. 6 */ 7public function toMail(object $notifiable): Mailable 8{ 9 return (new InvoicePaidMailable($this->invoice))10 ->to($notifiable->email);11}
Mailables 與即時通知
如果您正在傳送即時通知,提供給 toMail 方法的 $notifiable 例項將是 Illuminate\Notifications\AnonymousNotifiable 的例項,它提供了一個 routeNotificationFor 方法,可用於檢索應向其傳送即時通知的電子郵件地址。
1use App\Mail\InvoicePaid as InvoicePaidMailable; 2use Illuminate\Notifications\AnonymousNotifiable; 3use Illuminate\Mail\Mailable; 4 5/** 6 * Get the mail representation of the notification. 7 */ 8public function toMail(object $notifiable): Mailable 9{10 $address = $notifiable instanceof AnonymousNotifiable11 ? $notifiable->routeNotificationFor('mail')12 : $notifiable->email;13 14 return (new InvoicePaidMailable($this->invoice))15 ->to($address);16}
預覽郵件通知
設計郵件通知模板時,像普通 Blade 模板一樣在瀏覽器中快速預覽渲染後的郵件訊息非常方便。因此,Laravel 允許您直接從路由閉包或控制器中返回郵件通知生成的任何郵件訊息。當返回 MailMessage 時,它將在瀏覽器中渲染並顯示,使您可以快速預覽其設計,而無需將其傳送到實際的電子郵件地址。
1use App\Models\Invoice;2use App\Notifications\InvoicePaid;3 4Route::get('/notification', function () {5 $invoice = Invoice::find(1);6 7 return (new InvoicePaid($invoice))8 ->toMail($invoice->user);9});
Markdown 郵件通知
Markdown 郵件通知允許您利用郵件通知的預構建模板,同時讓您更自由地編寫更長、自定義的訊息。由於訊息是使用 Markdown 編寫的,Laravel 能夠為訊息渲染精美的響應式 HTML 模板,同時自動生成純文字版本。
生成訊息
要生成帶有相應 Markdown 模板的通知,可以使用 make:notification Artisan 命令的 --markdown 選項。
1php artisan make:notification InvoicePaid --markdown=mail.invoice.paid
與其他所有郵件通知一樣,使用 Markdown 模板的通知應在其通知類上定義 toMail 方法。但是,不要使用 line 和 action 方法來構建通知,而是使用 markdown 方法來指定應使用的 Markdown 模板名稱。希望提供給模板的資料陣列可以作為該方法的第二個引數傳遞。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 $url = url('/invoice/'.$this->invoice->id); 7 8 return (new MailMessage) 9 ->subject('Invoice Paid')10 ->markdown('mail.invoice.paid', ['url' => $url]);11}
編寫訊息
Markdown 郵件通知使用 Blade 元件和 Markdown 語法的組合,使您能夠輕鬆構建通知,同時利用 Laravel 預先設計的通知元件。
1<x-mail::message> 2# Invoice Paid 3 4Your invoice has been paid! 5 6<x-mail::button :url="$url"> 7View Invoice 8</x-mail::button> 9 10Thanks,<br>11{{ config('app.name') }}12</x-mail::message>
在編寫 Markdown 電子郵件時,請勿使用過多的縮排。根據 Markdown 標準,Markdown 解析器會將縮排的內容渲染為程式碼塊。
按鈕元件
按鈕元件渲染一個居中的按鈕連結。該元件接受兩個引數:url 和可選的 color。支援的顏色為 primary、green 和 red。您可以根據需要向通知中新增任意數量的按鈕元件。
1<x-mail::button :url="$url" color="green">2View Invoice3</x-mail::button>
面板元件
面板元件在面板中渲染給定的文字塊,該面板的背景顏色與通知其餘部分的背景顏色略有不同。這使您可以引起對給定文字塊的注意。
1<x-mail::panel>2This is the panel content.3</x-mail::panel>
表格元件
表格元件允許您將 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 通知元件匯出到您自己的應用程式中進行自定義。要匯出元件,請使用 vendor:publish Artisan 命令釋出 laravel-mail 資源標籤。
1php 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 元件構建全新的主題,可以將 CSS 檔案放置在 html/themes 目錄中。命名並儲存 CSS 檔案後,更新 mail 配置檔案的 theme 選項以匹配新主題的名稱。
要為單個通知自定義主題,可以在構建通知的郵件訊息時呼叫 theme 方法。theme 方法接受傳送通知時應使用的主題名稱。
1/** 2 * Get the mail representation of the notification. 3 */ 4public function toMail(object $notifiable): MailMessage 5{ 6 return (new MailMessage) 7 ->theme('invoice') 8 ->subject('Invoice Paid') 9 ->markdown('mail.invoice.paid', ['url' => $url]);10}
資料庫通知
前置條件
database 通知頻道將通知資訊儲存在資料庫表中。該表將包含諸如通知型別之類的資訊,以及描述通知的 JSON 資料結構。
您可以查詢該表以在應用程式的使用者介面中顯示通知。但是,在執行此操作之前,您需要建立一個數據庫表來儲存您的通知。您可以使用 make:notifications-table 命令生成具有正確表結構的遷移。
1php artisan make:notifications-table2 3php artisan migrate
如果您的可通知模型正在使用 UUID 或 ULID 主鍵,則應在通知表遷移中將 morphs 方法替換為 uuidMorphs 或 ulidMorphs。
格式化資料庫通知
如果通知支援儲存在資料庫表中,則應在通知類上定義 toDatabase 或 toArray 方法。此方法將接收一個 $notifiable 實體,並應返回一個普通的 PHP 陣列。返回的陣列將被編碼為 JSON 並存儲在 notifications 表的 data 列中。讓我們看一個 toArray 方法的例子。
1/** 2 * Get the array representation of the notification. 3 * 4 * @return array<string, mixed> 5 */ 6public function toArray(object $notifiable): array 7{ 8 return [ 9 'invoice_id' => $this->invoice->id,10 'amount' => $this->invoice->amount,11 ];12}
當通知儲存在應用程式的資料庫中時,type 列預設設定為通知的類名,read_at 列將為 null。但是,您可以透過在通知類中定義 databaseType 和 initialDatabaseReadAtValue 方法來自定義此行為。
1use Illuminate\Support\Carbon; 2 3/** 4 * Get the notification's database type. 5 */ 6public function databaseType(object $notifiable): string 7{ 8 return 'invoice-paid'; 9}10 11/**12 * Get the initial value for the "read_at" column.13 */14public function initialDatabaseReadAtValue(): ?Carbon15{16 return null;17}
toDatabase 與 toArray
toArray 方法也由 broadcast 頻道使用,以確定要廣播到 JavaScript 前端的資料。如果您希望 database 和 broadcast 頻道有兩種不同的陣列表示,則應定義 toDatabase 方法而不是 toArray 方法。
訪問通知
一旦通知儲存在資料庫中,您就需要一種方便的方式從可通知實體訪問它們。Laravel 預設的 App\Models\User 模型中包含的 Illuminate\Notifications\Notifiable trait 包括一個 notifications Eloquent 關係,該關係返回該實體的通知。要獲取通知,您可以像使用任何其他 Eloquent 關係一樣訪問此方法。預設情況下,通知將按 created_at 時間戳排序,最近的通知排在集合的前面。
1$user = App\Models\User::find(1);2 3foreach ($user->notifications as $notification) {4 echo $notification->type;5}
如果您只想檢索“未讀”通知,可以使用 unreadNotifications 關係。同樣,這些通知將按 created_at 時間戳排序,最近的通知排在集合的前面。
1$user = App\Models\User::find(1);2 3foreach ($user->unreadNotifications as $notification) {4 echo $notification->type;5}
如果您只想檢索“已讀”通知,可以使用 readNotifications 關係。
1$user = App\Models\User::find(1);2 3foreach ($user->readNotifications as $notification) {4 echo $notification->type;5}
要從 JavaScript 客戶端訪問您的通知,您應該為您的應用程式定義一個通知控制器,該控制器返回可通知實體的通知(例如當前使用者)。然後,您可以從 JavaScript 客戶端向該控制器的 URL 發出 HTTP 請求。
標記通知為已讀
通常,您希望在使用者檢視通知時將其標記為“已讀”。Illuminate\Notifications\Notifiable trait 提供了一個 markAsRead 方法,該方法會更新通知資料庫記錄上的 read_at 列。
1$user = App\Models\User::find(1);2 3foreach ($user->unreadNotifications as $notification) {4 $notification->markAsRead();5}
但是,您無需迴圈遍歷每個通知,而是可以直接在通知集合上使用 markAsRead 方法。
1$user->unreadNotifications->markAsRead();
您還可以使用批次更新查詢來將所有通知標記為已讀,而無需從資料庫中檢索它們。
1$user = App\Models\User::find(1);2 3$user->unreadNotifications()->update(['read_at' => now()]);
您可以 delete 通知以將其完全從表中移除。
1$user->notifications()->delete();
廣播通知
前置條件
在廣播通知之前,您應該配置並熟悉 Laravel 的事件廣播服務。事件廣播提供了一種從 JavaScript 前端響應伺服器端 Laravel 事件的方法。
格式化廣播通知
broadcast 頻道使用 Laravel 的事件廣播服務廣播通知,允許您的 JavaScript 前端即時捕獲通知。如果通知支援廣播,則可以在通知類上定義 toBroadcast 方法。此方法接收一個 $notifiable 實體,並應返回一個 BroadcastMessage 例項。如果 toBroadcast 方法不存在,則將使用 toArray 方法來收集應廣播的資料。返回的資料將被編碼為 JSON 並廣播到您的 JavaScript 前端。讓我們看一個 toBroadcast 方法的例子。
1use Illuminate\Notifications\Messages\BroadcastMessage; 2 3/** 4 * Get the broadcastable representation of the notification. 5 */ 6public function toBroadcast(object $notifiable): BroadcastMessage 7{ 8 return new BroadcastMessage([ 9 'invoice_id' => $this->invoice->id,10 'amount' => $this->invoice->amount,11 ]);12}
廣播佇列配置
所有廣播通知都會加入佇列以進行廣播。如果您想配置用於廣播操作的佇列連線或佇列名稱,可以使用 BroadcastMessage 的 onConnection 和 onQueue 方法。
1return (new BroadcastMessage($data))2 ->onConnection('sqs')3 ->onQueue('broadcasts');
自定義通知型別
除了您指定的資料外,所有廣播通知都有一個 type 欄位,其中包含通知的完整類名。如果您想自定義通知 type,可以在通知類上定義 broadcastType 方法。
1/**2 * Get the type of the notification being broadcast.3 */4public function broadcastType(): string5{6 return 'broadcast.message';7}
監聽通知
通知將透過使用 {notifiable}.{id} 約定格式化的私有頻道進行廣播。因此,如果您要向 ID 為 1 的 App\Models\User 例項傳送通知,則通知將在 App.Models.User.1 私有頻道上廣播。使用 Laravel Echo 時,可以使用 notification 方法輕鬆監聽頻道上的通知。
1Echo.private('App.Models.User.' + userId)2 .notification((notification) => {3 console.log(notification.type);4 });
使用 React 或 Vue
Laravel Echo 包含 React 和 Vue 鉤子,使監聽通知變得輕鬆。首先,呼叫 useEchoNotification 鉤子來監聽通知。當消費元件解除安裝時,useEchoNotification 鉤子會自動退出頻道。
1import { useEchoNotification } from "@laravel/echo-react";2 3useEchoNotification(4 `App.Models.User.${userId}`,5 (notification) => {6 console.log(notification.type);7 },8);
1<script setup lang="ts"> 2import { useEchoNotification } from "@laravel/echo-vue"; 3 4useEchoNotification( 5 `App.Models.User.${userId}`, 6 (notification) => { 7 console.log(notification.type); 8 }, 9);10</script>
預設情況下,鉤子會監聽所有通知。要指定您想要監聽的通知型別,可以向 useEchoNotification 提供字串或型別陣列。
1import { useEchoNotification } from "@laravel/echo-react";2 3useEchoNotification(4 `App.Models.User.${userId}`,5 (notification) => {6 console.log(notification.type);7 },8 'App.Notifications.InvoicePaid',9);
1<script setup lang="ts"> 2import { useEchoNotification } from "@laravel/echo-vue"; 3 4useEchoNotification( 5 `App.Models.User.${userId}`, 6 (notification) => { 7 console.log(notification.type); 8 }, 9 'App.Notifications.InvoicePaid',10);11</script>
您還可以指定通知載荷資料的形狀,從而提供更高的型別安全性和編輯便利性。
1type InvoicePaidNotification = { 2 invoice_id: number; 3 created_at: string; 4}; 5 6useEchoNotification<InvoicePaidNotification>( 7 `App.Models.User.${userId}`, 8 (notification) => { 9 console.log(notification.invoice_id);10 console.log(notification.created_at);11 console.log(notification.type);12 },13 'App.Notifications.InvoicePaid',14);
自定義通知頻道
如果您想自定義實體廣播通知的廣播頻道,可以在可通知實體上定義 receivesBroadcastNotificationsOn 方法。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Broadcasting\PrivateChannel; 6use Illuminate\Foundation\Auth\User as Authenticatable; 7use Illuminate\Notifications\Notifiable; 8 9class User extends Authenticatable10{11 use Notifiable;12 13 /**14 * The channels the user receives notification broadcasts on.15 */16 public function receivesBroadcastNotificationsOn(): string17 {18 return 'users.'.$this->id;19 }20}
簡訊通知
前置條件
在 Laravel 中傳送簡訊通知由 Vonage(原名 Nexmo)提供支援。在透過 Vonage 傳送通知之前,您需要安裝 laravel/vonage-notification-channel 和 guzzlehttp/guzzle 包。
1composer require laravel/vonage-notification-channel guzzlehttp/guzzle
該包包含一個配置檔案。但是,您無需將此配置檔案匯出到您自己的應用程式中。您只需使用 VONAGE_KEY 和 VONAGE_SECRET 環境變數來定義您的 Vonage 公鑰和私鑰即可。
定義金鑰後,您應設定一個 VONAGE_SMS_FROM 環境變數,該變數定義了預設傳送簡訊訊息的電話號碼。您可以在 Vonage 控制面板中生成此電話號碼。
1VONAGE_SMS_FROM=15556666666
格式化簡訊通知
如果通知支援以簡訊形式傳送,則應在通知類上定義 toVonage 方法。此方法接收一個 $notifiable 實體,並應返回一個 Illuminate\Notifications\Messages\VonageMessage 例項。
1use Illuminate\Notifications\Messages\VonageMessage; 2 3/** 4 * Get the Vonage / SMS representation of the notification. 5 */ 6public function toVonage(object $notifiable): VonageMessage 7{ 8 return (new VonageMessage) 9 ->content('Your SMS message content');10}
Unicode 內容
如果您的簡訊訊息將包含 Unicode 字元,則在構建 VonageMessage 例項時應呼叫 unicode 方法。
1use Illuminate\Notifications\Messages\VonageMessage; 2 3/** 4 * Get the Vonage / SMS representation of the notification. 5 */ 6public function toVonage(object $notifiable): VonageMessage 7{ 8 return (new VonageMessage) 9 ->content('Your unicode message')10 ->unicode();11}
自定義“發件人”號碼
如果您想從不同於 VONAGE_SMS_FROM 環境變數指定的電話號碼傳送某些通知,可以在 VonageMessage 例項上呼叫 from 方法。
1use Illuminate\Notifications\Messages\VonageMessage; 2 3/** 4 * Get the Vonage / SMS representation of the notification. 5 */ 6public function toVonage(object $notifiable): VonageMessage 7{ 8 return (new VonageMessage) 9 ->content('Your SMS message content')10 ->from('15554443333');11}
新增客戶參考號
如果您想跟蹤每個使用者、團隊或客戶的成本,可以向通知新增“客戶參考號”。Vonage 將允許您使用此客戶參考號生成報告,以便您更好地瞭解特定客戶的簡訊使用情況。客戶參考號可以是最多 40 個字元的任何字串。
1use Illuminate\Notifications\Messages\VonageMessage; 2 3/** 4 * Get the Vonage / SMS representation of the notification. 5 */ 6public function toVonage(object $notifiable): VonageMessage 7{ 8 return (new VonageMessage) 9 ->clientReference((string) $notifiable->id)10 ->content('Your SMS message content');11}
路由簡訊通知
要將 Vonage 通知路由到正確的電話號碼,請在您的可通知實體上定義 routeNotificationForVonage 方法。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Foundation\Auth\User as Authenticatable; 6use Illuminate\Notifications\Notifiable; 7use Illuminate\Notifications\Notification; 8 9class User extends Authenticatable10{11 use Notifiable;12 13 /**14 * Route notifications for the Vonage channel.15 */16 public function routeNotificationForVonage(Notification $notification): string17 {18 return $this->phone_number;19 }20}
Slack 通知
前置條件
在傳送 Slack 通知之前,您應該透過 Composer 安裝 Slack 通知頻道。
1composer require laravel/slack-notification-channel
此外,您必須為您的 Slack 工作區建立一個 Slack App。
如果您只需要向建立 App 的同一個 Slack 工作區傳送通知,則應確保您的 App 擁有 chat:write、chat:write.public 和 chat:write.customize 作用域。這些作用域可以從 Slack 中的“OAuth & Permissions”App 管理選項卡新增。
接下來,複製 App 的“Bot User OAuth Token”並將其放入應用程式 services.php 配置檔案中的 slack 配置陣列中。此令牌可以在 Slack 中的“OAuth & Permissions”選項卡上找到。
1'slack' => [2 'notifications' => [3 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),4 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),5 ],6],
App 分發
如果您的應用程式將向由您的應用程式使用者擁有的外部 Slack 工作區傳送通知,則需要透過 Slack “分發”您的 App。App 分發可以從 Slack 中 App 的“Manage Distribution”選項卡進行管理。一旦您的 App 被分發,您就可以使用 Socialite 代表您的應用程式使用者獲取 Slack Bot 令牌。
格式化 Slack 通知
如果通知支援以 Slack 訊息形式傳送,則應在通知類上定義 toSlack 方法。此方法接收一個 $notifiable 實體,並應返回一個 Illuminate\Notifications\Slack\SlackMessage 例項。您可以使用 Slack 的 Block Kit API 構建豐富的通知。以下示例可以在 Slack 的 Block Kit builder 中進行預覽。
1use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock; 2use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock; 3use Illuminate\Notifications\Slack\SlackMessage; 4 5/** 6 * Get the Slack representation of the notification. 7 */ 8public function toSlack(object $notifiable): SlackMessage 9{10 return (new SlackMessage)11 ->text('One of your invoices has been paid!')12 ->headerBlock('Invoice Paid')13 ->contextBlock(function (ContextBlock $block) {14 $block->text('Customer #1234');15 })16 ->sectionBlock(function (SectionBlock $block) {17 $block->text('An invoice has been paid.');18 $block->field("*Invoice No:*\n1000")->markdown();20 })21 ->dividerBlock()22 ->sectionBlock(function (SectionBlock $block) {23 $block->text('Congratulations!');24 });25}
使用 Slack 的 Block Kit Builder 模板
除了使用流暢的訊息構建器方法來構建您的 Block Kit 訊息外,您還可以將 Slack 的 Block Kit Builder 生成的原始 JSON 載荷提供給 usingBlockKitTemplate 方法。
1use Illuminate\Notifications\Slack\SlackMessage; 2use Illuminate\Support\Str; 3 4/** 5 * Get the Slack representation of the notification. 6 */ 7public function toSlack(object $notifiable): SlackMessage 8{ 9 $template = <<<JSON10 {11 "blocks": [12 {13 "type": "header",14 "text": {15 "type": "plain_text",16 "text": "Team Announcement"17 }18 },19 {20 "type": "section",21 "text": {22 "type": "plain_text",23 "text": "We are hiring!"24 }25 }26 ]27 }28 JSON;29 30 return (new SlackMessage)31 ->usingBlockKitTemplate($template);32}
Slack 互動性
Slack 的 Block Kit 通知系統提供了強大的功能來處理使用者互動。要利用這些功能,您的 Slack App 應啟用“Interactivity”,並配置一個指向您的應用程式提供的 URL 的“Request URL”。這些設定可以從 Slack 中 App 的“Interactivity & Shortcuts”管理選項卡進行管理。
在以下使用 actionsBlock 方法的示例中,Slack 將向您的“Request URL”傳送一個 POST 請求,其中包含點選按鈕的 Slack 使用者、點選按鈕的 ID 等載荷。然後,您的應用程式可以根據載荷確定要採取的行動。您還應該驗證該請求是由 Slack 發出的。
1use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock; 2use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock; 3use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock; 4use Illuminate\Notifications\Slack\SlackMessage; 5 6/** 7 * Get the Slack representation of the notification. 8 */ 9public function toSlack(object $notifiable): SlackMessage10{11 return (new SlackMessage)12 ->text('One of your invoices has been paid!')13 ->headerBlock('Invoice Paid')14 ->contextBlock(function (ContextBlock $block) {15 $block->text('Customer #1234');16 })17 ->sectionBlock(function (SectionBlock $block) {18 $block->text('An invoice has been paid.');19 })20 ->actionsBlock(function (ActionsBlock $block) {21 // ID defaults to "button_acknowledge_invoice"...22 $block->button('Acknowledge Invoice')->primary();23 24 // Manually configure the ID...25 $block->button('Deny')->danger()->id('deny_invoice');26 });27}
確認模態
如果您希望使用者在執行操作前必須確認操作,可以在定義按鈕時呼叫 confirm 方法。confirm 方法接受訊息和一個接收 ConfirmObject 例項的閉包。
1use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock; 2use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock; 3use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock; 4use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject; 5use Illuminate\Notifications\Slack\SlackMessage; 6 7/** 8 * Get the Slack representation of the notification. 9 */10public function toSlack(object $notifiable): SlackMessage11{12 return (new SlackMessage)13 ->text('One of your invoices has been paid!')14 ->headerBlock('Invoice Paid')15 ->contextBlock(function (ContextBlock $block) {16 $block->text('Customer #1234');17 })18 ->sectionBlock(function (SectionBlock $block) {19 $block->text('An invoice has been paid.');20 })21 ->actionsBlock(function (ActionsBlock $block) {22 $block->button('Acknowledge Invoice')23 ->primary()24 ->confirm(25 'Acknowledge the payment and send a thank you email?',26 function (ConfirmObject $dialog) {27 $dialog->confirm('Yes');28 $dialog->deny('No');29 }30 );31 });32}
檢查 Slack Blocks
如果您想快速檢查您一直在構建的塊,可以在 SlackMessage 例項上呼叫 dd 方法。dd 方法將生成並 dump 一個 URL 到 Slack 的 Block Kit Builder,它會在瀏覽器中顯示載荷和通知的預覽。您可以將 true 傳遞給 dd 方法以 dump 原始載荷。
1return (new SlackMessage)2 ->text('One of your invoices has been paid!')3 ->headerBlock('Invoice Paid')4 ->dd();
路由 Slack 通知
要將 Slack 通知定向到適當的 Slack 團隊和頻道,請在您的可通知模型上定義 routeNotificationForSlack 方法。此方法可以返回三個值之一:
null- 將路由推遲到通知本身中配置的頻道。您可以使用SlackMessage構建時的to方法來配置通知內的頻道。- 指定要向其傳送通知的 Slack 頻道的字串,例如
#support-channel。 SlackRoute例項,它允許您指定 OAuth 令牌和頻道名稱,例如SlackRoute::make($this->slack_channel, $this->slack_token)。此方法應用於向外部工作區傳送通知。
例如,從 routeNotificationForSlack 方法返回 #support-channel 將把通知傳送到與應用程式 services.php 配置檔案中定義的 Bot User OAuth 令牌關聯的工作區中的 #support-channel 頻道。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Foundation\Auth\User as Authenticatable; 6use Illuminate\Notifications\Notifiable; 7use Illuminate\Notifications\Notification; 8 9class User extends Authenticatable10{11 use Notifiable;12 13 /**14 * Route notifications for the Slack channel.15 */16 public function routeNotificationForSlack(Notification $notification): mixed17 {18 return '#support-channel';19 }20}
通知外部 Slack 工作區
在向外部 Slack 工作區傳送通知之前,您的 Slack App 必須被分發。
當然,您通常會希望向您的應用程式使用者擁有的 Slack 工作區傳送通知。為此,您首先需要獲取使用者的 Slack OAuth 令牌。值得慶幸的是,Laravel Socialite 包含一個 Slack 驅動程式,允許您輕鬆地使用 Slack 對應用程式使用者進行身份驗證並獲取 Bot 令牌。
一旦您獲得了 Bot 令牌並將其儲存在應用程式的資料庫中,您就可以使用 SlackRoute::make 方法將通知路由到使用者的工作區。此外,您的應用程式可能需要提供機會讓使用者指定應將通知傳送到哪個頻道。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Foundation\Auth\User as Authenticatable; 6use Illuminate\Notifications\Notifiable; 7use Illuminate\Notifications\Notification; 8use Illuminate\Notifications\Slack\SlackRoute; 9 10class User extends Authenticatable11{12 use Notifiable;13 14 /**15 * Route notifications for the Slack channel.16 */17 public function routeNotificationForSlack(Notification $notification): mixed18 {19 return SlackRoute::make($this->slack_channel, $this->slack_token);20 }21}
本地化通知
Laravel 允許您以 HTTP 請求當前區域設定以外的區域設定傳送通知,如果通知是排隊的,它甚至會記住此區域設定。
為此,Illuminate\Notifications\Notification 類提供了一個 locale 方法來設定所需的語言。當評估通知時,應用程式將切換到此區域設定,並在評估完成後還原回之前的區域設定。
1$user->notify((new InvoicePaid($invoice))->locale('es'));
多個可通知實體的本地化也可以透過 Notification 門面實現。
1Notification::locale('es')->send(2 $users, new InvoicePaid($invoice)3);
使用者首選區域設定
有時,應用程式會儲存每個使用者的首選區域設定。透過在可通知模型上實現 HasLocalePreference 契約,您可以指示 Laravel 在傳送通知時使用此儲存的區域設定。
1use Illuminate\Contracts\Translation\HasLocalePreference; 2 3class User extends Model implements HasLocalePreference 4{ 5 /** 6 * Get the user's preferred locale. 7 */ 8 public function preferredLocale(): string 9 {10 return $this->locale;11 }12}
一旦實現了該介面,Laravel 在向模型傳送通知和 mailable 時將自動使用首選區域設定。因此,使用此介面時無需呼叫 locale 方法。
1$user->notify(new InvoicePaid($invoice));
測試
您可以使用 Notification 門面的 fake 方法來防止傳送通知。通常,傳送通知與您實際測試的程式碼無關。很可能,只需斷言 Laravel 已被指示傳送給定的通知就足夠了。
呼叫 Notification 門面的 fake 方法後,您可以斷言已指示將通知傳送給使用者,甚至可以檢查通知收到的資料。
1<?php 2 3use App\Notifications\OrderShipped; 4use Illuminate\Support\Facades\Notification; 5 6test('orders can be shipped', function () { 7 Notification::fake(); 8 9 // Perform order shipping...10 11 // Assert that no notifications were sent...12 Notification::assertNothingSent();13 14 // Assert a notification was sent to the given users...15 Notification::assertSentTo(16 [$user], OrderShipped::class17 );18 19 // Assert a notification was not sent...20 Notification::assertNotSentTo(21 [$user], AnotherNotification::class22 );23 24 // Assert a notification was sent twice...25 Notification::assertSentTimes(WeeklyReminder::class, 2);26 27 // Assert that a given number of notifications were sent...28 Notification::assertCount(3);29});
1<?php 2 3namespace Tests\Feature; 4 5use App\Notifications\OrderShipped; 6use Illuminate\Support\Facades\Notification; 7use Tests\TestCase; 8 9class ExampleTest extends TestCase10{11 public function test_orders_can_be_shipped(): void12 {13 Notification::fake();14 15 // Perform order shipping...16 17 // Assert that no notifications were sent...18 Notification::assertNothingSent();19 20 // Assert a notification was sent to the given users...21 Notification::assertSentTo(22 [$user], OrderShipped::class23 );24 25 // Assert a notification was not sent...26 Notification::assertNotSentTo(27 [$user], AnotherNotification::class28 );29 30 // Assert a notification was sent twice...31 Notification::assertSentTimes(WeeklyReminder::class, 2);32 33 // Assert that a given number of notifications were sent...34 Notification::assertCount(3);35 }36}
您可以將閉包傳遞給 assertSentTo 或 assertNotSentTo 方法,以斷言傳送了一個透過給定“真值測試”的通知。如果至少有一個通知傳送並通過了給定的真值測試,則斷言將成功。
1Notification::assertSentTo(2 $user,3 function (OrderShipped $notification, array $channels) use ($order) {4 return $notification->order->id === $order->id;5 }6);
按需通知 (On-Demand Notifications)
如果您測試的程式碼傳送了即時通知,則可以透過 assertSentOnDemand 方法測試是否傳送了即時通知。
1Notification::assertSentOnDemand(OrderShipped::class);
透過將閉包作為 assertSentOnDemand 方法的第二個引數傳遞,您可以確定是否向正確的“路由”地址傳送了即時通知。
1Notification::assertSentOnDemand(2 OrderShipped::class,3 function (OrderShipped $notification, array $channels, object $notifiable) use ($user) {4 return $notifiable->routes['mail'] === $user->email;5 }6);
通知事件
通知傳送事件
當通知正在傳送時,Illuminate\Notifications\Events\NotificationSending 事件由通知系統分發。這包含“可通知”實體和通知例項本身。您可以在應用程式中為此事件建立事件監聽器。
1use Illuminate\Notifications\Events\NotificationSending; 2 3class CheckNotificationStatus 4{ 5 /** 6 * Handle the event. 7 */ 8 public function handle(NotificationSending $event): void 9 {10 // ...11 }12}
如果 NotificationSending 事件的事件監聽器從其 handle 方法返回 false,則不會發送通知。
1/**2 * Handle the event.3 */4public function handle(NotificationSending $event): bool5{6 return false;7}
在事件監聽器內,您可以訪問事件上的 notifiable、notification 和 channel 屬性,以瞭解有關通知接收者或通知本身的更多資訊。
1/**2 * Handle the event.3 */4public function handle(NotificationSending $event): void5{6 // $event->channel7 // $event->notifiable8 // $event->notification9}
通知已傳送事件
當通知已傳送時,Illuminate\Notifications\Events\NotificationSent 事件由通知系統分發。這包含“可通知”實體和通知例項本身。您可以在應用程式中為此事件建立事件監聽器。
1use Illuminate\Notifications\Events\NotificationSent; 2 3class LogNotification 4{ 5 /** 6 * Handle the event. 7 */ 8 public function handle(NotificationSent $event): void 9 {10 // ...11 }12}
在事件監聽器內,您可以訪問事件上的 notifiable、notification、channel 和 response 屬性,以瞭解有關通知接收者或通知本身的更多資訊。
1/** 2 * Handle the event. 3 */ 4public function handle(NotificationSent $event): void 5{ 6 // $event->channel 7 // $event->notifiable 8 // $event->notification 9 // $event->response10}
自定義頻道
Laravel 自帶少量通知頻道,但您可能想編寫自己的驅動程式來透過其他頻道傳送通知。Laravel 使其變得簡單。首先,定義一個包含 send 方法的類。該方法應接收兩個引數:$notifiable 和 $notification。
在 send 方法中,您可以呼叫通知上的方法來檢索您的頻道理解的訊息物件,然後以任何您希望的方式將通知傳送給 $notifiable 例項。
1<?php 2 3namespace App\Notifications; 4 5use Illuminate\Notifications\Notification; 6 7class VoiceChannel 8{ 9 /**10 * Send the given notification.11 */12 public function send(object $notifiable, Notification $notification): void13 {14 $message = $notification->toVoice($notifiable);15 16 // Send notification to the $notifiable instance...17 }18}
一旦定義了通知頻道類,您就可以從任何通知的 via 方法返回該類名。在此示例中,通知的 toVoice 方法可以返回您選擇用來表示語音訊息的任何物件。例如,您可以定義自己的 VoiceMessage 類來表示這些訊息。
1<?php 2 3namespace App\Notifications; 4 5use App\Notifications\Messages\VoiceMessage; 6use App\Notifications\VoiceChannel; 7use Illuminate\Bus\Queueable; 8use Illuminate\Contracts\Queue\ShouldQueue; 9use Illuminate\Notifications\Notification;10 11class InvoicePaid extends Notification12{13 use Queueable;14 15 /**16 * Get the notification channels.17 */18 public function via(object $notifiable): string19 {20 return VoiceChannel::class;21 }22 23 /**24 * Get the voice representation of the notification.25 */26 public function toVoice(object $notifiable): VoiceMessage27 {28 // ...29 }30}