1凤薛、簡(jiǎn)介
除了支持發(fā)送郵件
之外枚冗,Laravel
還支持通過多種傳輸通道發(fā)送通知
缓溅,這些通道包括郵件
、短信(通過Nexmo
)以及等Slack
等赁温。通知可以存儲(chǔ)在數(shù)據(jù)庫(kù)
以便后續(xù)在web界面中顯示坛怪。
通常淤齐,通知都是很短的、用于告知用戶應(yīng)用中所發(fā)生事件
的消息袜匿。例如更啄,如果你在開發(fā)一個(gè)計(jì)費(fèi)應(yīng)用,則需要通過郵件或短信等渠道給用戶發(fā)送“賬單支付”通知居灯。
2祭务、創(chuàng)建通知
在Laravel中,每個(gè)通知都以單獨(dú)類的形式存在(通常存放在app/
Notifications
目錄)怪嫌,如果在應(yīng)用中沒看到這個(gè)目錄义锥,別擔(dān)心,它將會(huì)在你運(yùn)行Artisan命令make:notification
的時(shí)候自動(dòng)創(chuàng)建:
php artisan make:notification InvoicePaid
該命令會(huì)在app/Notifications
目錄下生成一個(gè)新的通知類岩灭,每個(gè)通知類都包含一個(gè)via方法以及多個(gè)消息構(gòu)建方法(如toMail
或toDatabase
)拌倍,這些消息構(gòu)建方法用于將通知轉(zhuǎn)化成為特定渠道優(yōu)化的消息。
3噪径、發(fā)送通知
使用Notifiable Trait
通知可以通過兩種方式發(fā)送:使用Notifiable
trait提供的notify
方法或者使用Notification
門面
贰拿。首先,我們來檢驗(yàn)Notifiable
trait熄云。該trait被默認(rèn)的App\User
模型使用并提供一個(gè)可用于發(fā)送通知的方法:notify
膨更。notify
方法接收一個(gè)通知實(shí)例:
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));
注:記住,你可以在任何模型中使用Illuminate\Notifications\Notifiable
trait缴允,不限于只在User
模型中使用荚守。
使用Notification門面
作為替代方案,還可以通過Notification
門面發(fā)送通知练般。這主要在你需要發(fā)送通知給多個(gè)用戶的時(shí)候很有用矗漾,要使用這個(gè)門面發(fā)送通知,需要將所有被通知用戶和通知實(shí)例傳遞給send
方法:
Notification::send($users, new InvoicePaid($invoice));
指定傳輸通道
每個(gè)通知類都有一個(gè)via
方法用于決定通知通過何種通道傳輸薄料,Laravel開箱支持mail
敞贡、database
、broadcast
摄职、nexmo
以及slack
通道誊役。
注:如果你想要使用其他傳輸通道,比如Telegram或Pusher谷市,參考社區(qū)提供的驅(qū)動(dòng):Laravel通知通道網(wǎng)站蛔垢。
via
方法接收一個(gè)$notifiable
實(shí)例,用于指定通知被發(fā)送到的類實(shí)例迫悠。你可以使用$notifiable來判斷通知通過何種通道傳輸:
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable){
return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database'];
}
通知隊(duì)列
注:使用通知隊(duì)列前需要配置隊(duì)列并開啟一個(gè)隊(duì)列任務(wù)鹏漆。
發(fā)送同時(shí)可能是耗時(shí)的,尤其是通道需要調(diào)用額外的API來傳輸通知。為了加速應(yīng)用的響應(yīng)時(shí)間艺玲,可以讓通知類實(shí)現(xiàn)ShouldQueue接口并使用Queueable
trait括蝠。如果通知類是通過make:notification命令生成的,那么該接口和trait已經(jīng)默認(rèn)導(dǎo)入饭聚,你可以快速將它們添加到通知類:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// ...
}
ShouldQueue
接口被添加到通知類以后忌警,你可以像之前一樣正常發(fā)送通知,Laravel會(huì)自動(dòng)檢測(cè)到ShouldQueue
接口然后將通知傳輸推送到隊(duì)列:
$user->notify(new InvoicePaid($invoice));
如果你想要延遲通知的傳輸若治,可以在加上delay
方法:
$when = Carbon::now()->addMinutes(10);
$user->notify((new InvoicePaid($invoice))->delay($when));
4慨蓝、郵件通知
格式化郵件消息
如果通知支持以郵件方式發(fā)送,你需要在通知類上定義一個(gè)toMail
方法端幼。該方法會(huì)接收一個(gè)$notifiable
實(shí)體并返回Illuminate\Notifications\Messages\MailMessage
實(shí)例礼烈。郵件消息可以包含多行文本以及對(duì)動(dòng)作的調(diào)用,讓我們來看一個(gè)toMail
方法的示例:
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage */
public function toMail($notifiable){
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
注:注意到我們?cè)?code>message方法中使用了
$this->invoice->id
婆跑,你可以傳遞任何通知生成消息所需要的數(shù)據(jù)到通知的構(gòu)造器此熬。
在這個(gè)例子中,我們注冊(cè)了一條問候滑进、一行文本犀忱、對(duì)動(dòng)作的調(diào)用以及另一行文本。MailMessage
對(duì)象提供的這些方法讓格式化短小的交易郵件變得簡(jiǎn)單快捷扶关。mail
通道會(huì)將消息組件轉(zhuǎn)化為漂亮的阴汇、響應(yīng)式的、帶有純文本副本的HTML郵件模板节槐。下面是一個(gè)通過mail
通道生成的郵件示例:
注:發(fā)送郵件通知時(shí)搀庶,確保在配置文件
config/app.php
中設(shè)置了name
的值,該值將會(huì)用在郵件通知消息的頭部和尾部铜异。
自定義收件人
通過mail通道發(fā)送通知時(shí)哥倔,通知系統(tǒng)會(huì)自動(dòng)在被通知實(shí)體上查找email屬性,你可以通過在該實(shí)體上定義一個(gè)routeNotificationForMail自定義使用哪個(gè)郵箱地址發(fā)送通知:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable{
use Notifiable;
/**
* Route notifications for the mail channel.
*
* @return string
*/
public function routeNotificationForMail() {
return $this->email_address;
}
}
自定義主題
默認(rèn)情況下揍庄,郵件的主題就是格式為“標(biāo)題化”的通知類名咆蒿,因此,如果通知類被命名為InvoicePaid
蚂子,郵件的主題就是Invoice Paid
沃测,如果你想要為消息指定明確的主題,可以在構(gòu)建消息的時(shí)候調(diào)用subject
方法:
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage */
public function toMail($notifiable){
return (new MailMessage)
->subject('Notification Subject')
->line('...');
}
自定義模板
你可以通過發(fā)布通知擴(kuò)展包的資源來修改郵件通知所使用的HTML和純文本模板缆镣。運(yùn)行完下面這個(gè)命令之后芽突,郵件通知模板將會(huì)存放到resources/views/vendor/notifications
目錄:
php artisan vendor:publish --tag=laravel-notifications
錯(cuò)誤消息
一些通知會(huì)告知用戶錯(cuò)誤信息,例如一次失敗的單據(jù)支付董瞻,你可以在構(gòu)建消息的時(shí)候調(diào)用error方法標(biāo)識(shí)郵件消息是一個(gè)錯(cuò)誤消息。當(dāng)在一個(gè)郵件消息上使用error
方法時(shí),動(dòng)作按鈕的顏色將會(huì)由藍(lán)色變成紅色:
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Message
*/
public function toMail($notifiable){
return (new MailMessage)
->error()
->subject('Notification Subject')
->line('...');
}
5钠糊、數(shù)據(jù)庫(kù)通知
預(yù)備知識(shí)
database
通知通道會(huì)在數(shù)據(jù)表中存儲(chǔ)通知信息挟秤,該表包含諸如通知類型以及用于描述通知的自定義JSON數(shù)據(jù)之類的信息。
你可以在用戶界面中查詢這個(gè)數(shù)據(jù)表來展示通知抄伍,不過艘刚,在此之前,需要?jiǎng)?chuàng)建數(shù)據(jù)表來保存信息截珍,你可以使用notifications:table
命令來生成遷移然后生成數(shù)據(jù)表:
php artisan notifications:table
php artisan migrate
格式化數(shù)據(jù)庫(kù)通知
如果一個(gè)通知支持存放在數(shù)據(jù)表攀甚,則需要在通知類中定義toDatabase
或toArray
方法,該方法接收一個(gè)$notifiable
實(shí)體并返回原生的PHP數(shù)組岗喉。返回的數(shù)組會(huì)被編碼為JSON格式然后存放到notifications
表的data
字段秋度。讓我們來看一個(gè)toArray
方法的例子:
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable){
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
];
}
toDatabase Vs. toArray
toArray
方法還被broadcast
通道用來判斷廣播什么數(shù)據(jù)到JavaScript客戶端,如果你想要為database
和broadcast
通道提供兩種不同的數(shù)組表示钱床,則需要定義一個(gè)toDatabase
方法來取代toArray
方法荚斯。
訪問通知
通知被存放到數(shù)據(jù)表之后,需要在被通知實(shí)體中有一個(gè)便捷的方式來訪問它們查牌。Laravel默認(rèn)提供的App\User
模型引入的Illuminate\Notifications\Notifiable
trait包含了返回實(shí)體對(duì)應(yīng)通知的Eloquent關(guān)聯(lián)關(guān)系方法notifications
事期,要獲取這些通知,可以像訪問其它Eloquent關(guān)聯(lián)關(guān)系一樣訪問該關(guān)聯(lián)方法纸颜,默認(rèn)情況下兽泣,通知按照created_at
時(shí)間戳排序:
$user = App\User::find(1);
foreach ($user->notifications as $notification) {
echo $notification->type;
}
如果你只想獲取未讀消息,可使用關(guān)聯(lián)關(guān)系unreadNotifications
胁孙,同樣唠倦,這些通知也按照created_at
時(shí)間戳排序:
$user = App\User::find(1);
foreach ($user->unreadNotifications as $notification) {
echo $notification->type;
}
注:要想從JavaScript客戶端訪問通知,需要在應(yīng)用中定義一個(gè)通知控制器為指定被通知實(shí)體(比如當(dāng)前用戶)返回通知浊洞,然后從JavaScript客戶端發(fā)送一個(gè)HTTP請(qǐng)求到控制器對(duì)應(yīng)URI牵敷。
標(biāo)記通知為已讀
一般情況下,我們會(huì)將用戶瀏覽過的通知標(biāo)記為已讀法希,Illuminate\Notifications\Notifiable
trait提供了一個(gè)markAsRead
方法枷餐,用于更新對(duì)應(yīng)通知數(shù)據(jù)庫(kù)紀(jì)錄上的read_at
字段:
$user = App\User::find(1);
foreach ($user->unreadNotifications as $notification) {
$notification->markAsRead();
}
如果覺得循環(huán)便利每個(gè)通知太麻煩,可以直接在通知集合上調(diào)用markAsRead
方法:
$user->unreadNotifications->markAsRead();
還可以使用批量更新方式標(biāo)記通知為已讀苫亦,無需先從數(shù)據(jù)庫(kù)獲取通知:
$user = App\User::find(1);
$user->unreadNotifications()->update(['read_at' => Carbon::now()]);
當(dāng)然毛肋,你也可以通過delete
方法從數(shù)據(jù)庫(kù)中移除這些通知:
$user->notifications()->delete();
6、廣播通知
預(yù)備知識(shí)
在進(jìn)行廣播通知之前屋剑,需要配置并了解事件廣播润匙,事件廣播為JavaScript客戶端響應(yīng)服務(wù)端事件觸發(fā)鋪平了道路。
格式化廣播通知
``broadcast通道廣播通知使用了Laravel的事件廣播服務(wù)唉匾,從而允許JavaScript客戶端實(shí)時(shí)捕獲通知孕讳。如果通知支持廣播匠楚,則需要在通知類上定義
toBroadcast或
toArray方法,該方法接收一個(gè)
$notifiable實(shí)體并返回原生的PHP數(shù)組厂财,返回的數(shù)組會(huì)編碼成JSON格式然后廣播到JavaScript客戶端芋簿。讓我們來看一個(gè)
toArray`方法的示例:
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable){
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
];
}
注:除了指定的數(shù)據(jù),廣播通知還包含了一個(gè)type
字段璃饱,用于表示通知類名与斤。
toBroadcast Vs. toArray
toArray
方法還可以用于database
通道以判斷在數(shù)據(jù)表中存儲(chǔ)哪些數(shù)據(jù)。如果你想要為database
和broadcast
通道提供兩種不同的數(shù)組表示方式荚恶,需要定義一個(gè)toBroadcast
方法來取代toArray
方法撩穿。
監(jiān)聽通知
通知將會(huì)以格式化為{notifiable}.{id}
的形式在私人頻道上廣播,因此谒撼,如果你要發(fā)送通知到ID為1
的App\User
實(shí)例食寡,那么該通知將會(huì)在私人頻道App.User.1
上進(jìn)行廣播,如果使用了Laravel Echo
嗤栓,可以使用輔助函數(shù)notification
輕松在某個(gè)頻道上監(jiān)聽通知:
Echo.private('App.User.' + userId)
.notification((notification) => {
console.log(notification.type);
});
7冻河、短信(SMS)通知
預(yù)備知識(shí)
Laravel基于Nexmo發(fā)送短信通知,在使用Nexmo發(fā)送通知前茉帅,需要安裝Composer包nexmo/client并在配置文件config/services.php
中進(jìn)行少許配置叨叙。你可以從拷貝以下示例配置開始:
'nexmo' => [
'key' => env('NEXMO_KEY'),
'secret' => env('NEXMO_SECRET'),
'sms_from' => '15556666666',
],
sms_from
配置項(xiàng)就是你用于發(fā)送短信消息的手機(jī)號(hào)碼,你需要在Nexmo控制面板中為應(yīng)用生成一個(gè)手機(jī)號(hào)碼堪澎。
格式化短信通知
如果通知支持以短信方式發(fā)送擂错,需要在通知類上定義一個(gè)toNexmo
方法。該方法接收一個(gè)$notifiable
實(shí)體并返回Illuminate\Notifications\Messages\NexmoMessage
實(shí)例:
/**
* Get the Nexmo / SMS representation of the notification.
*
* @param mixed $notifiable
* @return NexmoMessage */public function toNexmo($notifiable){ return (new NexmoMessage) ->content('Your SMS message content');
}
自定義來源號(hào)碼
如果你要通過與配置文件config/services.php
中指定的手機(jī)號(hào)不同的其他號(hào)碼發(fā)送通知樱蛤,可以使用NexmoMessage
實(shí)例上的from
方法:
/**
* Get the Nexmo / SMS representation of the notification.
*
* @param mixed $notifiable
* @return NexmoMessage
*/
public function toNexmo($notifiable){
return (new NexmoMessage)
->content('Your SMS message content')
->from('15554443333');
}
短信通知路由
使用nexmo
通道發(fā)送通知的時(shí)候钮呀,通知系統(tǒng)會(huì)自動(dòng)在被通知實(shí)體上查找phone_number
屬性。如果你想要自定義通知被發(fā)送到的手機(jī)號(hào)碼昨凡,可以在該實(shí)體上定義一個(gè)routeNotificationForNexmo
方法:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable{
use Notifiable;
/**
* Route notifications for the Nexmo channel.
*
* @return string
*/
public function routeNotificationForNexmo() {
return $this->phone;
}
}
8爽醋、Slack通知
預(yù)備知識(shí)
在通過Slack
發(fā)送通知前,必須通過Composer安裝Guzzle HTTP庫(kù):
composer require guzzlehttp/guzzle
此外便脊,你還要為Slack組配置一個(gè)“Incoming Webhook”集成蚂四。該集成會(huì)在你進(jìn)行Slack通知路由的時(shí)候提供一個(gè)URL。
格式化Slack通知
如果通知支持通過Slack消息發(fā)送哪痰,則需要在通知類上定義一個(gè)toSlack
方法遂赠,該方法接收一個(gè)$notifiable
實(shí)體并返回Illuminate\Notifications\Messages\SlackMessage
實(shí)例,該實(shí)例包含文本內(nèi)容以及格式化額外文本或數(shù)組字段的“附件”晌杰。讓我們來看一個(gè)基本的toSlack使用示例:
/**
* Get the Slack representation of the notification.
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable){
return (new SlackMessage)
->content('One of your invoices has been paid!');
}
在這個(gè)例子中肋演,我們只發(fā)送一行簡(jiǎn)單的文本到Slack,最終創(chuàng)建的消息如下:
Slack附件
你還可以添加“附件”到Slack消息边灭。相對(duì)簡(jiǎn)單文本消息称簿,附件可以提供更加豐富的格式選擇。在這個(gè)例子中授药,我們會(huì)發(fā)送一個(gè)在應(yīng)用程序中出現(xiàn)的異常錯(cuò)誤通知悔叽,包含鏈接到更多異常細(xì)節(jié)的鏈接:
/**
* Get the Slack representation of the notification.
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable){
$url = url('/exceptions/'.$this->exception->id);
return (new SlackMessage)
->error()
->content('Whoops! Something went wrong.')
->attachment(function ($attachment) use ($url) {
$attachment->title('Exception: File Not Found', $url)
->content('File [background.jpg] was not found.');
});
}
上述代碼會(huì)生成如下Slack消息:
附件還允許你指定要呈獻(xiàn)給用戶的數(shù)組數(shù)據(jù)睹晒。為了提高可讀性戚啥,給定的數(shù)組會(huì)以表格形式展示:
/** * Get the Slack representation of the notification. * * @param mixed $notifiable * @return SlackMessage */
public function toSlack($notifiable){ $url = url('/invoices/'.$this->invoice->id);
return (new SlackMessage) ->success() ->content('One of your invoices has been paid!') ->attachment(function ($attachment) use ($url) { $attachment->title('Invoice 1322', $url) ->fields([ 'Title' => 'Server Expenses', 'Amount' => '$1,234', 'Via' => 'American Express', 'Was Overdue' => ':-1:', ]); });}
上述代碼會(huì)生成如下Slack消息:
自定義發(fā)送者 & 接收者
你可以使用
from
和to
方法自定義發(fā)送者和接收者键痛,from
方法接收用戶名和 emoji 標(biāo)識(shí)符絮短,而
to
方法接收一個(gè)頻道或用戶名:
/**
* Get the Slack representation of the notification.
*
* @param mixed $notifiable
* @return SlackMessage
*/
public function toSlack($notifiable){
return (new SlackMessage)
->from('Ghost', ':ghost:')
->to('#other');
->content('This will be sent to #other')
}
Slack通知路由
要路由Slack通知到適當(dāng)?shù)奈恢靡靥枰诒煌ㄖ膶?shí)體上定義一個(gè)routeNotificationForSlack
方法拢驾,這將會(huì)返回通知被發(fā)送到的webhook URL。webhook URL可通過在Slack組上添加一個(gè)“Incoming Webhook”服務(wù)來生成:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable{
use Notifiable;
/**
* Route notifications for the Slack channel.
*
* @return string
*/
public function routeNotificationForSlack() {
return $this->slack_webhook_url;
}
}
9、通知事件
當(dāng)通知被發(fā)送后架忌,通知系統(tǒng)會(huì)觸發(fā)Illuminate\Notifications\Events\NotificationSent
事件,該事件實(shí)例包含被通知的實(shí)體(如用戶)和通知實(shí)例本身井仰。你可以在EventServiceProvider
中為該事件注冊(cè)監(jiān)聽器:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Notifications\Events\NotificationSent' => [
'App\Listeners\LogNotification',
],
];
注:在
EventServiceProvider
中注冊(cè)監(jiān)聽器之后,使用Artisan命令event:generate
快速生成監(jiān)聽器類。
在事件監(jiān)聽器中端仰,可以訪問事件的 notifiable
、notification
和channel
屬性了解通知接收者和通知本身的更多信息:
/**
* Handle the event.
*
* @param NotificationSent $event
* @return void
*/
public function handle(NotificationSent $event){
// $event->channel
// $event->notifiable
// $event->notification
}
10、自定義頻道
通過上面的介紹臀稚,可見Laravel為我們提供了一大把通知通道窜管,但是如果你想要編寫自己的驅(qū)動(dòng)以便通過其他通道發(fā)送通知,也很簡(jiǎn)單失乾。首先定義一個(gè)包含send
方法的類,該方法接收兩個(gè)參數(shù):$notifiable
和$notification
:
<?php
namespace App\Channels;
use Illuminate\Notifications\Notification;
class VoiceChannel{
/**
* Send the given notification.
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @return void
*/
public function send($notifiable, Notification $notification) {
$message = $notification->toVoice($notifiable);
// Send notification to the $notifiable instance...
}
}
通知類被定義后宜雀,就可以在應(yīng)用中通過via方法返回類名:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use App\Channels\VoiceChannel;
use App\Channels\Messages\VoiceMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoicePaid extends Notification{
use Queueable;
/**
* Get the notification channels.
*
* @param mixed $notifiable
* @return array|string
*/
public function via($notifiable) {
return [VoiceChannel::class];
}
/**
* Get the voice representation of the notification.
*
* @param mixed $notifiable
* @return VoiceMessage
*/
public function toVoice($notifiable) {
// ...
}