通知
簡介
除了支援傳送電子郵件之外,Laravel 還支援透過各種傳遞管道傳送通知,包括電子郵件、簡訊(透過 Vonage,以前稱為 Nexmo)和 Slack。此外,還建立各種社群建構的通知管道,以透過數十種不同的管道傳送通知!通知也可以儲存在資料庫中,以便在您的 Web 介面中顯示。
一般來說,通知應為簡短的資訊訊息,通知使用者您的應用程式中發生的某些事件。例如,如果您正在編寫計費應用程式,您可能會透過電子郵件和簡訊管道向使用者傳送「發票已付款」通知。
產生通知
在 Laravel 中,每個通知都由一個單一類別表示,通常儲存在 app/Notifications
目錄中。如果您在應用程式中沒有看到此目錄,請不要擔心 - 當您執行 make:notification
Artisan 命令時,會為您建立此目錄
php artisan make:notification InvoicePaid
此命令會在您的 app/Notifications
目錄中放置一個全新的通知類別。每個通知類別都包含一個 via
方法和可變數量的訊息建構方法,例如 toMail
或 toDatabase
,這些方法會將通知轉換為針對特定管道量身定制的訊息。
傳送通知
使用 Notifiable Trait
通知可以使用兩種方式傳送:使用 Notifiable
trait 的 notify
方法或使用 Notification
facade。 Notifiable
trait 預設包含在您的應用程式 App\Models\User
模型中
<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable;use Illuminate\Notifications\Notifiable; class User extends Authenticatable{ use Notifiable;}
此 trait 提供的 notify
方法預期接收通知實例
use App\Notifications\InvoicePaid; $user->notify(new InvoicePaid($invoice));
請記住,您可以在任何模型上使用 Notifiable
trait。您不僅限於僅在 User
模型上包含它。
使用 Notification Facade
或者,您也可以透過 Notification
facade 傳送通知。當您需要向多個可通知的實體(例如使用者集合)傳送通知時,此方法非常有用。若要使用 facade 傳送通知,請將所有可通知的實體和通知實例傳遞至 send
方法
use Illuminate\Support\Facades\Notification; Notification::send($users, new InvoicePaid($invoice));
您也可以使用 sendNow
方法立即傳送通知。即使通知實作了 ShouldQueue
介面,此方法也會立即傳送通知
Notification::sendNow($developers, new DeploymentCompleted($deployment));
指定傳遞管道
每個通知類別都有一個 via
方法,可決定在哪些管道上傳遞通知。通知可以透過 mail
、database
、broadcast
、vonage
和 slack
管道傳送。
如果您想使用其他傳遞管道,例如 Telegram 或 Pusher,請查看社群驅動的 Laravel 通知管道網站。
via
方法接收一個 $notifiable
實例,它將是接收通知的類別實例。您可以使用 $notifiable
來決定應該在哪些管道上傳遞通知
/** * Get the notification's delivery channels. * * @return array<int, string> */public function via(object $notifiable): array{ return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];}
佇列通知
在將通知加入佇列之前,您應該設定佇列並啟動工作程序。
傳送通知可能需要時間,尤其是在管道需要進行外部 API 呼叫以傳遞通知時。若要加快應用程式的響應時間,請將 ShouldQueue
介面和 Queueable
trait 新增至您的類別,以將您的通知加入佇列。對於使用 make:notification
命令產生的所有通知,介面和 trait 都已匯入,因此您可以立即將它們新增至您的通知類別
<?php namespace App\Notifications; use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue{ use Queueable; // ...}
將 ShouldQueue
介面新增至您的通知後,您可以像平常一樣傳送通知。Laravel 將偵測類別上的 ShouldQueue
介面,並自動將通知的傳遞加入佇列
$user->notify(new InvoicePaid($invoice));
在將通知加入佇列時,會為每個收件者和管道組合建立佇列工作。例如,如果您的通知有三個收件者和兩個管道,則會將六個工作分派到佇列。
延遲通知
如果您想要延遲通知的傳遞,您可以將 delay
方法鏈結到您的通知實例化
$delay = now()->addMinutes(10); $user->notify((new InvoicePaid($invoice))->delay($delay));
您可以將陣列傳遞至 delay
方法,以指定特定管道的延遲時間
$user->notify((new InvoicePaid($invoice))->delay([ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10),]));
或者,您可以在通知類別本身上定義 withDelay
方法。withDelay
方法應傳回管道名稱和延遲值的陣列
/** * Determine the notification's delivery delay. * * @return array<string, \Illuminate\Support\Carbon> */public function withDelay(object $notifiable): array{ return [ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10), ];}
自訂通知佇列連線
依預設,佇列通知將使用您應用程式的預設佇列連線加入佇列。如果您想要指定應該用於特定通知的不同連線,您可以從通知的建構子中呼叫 onConnection
方法
<?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; /** * Create a new notification instance. */ public function __construct() { $this->onConnection('redis'); }}
或者,如果你想為通知支援的每個通知管道指定一個特定的佇列連線,你可以在你的通知上定義一個 viaConnections
方法。此方法應返回一個管道名稱/佇列連線名稱的配對陣列。
/** * Determine which connections should be used for each notification channel. * * @return array<string, string> */public function viaConnections(): array{ return [ 'mail' => 'redis', 'database' => 'sync', ];}
自訂通知管道佇列
如果你想為通知支援的每個通知管道指定一個特定的佇列,你可以在你的通知上定義一個 viaQueues
方法。此方法應返回一個管道名稱/佇列名稱的配對陣列。
/** * Determine which queues should be used for each notification channel. * * @return array<string, string> */public function viaQueues(): array{ return [ 'mail' => 'mail-queue', 'slack' => 'slack-queue', ];}
佇列通知中介層
佇列通知可以定義中介層,就像佇列任務一樣。首先,在你的通知類別中定義一個 middleware
方法。middleware
方法將接收 $notifiable
和 $channel
變數,讓你根據通知的目的地自訂返回的中介層。
use Illuminate\Queue\Middleware\RateLimited; /** * Get the middleware the notification job should pass through. * * @return array<int, object> */public function middleware(object $notifiable, string $channel){ return match ($channel) { 'email' => [new RateLimited('postmark')], 'slack' => [new RateLimited('slack')], default => [], };}
佇列通知與資料庫交易
當佇列通知在資料庫交易中被發送時,它們可能會在資料庫交易提交之前被佇列處理。當這種情況發生時,你在資料庫交易期間對模型或資料庫記錄所做的任何更新可能尚未反映在資料庫中。此外,在交易中建立的任何模型或資料庫記錄可能不存在於資料庫中。如果你的通知依賴這些模型,當處理發送佇列通知的任務時,可能會發生意外錯誤。
如果你的佇列連線的 after_commit
組態選項設定為 false
,你仍然可以透過在發送通知時呼叫 afterCommit
方法,來指示特定的佇列通知應在所有開啟的資料庫交易提交後再發送。
use App\Notifications\InvoicePaid; $user->notify((new InvoicePaid($invoice))->afterCommit());
或者,你可以從通知的建構子中呼叫 afterCommit
方法。
<?php namespace App\Notifications; use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Notifications\Notification; class InvoicePaid extends Notification implements ShouldQueue{ use Queueable; /** * Create a new notification instance. */ public function __construct() { $this->afterCommit(); }}
若要瞭解更多關於解決這些問題的資訊,請查閱關於佇列任務和資料庫交易的文件。
判斷是否應發送佇列通知
在佇列通知被發送到佇列進行背景處理後,它通常會被佇列工作者接收並發送到其預定的收件人。
但是,如果你想在佇列工作者處理後,對是否應發送佇列通知做出最終決定,你可以在通知類別中定義一個 shouldSend
方法。如果此方法返回 false
,則不會發送通知。
/** * Determine if the notification should be sent. */public function shouldSend(object $notifiable, string $channel): bool{ return $this->invoice->isPaid();}
隨需通知
有時你可能需要將通知發送給未儲存為應用程式「使用者」的人。使用 Notification
外觀的 route
方法,你可以在發送通知之前指定臨時的通知路由資訊。
use Illuminate\Broadcasting\Channel;use Illuminate\Support\Facades\Notification; ->route('vonage', '5555555555') ->route('slack', '#slack-channel') ->route('broadcast', [new Channel('channel-name')]) ->notify(new InvoicePaid($invoice));
如果你想在將隨需通知發送到 mail
路由時提供收件人的姓名,你可以提供一個陣列,其中包含電子郵件地址作為鍵,以及姓名作為陣列中第一個元素的值。
Notification::route('mail', [])->notify(new InvoicePaid($invoice));
使用 routes
方法,你可以一次為多個通知管道提供臨時的路由資訊。
Notification::routes([ 'vonage' => '5555555555',])->notify(new InvoicePaid($invoice));
郵件通知
設定郵件訊息格式
如果通知支援以電子郵件形式發送,你應該在通知類別中定義一個 toMail
方法。此方法將接收一個 $notifiable
實體,並應返回一個 Illuminate\Notifications\Messages\MailMessage
實例。
MailMessage
類別包含一些簡單的方法來幫助你建立交易性電子郵件訊息。郵件訊息可能包含多行文字以及「行動呼籲」。讓我們看一下 toMail
方法的範例。
/** * Get the mail representation of the notification. */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!');}
請注意,我們在 toMail
方法中使用 $this->invoice->id
。你可以將通知產生訊息所需的任何資料傳遞到通知的建構子中。
在此範例中,我們註冊了問候語、一行文字、行動呼籲,然後是另一行文字。MailMessage
物件提供的這些方法使格式化小型交易性電子郵件變得簡單快速。然後,郵件管道會將訊息元件轉換為漂亮、具有回應式的 HTML 電子郵件範本,以及純文字副本。以下是 mail
管道產生的電子郵件範例。

發送郵件通知時,請務必在你的 config/app.php
組態檔案中設定 name
組態選項。此值將用於郵件通知訊息的標頭和頁尾。
錯誤訊息
有些通知會通知使用者錯誤,例如付款失敗的發票。你可以透過在建立訊息時呼叫 error
方法,來指示郵件訊息與錯誤相關。當在郵件訊息上使用 error
方法時,行動呼籲按鈕將變為紅色而不是黑色。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->error() ->subject('Invoice Payment Failed') ->line('...');}
其他郵件通知格式化選項
你可以使用 view
方法來指定應使用的自訂範本,以呈現通知電子郵件,而不是在通知類別中定義文字「行」。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage)->view( 'mail.invoice.paid', ['invoice' => $this->invoice] );}
你可以通過傳遞視圖名稱作為提供給 view
方法的陣列的第二個元素,來為郵件訊息指定純文字視圖。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage)->view( ['mail.invoice.paid', 'mail.invoice.paid-text'], ['invoice' => $this->invoice] );}
或者,如果你的訊息只有純文字視圖,你可以使用 text
方法。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage)->text( 'mail.invoice.paid-text', ['invoice' => $this->invoice] );}
自訂寄件者
預設情況下,電子郵件的寄件者/寄件人地址是在 config/mail.php
組態檔案中定義的。但是,你可以使用 from
方法為特定通知指定寄件人地址。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->line('...');}
自訂收件者
透過 mail
管道發送通知時,通知系統會自動在你的可通知實體上尋找 email
屬性。你可以透過在可通知實體上定義一個 routeNotificationForMail
方法,來自訂用於傳遞通知的電子郵件地址。
<?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; /** * Route notifications for the mail channel. * * @return array<string, string>|string */ public function routeNotificationForMail(Notification $notification): array|string { // Return email address only... return $this->email_address; // Return email address and name... return [$this->email_address => $this->name]; }}
自訂主旨
預設情況下,電子郵件的主旨是通知的類別名稱,格式化為「標題大小寫」。因此,如果你的通知類別名為 InvoicePaid
,則電子郵件的主旨將為 Invoice Paid
。如果你想為訊息指定不同的主旨,你可以在建立訊息時呼叫 subject
方法。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->subject('Notification Subject') ->line('...');}
自訂郵件程式
預設情況下,電子郵件通知將使用 config/mail.php
組態檔案中定義的預設郵件程式發送。但是,你可以在建立訊息時呼叫 mailer
方法,在執行時指定不同的郵件程式。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->mailer('postmark') ->line('...');}
自訂樣板
你可以透過發布通知套件的資源,修改郵件通知使用的 HTML 和純文字範本。執行此指令後,郵件通知範本將位於 resources/views/vendor/notifications
目錄中。
php artisan vendor:publish --tag=laravel-notifications
附件
若要將附件新增到電子郵件通知,請在建立訊息時使用 attach
方法。attach
方法接受檔案的絕對路徑作為其第一個引數。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->greeting('Hello!') ->attach('/path/to/file');}
將檔案附加到訊息時,你也可以通過傳遞 array
作為 attach
方法的第二個引數,來指定顯示名稱和/或 MIME 類型。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->greeting('Hello!') ->attach('/path/to/file', [ 'as' => 'name.pdf', 'mime' => 'application/pdf', ]);}
與在可郵寄物件中附加檔案不同,你不能使用 attachFromStorage
直接從儲存磁碟附加檔案。你應該改為使用 attach
方法,使用儲存磁碟上檔案的絕對路徑。或者,你可以從 toMail
方法返回一個 可郵寄物件。
use App\Mail\InvoicePaid as InvoicePaidMailable; /** * Get the mail representation of the notification. */public function toMail(object $notifiable): Mailable{ return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email) ->attachFromStorage('/path/to/file');}
在必要時,可以使用 attachMany
方法將多個檔案附加到訊息。
/** * Get the mail representation of the notification. */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
方法時,應提供應指定給附件的檔案名稱。
/** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->greeting('Hello!') ->attachData($this->pdf, 'name.pdf', [ 'mime' => 'application/pdf', ]);}
新增標籤和中繼資料
某些第三方電子郵件提供者(例如 Mailgun 和 Postmark)支援訊息「標籤」和「中繼資料」,可用於對你的應用程式發送的電子郵件進行分組和追蹤。你可以透過 tag
和 metadata
方法將標籤和中繼資料新增到電子郵件訊息。
/** * Get the mail representation of the notification. */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 實例進行呼叫。這讓你可以在傳遞訊息之前深入自訂訊息。
use Symfony\Component\Mime\Email; /** * Get the mail representation of the notification. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->withSymfonyMessage(function (Email $message) { $message->getHeaders()->addTextHeader( 'Custom-Header', 'Header Value' ); });}
使用 Mailables
如果需要,你可以從通知的 toMail
方法返回完整的可郵寄物件。當返回 Mailable
而不是 MailMessage
時,你將需要使用可郵寄物件的 to
方法來指定訊息的收件人。
use App\Mail\InvoicePaid as InvoicePaidMailable;use Illuminate\Mail\Mailable; /** * Get the mail representation of the notification. */public function toMail(object $notifiable): Mailable{ return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email);}
可郵寄物件和隨需通知
如果你正在發送隨需通知,則提供給 toMail
方法的 $notifiable
實例將是 Illuminate\Notifications\AnonymousNotifiable
的實例,它提供了一個 routeNotificationFor
方法,可用於檢索應發送隨需通知的電子郵件地址。
use App\Mail\InvoicePaid as InvoicePaidMailable;use Illuminate\Notifications\AnonymousNotifiable;use Illuminate\Mail\Mailable; /** * Get the mail representation of the notification. */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
時,它將被呈現並顯示在瀏覽器中,讓你無需將其發送到實際電子郵件地址即可快速預覽其設計。
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
選項。
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid
與所有其他電子郵件通知一樣,使用 Markdown 範本的通知應在其通知類別上定義一個 toMail
方法。但是,不要使用 line
和 action
方法來建構通知,而是使用 markdown
方法來指定應使用的 Markdown 範本名稱。您希望提供給範本使用的資料陣列可以作為該方法的第二個參數傳遞。
/** * Get the mail representation of the notification. */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 預先製作的通知元件。
<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>
按鈕元件
按鈕元件會渲染一個置中的按鈕連結。該元件接受兩個參數,一個 url
和一個可選的 color
。支援的顏色有 primary
、green
和 red
。您可以在通知中添加任意數量的按鈕元件。
<x-mail::button :url="$url" color="green">View Invoice</x-mail::button>
面板元件
面板元件會在面板中渲染給定的文字區塊,該面板的背景顏色與通知的其餘部分略有不同。這讓您可以將注意力集中在給定的文字區塊上。
<x-mail::panel>This is the panel content.</x-mail::panel>
表格元件
表格元件允許您將 Markdown 表格轉換為 HTML 表格。該元件接受 Markdown 表格作為其內容。表格欄位對齊支援使用預設的 Markdown 表格對齊語法。
<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
資產標籤。
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 元件建立全新的主題,您可以將 CSS 檔案放在 html/themes
目錄中。在命名並儲存您的 CSS 檔案後,更新 mail
設定檔的 theme
選項以符合您的新主題名稱。
若要自訂個別通知的主題,您可以在建構通知的郵件訊息時呼叫 theme
方法。theme
方法接受在傳送通知時應使用的主題名稱。
/** * Get the mail representation of the notification. */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
命令來產生具有正確表格結構的遷移。
php artisan make:notifications-table php artisan migrate
如果您的可通知模型正在使用UUID 或 ULID 主鍵,您應該在通知表格遷移中將 morphs
方法替換為uuidMorphs
或 ulidMorphs
。
設定資料庫通知格式
如果通知支援儲存在資料庫表格中,您應該在通知類別上定義一個 toDatabase
或 toArray
方法。此方法將接收一個 $notifiable
實體,並應傳回一個純 PHP 陣列。傳回的陣列將被編碼為 JSON 並儲存在您 notifications
表格的 data
欄位中。讓我們看看一個 toArray
方法的範例。
/** * Get the array representation of the notification. * * @return array<string, mixed> */public function toArray(object $notifiable): array{ return [ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ];}
當通知儲存在您應用程式的資料庫中時,type
欄位將會填入通知的類別名稱。但是,您可以透過在您的通知類別上定義 databaseType
方法來自訂此行為。
/** * Get the notification's database type. * * @return string */public function databaseType(object $notifiable): string{ return 'invoice-paid';}
toDatabase
vs. toArray
toArray
方法也由 broadcast
管道使用,以確定要廣播到您的 JavaScript 前端哪些資料。如果您希望 database
和 broadcast
管道有兩個不同的陣列表示,您應該定義一個 toDatabase
方法而不是 toArray
方法。
存取通知
一旦通知儲存在資料庫中,您需要一種方便的方式從您的可通知實體存取它們。 Illuminate\Notifications\Notifiable
trait (包含在 Laravel 的預設 App\Models\User
模型中) 包含一個 notifications
Eloquent 關聯,該關聯會傳回實體的通知。若要擷取通知,您可以像存取任何其他 Eloquent 關聯一樣存取此方法。預設情況下,通知將依 created_at
時間戳記排序,最近的通知位於集合的開頭。
$user = App\Models\User::find(1); foreach ($user->notifications as $notification) { echo $notification->type;}
如果您只想擷取「未讀」通知,您可以使用 unreadNotifications
關聯。同樣,這些通知將依 created_at
時間戳記排序,最近的通知位於集合的開頭。
$user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { echo $notification->type;}
若要從您的 JavaScript 用戶端存取您的通知,您應該為您的應用程式定義一個通知控制器,該控制器會傳回可通知實體的通知,例如目前的使用者。然後,您可以從您的 JavaScript 用戶端向該控制器的 URL 發出 HTTP 請求。
將通知標記為已讀
通常,您會在使用者檢視通知時將其標記為「已讀」。 Illuminate\Notifications\Notifiable
trait 提供了一個 markAsRead
方法,該方法會更新通知資料庫記錄上的 read_at
欄位。
$user = App\Models\User::find(1); foreach ($user->unreadNotifications as $notification) { $notification->markAsRead();}
但是,您可以直接在通知集合上使用 markAsRead
方法,而不是迴圈處理每個通知。
$user->unreadNotifications->markAsRead();
您也可以使用大量更新查詢來將所有通知標記為已讀,而無需從資料庫擷取它們。
$user = App\Models\User::find(1); $user->unreadNotifications()->update(['read_at' => now()]);
您可以 delete
這些通知,以將它們從表格中完全移除。
$user->notifications()->delete();
廣播通知
先決條件
在廣播通知之前,您應該設定並熟悉 Laravel 的事件廣播服務。事件廣播提供了一種從您的 JavaScript 前端對伺服器端的 Laravel 事件做出反應的方式。
設定廣播通知格式
broadcast
管道使用 Laravel 的事件廣播服務廣播通知,讓您的 JavaScript 前端可以即時捕獲通知。如果通知支援廣播,您可以在通知類別上定義一個 toBroadcast
方法。此方法將接收一個 $notifiable
實體,並應傳回一個 BroadcastMessage
實例。如果 toBroadcast
方法不存在,則將使用 toArray
方法來收集應廣播的資料。傳回的資料將被編碼為 JSON 並廣播到您的 JavaScript 前端。讓我們看看一個 toBroadcast
方法的範例。
use Illuminate\Notifications\Messages\BroadcastMessage; /** * Get the broadcastable representation of the notification. */public function toBroadcast(object $notifiable): BroadcastMessage{ return new BroadcastMessage([ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]);}
廣播佇列設定
所有廣播通知都會排隊等候廣播。如果您想設定用於排隊廣播操作的佇列連線或佇列名稱,您可以使用 BroadcastMessage
的 onConnection
和 onQueue
方法。
return (new BroadcastMessage($data)) ->onConnection('sqs') ->onQueue('broadcasts');
自訂通知類型
除了您指定的資料外,所有廣播通知還會有一個包含通知完整類別名稱的 type
欄位。如果您想自訂通知 type
,您可以在通知類別上定義 broadcastType
方法。
/** * Get the type of the notification being broadcast. */public function broadcastType(): string{ return 'broadcast.message';}
監聽通知
通知將在使用 {notifiable}.{id}
慣例格式化的私有管道上廣播。因此,如果您要將通知傳送給 ID 為 1
的 App\Models\User
實例,則該通知將在 App.Models.User.1
私有管道上廣播。當使用Laravel Echo時,您可以使用 notification
方法輕鬆偵聽管道上的通知。
Echo.private('App.Models.User.' + userId) .notification((notification) => { console.log(notification.type); });
自訂通知管道
如果您想自訂實體的廣播通知在哪個管道上廣播,您可以在可通知實體上定義一個 receivesBroadcastNotificationsOn
方法。
<?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; /** * The channels the user receives notification broadcasts on. */ public function receivesBroadcastNotificationsOn(): string { return 'users.'.$this->id; }}
簡訊通知
先決條件
在 Laravel 中傳送簡訊通知是由 Vonage (以前稱為 Nexmo) 提供支援。在您可以透過 Vonage 傳送通知之前,您需要安裝 laravel/vonage-notification-channel
和 guzzlehttp/guzzle
套件。
composer require laravel/vonage-notification-channel guzzlehttp/guzzle
此套件包含一個設定檔。但是,您不需要將此設定檔匯出到您自己的應用程式。您只需使用 VONAGE_KEY
和 VONAGE_SECRET
環境變數來定義您的 Vonage 公開金鑰和私密金鑰即可。
在定義您的金鑰之後,您應該設定一個 VONAGE_SMS_FROM
環境變數,該變數會定義預設情況下應從哪個電話號碼傳送您的簡訊。您可以在 Vonage 控制面板中產生此電話號碼。
VONAGE_SMS_FROM=15556666666
設定簡訊通知格式
如果通知支援以簡訊傳送,您應該在通知類別上定義一個 toVonage
方法。此方法將接收一個 $notifiable
實體,並應傳回一個 Illuminate\Notifications\Messages\VonageMessage
實例。
use Illuminate\Notifications\Messages\VonageMessage; /** * Get the Vonage / SMS representation of the notification. */public function toVonage(object $notifiable): VonageMessage{ return (new VonageMessage) ->content('Your SMS message content');}
Unicode 內容
如果您的簡訊將包含 Unicode 字元,您應該在建構 VonageMessage
實例時呼叫 unicode
方法。
use Illuminate\Notifications\Messages\VonageMessage; /** * Get the Vonage / SMS representation of the notification. */public function toVonage(object $notifiable): VonageMessage{ return (new VonageMessage) ->content('Your unicode message') ->unicode();}
自訂「發送者」號碼
如果您想從與您的 VONAGE_SMS_FROM
環境變數指定的電話號碼不同的電話號碼傳送某些通知,您可以呼叫 VonageMessage
實例上的 from
方法。
use Illuminate\Notifications\Messages\VonageMessage; /** * Get the Vonage / SMS representation of the notification. */public function toVonage(object $notifiable): VonageMessage{ return (new VonageMessage) ->content('Your SMS message content') ->from('15554443333');}
新增客戶參考
如果您想追蹤每個使用者、團隊或客戶的成本,您可以將「客戶參考」新增至通知。 Vonage 將允許您使用此客戶參考產生報告,以便您可以更好地了解特定客戶的簡訊使用情況。客戶參考可以是任何最多 40 個字元的字串。
use Illuminate\Notifications\Messages\VonageMessage; /** * Get the Vonage / SMS representation of the notification. */public function toVonage(object $notifiable): VonageMessage{ return (new VonageMessage) ->clientReference((string) $notifiable->id) ->content('Your SMS message content');}
路由簡訊通知
若要將 Vonage 通知路由到正確的電話號碼,請在您的可通知實體上定義一個 routeNotificationForVonage
方法。
<?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; /** * Route notifications for the Vonage channel. */ public function routeNotificationForVonage(Notification $notification): string { return $this->phone_number; }}
Slack 通知
先決條件
在傳送 Slack 通知之前,您應該透過 Composer 安裝 Slack 通知管道。
composer require laravel/slack-notification-channel
此外,您必須為您的 Slack 工作區建立一個 Slack 應用程式。
如果您只需要將通知傳送至建立應用程式的相同 Slack 工作區,您應該確保您的應用程式具有 chat:write
、chat:write.public
和 chat:write.customize
範圍。如果您想以您的 Slack 應用程式身分傳送訊息,您應該確保您的應用程式也具有 chat:write:bot
範圍。這些範圍可以從 Slack 中的「OAuth 和權限」應用程式管理標籤新增。
接下來,複製應用程式的「機器人使用者 OAuth 權杖」並將其放入您應用程式的 services.php
設定檔中的 slack
設定陣列中。此權杖可以在 Slack 中的「OAuth 和權限」標籤上找到。
'slack' => [ 'notifications' => [ 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), ],],
應用程式發佈
如果您的應用程式會向應用程式使用者擁有的外部 Slack 工作區發送通知,您需要透過 Slack「發佈」您的應用程式。應用程式發佈可以在您應用程式的 Slack「管理發佈」標籤中進行管理。一旦您的應用程式被發佈,您可以使用 Socialite 來代表您的應用程式使用者取得 Slack Bot 令牌。
設定 Slack 通知格式
如果通知支援以 Slack 訊息的方式發送,您應該在通知類別上定義一個 toSlack
方法。這個方法會接收一個 $notifiable
實體,並且應該返回一個 Illuminate\Notifications\Slack\SlackMessage
實例。您可以使用 Slack 的 Block Kit API 構建豐富的通知。以下範例可以在 Slack 的 Block Kit 建構器中預覽。
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; /** * Get the Slack representation of the notification. */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(); }) ->dividerBlock() ->sectionBlock(function (SectionBlock $block) { $block->text('Congratulations!'); });}
使用 Slack 的 Block Kit 建構器範本
您可以使用 Slack 的 Block Kit 建構器產生的原始 JSON payload 提供給 usingBlockKitTemplate
方法,而不是使用流暢訊息建構器方法來建立您的 Block Kit 訊息。
use Illuminate\Notifications\Slack\SlackMessage;use Illuminate\Support\Str; /** * Get the Slack representation of the notification. */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 應用程式應該啟用「互動性」,並設定一個「請求 URL」,指向您的應用程式所提供的 URL。這些設定可以在 Slack 的「互動性與快捷方式」應用程式管理標籤中進行管理。
在以下範例中,使用了 actionsBlock
方法,Slack 會發送一個 POST
請求到您的「請求 URL」,其中包含點擊按鈕的 Slack 使用者、點擊的按鈕 ID 以及更多資訊。您的應用程式可以根據 payload 決定要採取的動作。您還應該驗證請求是否由 Slack 發出。
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; /** * Get the Slack representation of the notification. */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 defaults to "button_acknowledge_invoice"... $block->button('Acknowledge Invoice')->primary(); // Manually configure the ID... $block->button('Deny')->danger()->id('deny_invoice'); });}
確認視窗
如果您希望使用者在執行動作之前必須確認,您可以在定義按鈕時調用 confirm
方法。confirm
方法接受一個訊息和一個閉包,該閉包會接收一個 ConfirmObject
實例。
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; /** * Get the Slack representation of the notification. */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 區塊
如果您想快速檢查您正在建立的區塊,可以在 SlackMessage
實例上調用 dd
方法。dd
方法會產生並 dump 一個 URL 到 Slack 的 Block Kit 建構器,該建構器會在您的瀏覽器中顯示 payload 和通知的預覽。您可以將 true
傳遞給 dd
方法,以 dump 原始 payload。
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 令牌和頻道名稱,例如SlackRoute::make($this->slack_channel, $this->slack_token)
。此方法應用於向外部工作區發送通知。
例如,從 routeNotificationForSlack
方法返回 #support-channel
將會把通知發送到與應用程式的 services.php
設定檔中 Bot User OAuth 令牌相關聯的工作區中的 #support-channel
頻道。
<?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; /** * Route notifications for the Slack channel. */ public function routeNotificationForSlack(Notification $notification): mixed { return '#support-channel'; }}
通知外部 Slack 工作區
在向外部 Slack 工作區發送通知之前,您的 Slack 應用程式必須發佈。
當然,您通常會希望向您的應用程式使用者擁有的 Slack 工作區發送通知。若要這麼做,您首先需要取得使用者的 Slack OAuth 令牌。幸好,Laravel Socialite 包含一個 Slack 驅動程式,可讓您輕鬆地使用 Slack 驗證應用程式的使用者,並取得機器人令牌。
取得機器人令牌並將其儲存在應用程式的資料庫中之後,您可以使用 SlackRoute::make
方法將通知路由到使用者的工作區。此外,您的應用程式可能需要提供一個讓使用者指定應將通知發送到哪個頻道的機會。
<?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; /** * Route notifications for the Slack channel. */ public function routeNotificationForSlack(Notification $notification): mixed { return SlackRoute::make($this->slack_channel, $this->slack_token); }}
本地化通知
Laravel 允許您以非 HTTP 請求當前語言環境的其他語言環境發送通知,如果通知被放入佇列,甚至會記住此語言環境。
為此,Illuminate\Notifications\Notification
類別提供了一個 locale
方法來設定所需的語言。當通知被評估時,應用程式將會變更為此語言環境,然後在評估完成後還原為之前的語言環境。
$user->notify((new InvoicePaid($invoice))->locale('es'));
也可以透過 Notification
facade 達成多個可通知條目的本地化。
Notification::locale('es')->send( $users, new InvoicePaid($invoice));
使用者偏好的語言環境
有時候,應用程式會儲存每個使用者偏好的語言環境。透過在您的可通知模型上實作 HasLocalePreference
合約,您可以指示 Laravel 在發送通知時使用這個儲存的語言環境。
use Illuminate\Contracts\Translation\HasLocalePreference; class User extends Model implements HasLocalePreference{ /** * Get the user's preferred locale. */ public function preferredLocale(): string { return $this->locale; }}
一旦您實作了介面,Laravel 會在發送通知和 mailables 到模型時自動使用偏好的語言環境。因此,使用此介面時,無需調用 locale
方法。
$user->notify(new InvoicePaid($invoice));
測試
您可以使用 Notification
facade 的 fake
方法來防止發送通知。通常,發送通知與您實際測試的程式碼無關。最有可能的情況是,僅斷言 Laravel 被指示發送給定通知就已足夠。
在調用 Notification
facade 的 fake
方法之後,您可以斷言通知被指示發送給使用者,甚至檢查通知收到的資料。
<?php use App\Notifications\OrderShipped;use Illuminate\Support\Facades\Notification; test('orders can be shipped', function () { Notification::fake(); // Perform order shipping... // Assert that no notifications were sent... Notification::assertNothingSent(); // Assert a notification was sent to the given users... Notification::assertSentTo( [$user], OrderShipped::class ); // Assert a notification was not sent... Notification::assertNotSentTo( [$user], AnotherNotification::class ); // Assert that a given number of notifications were sent... Notification::assertCount(3);});
<?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(); // Perform order shipping... // Assert that no notifications were sent... Notification::assertNothingSent(); // Assert a notification was sent to the given users... Notification::assertSentTo( [$user], OrderShipped::class ); // Assert a notification was not sent... Notification::assertNotSentTo( [$user], AnotherNotification::class ); // Assert that a given number of notifications were sent... Notification::assertCount(3); }}
您可以將閉包傳遞給 assertSentTo
或 assertNotSentTo
方法,以斷言發送的通知通過了給定的「真值測試」。如果至少有一個通知通過了給定的真值測試,那麼斷言將會成功。
Notification::assertSentTo( $user, function (OrderShipped $notification, array $channels) use ($order) { return $notification->order->id === $order->id; });
隨需通知
如果您正在測試的程式碼發送按需通知,您可以透過 assertSentOnDemand
方法測試按需通知是否已發送。
Notification::assertSentOnDemand(OrderShipped::class);
透過將閉包作為第二個參數傳遞給 assertSentOnDemand
方法,您可以確定是否已將按需通知發送到正確的「路由」位址。
Notification::assertSentOnDemand( OrderShipped::class, function (OrderShipped $notification, array $channels, object $notifiable) use ($user) { return $notifiable->routes['mail'] === $user->email; });
通知事件
通知發送事件
當正在發送通知時,通知系統會發送 Illuminate\Notifications\Events\NotificationSending
事件。此事件包含「可通知」實體和通知實例本身。您可以在應用程式中為此事件建立事件監聽器。
use Illuminate\Notifications\Events\NotificationSending; class CheckNotificationStatus{ /** * Handle the given event. */ public function handle(NotificationSending $event): void { // ... }}
如果 NotificationSending
事件的事件監聽器的 handle
方法返回 false
,則通知將不會發送。
/** * Handle the given event. */public function handle(NotificationSending $event): bool{ return false;}
在事件監聽器中,您可以存取事件上的 notifiable
、notification
和 channel
屬性,以了解有關通知接收者或通知本身的更多資訊。
/** * Handle the given event. */public function handle(NotificationSending $event): void{ // $event->channel // $event->notifiable // $event->notification}
通知已發送事件
當發送通知時,通知系統會發送 Illuminate\Notifications\Events\NotificationSent
事件。此事件包含「可通知」實體和通知實例本身。您可以在應用程式中為此事件建立事件監聽器。
use Illuminate\Notifications\Events\NotificationSent; class LogNotification{ /** * Handle the given event. */ public function handle(NotificationSent $event): void { // ... }}
在事件監聽器中,您可以存取事件上的 notifiable
、notification
、channel
和 response
屬性,以了解有關通知接收者或通知本身的更多資訊。
/** * Handle the given event. */public function handle(NotificationSent $event): void{ // $event->channel // $event->notifiable // $event->notification // $event->response}
自訂管道
Laravel 隨附一些通知管道,但您可能需要編寫自己的驅動程式,以透過其他管道傳遞通知。Laravel 使其變得簡單。首先,定義一個包含 send
方法的類別。此方法應該接收兩個參數:一個 $notifiable
和一個 $notification
。
在 send
方法中,您可以在通知上調用方法以檢索您的管道所理解的訊息物件,然後以您希望的任何方式將通知發送到 $notifiable
實例。
<?php namespace App\Notifications; use Illuminate\Notifications\Notification; class VoiceChannel{ /** * Send the given notification. */ public function send(object $notifiable, Notification $notification): void { $message = $notification->toVoice($notifiable); // Send notification to the $notifiable instance... }}
定義通知管道類別後,您可以從任何通知的 via
方法中返回類別名稱。在此範例中,通知的 toVoice
方法可以返回您選擇的任何物件來表示語音訊息。例如,您可以定義自己的 VoiceMessage
類別來表示這些訊息。
<?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; /** * Get the notification channels. */ public function via(object $notifiable): string { return VoiceChannel::class; } /** * Get the voice representation of the notification. */ public function toVoice(object $notifiable): VoiceMessage { // ... }}