Laravel 5.3 --通知

1、簡介

除了支持發送郵件之外,Laravel還支持通過多種傳輸通道發送通知,這些通道包括郵件、短信(通過Nexmo)以及等Slack等。通知可以存儲在數據庫以便后續在web界面中顯示。
通常,通知都是很短的、用于告知用戶應用中所發生事件的消息。例如,如果你在開發一個計費應用,則需要通過郵件或短信等渠道給用戶發送“賬單支付”通知。

2、創建通知

在Laravel中,每個通知都以單獨類的形式存在(通常存放在app/Notifications目錄),如果在應用中沒看到這個目錄,別擔心,它將會在你運行Artisan命令make:notification的時候自動創建:

php artisan make:notification InvoicePaid

該命令會在app/Notifications目錄下生成一個新的通知類,每個通知類都包含一個via方法以及多個消息構建方法(如toMailtoDatabase),這些消息構建方法用于將通知轉化成為特定渠道優化的消息。

3、發送通知

使用Notifiable Trait
通知可以通過兩種方式發送:使用Notifiable trait提供的notify方法或者使用Notification門面。首先,我們來檢驗Notifiable trait。該trait被默認的App\User模型使用并提供一個可用于發送通知的方法:notifynotify方法接收一個通知實例:

use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));

注:記住,你可以在任何模型中使用Illuminate\Notifications\Notifiabletrait,不限于只在User模型中使用。

使用Notification門面
作為替代方案,還可以通過Notification門面發送通知。這主要在你需要發送通知給多個用戶的時候很有用,要使用這個門面發送通知,需要將所有被通知用戶和通知實例傳遞給send方法:

Notification::send($users, new InvoicePaid($invoice));

指定傳輸通道
每個通知類都有一個via方法用于決定通知通過何種通道傳輸,Laravel開箱支持maildatabasebroadcastnexmo以及slack通道。
注:如果你想要使用其他傳輸通道,比如Telegram或Pusher,參考社區提供的驅動:Laravel通知通道網站
via方法接收一個$notifiable實例,用于指定通知被發送到的類實例。你可以使用$notifiable來判斷通知通過何種通道傳輸:

/** 
* Get the notification's delivery channels. 
* 
* @param  mixed  $notifiable 
* @return array 
*/
public function via($notifiable){
 return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database'];
}

通知隊列

注:使用通知隊列前需要配置隊列并開啟一個隊列任務。

發送同時可能是耗時的,尤其是通道需要調用額外的API來傳輸通知。為了加速應用的響應時間,可以讓通知類實現ShouldQueue接口并使用Queueable trait。如果通知類是通過make:notification命令生成的,那么該接口和trait已經默認導入,你可以快速將它們添加到通知類:

<?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接口被添加到通知類以后,你可以像之前一樣正常發送通知,Laravel會自動檢測到ShouldQueue接口然后將通知傳輸推送到隊列:

$user->notify(new InvoicePaid($invoice));

如果你想要延遲通知的傳輸,可以在加上delay方法:

$when = Carbon::now()->addMinutes(10);
$user->notify((new InvoicePaid($invoice))->delay($when));

4、郵件通知

格式化郵件消息
如果通知支持以郵件方式發送,你需要在通知類上定義一個toMail
方法。該方法會接收一個$notifiable
實體并返回Illuminate\Notifications\Messages\MailMessage
實例。郵件消息可以包含多行文本以及對動作的調用,讓我們來看一個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!');
}

注:注意到我們在message方法中使用了$this->invoice->id,你可以傳遞任何通知生成消息所需要的數據到通知的構造器。

在這個例子中,我們注冊了一條問候、一行文本、對動作的調用以及另一行文本。MailMessage對象提供的這些方法讓格式化短小的交易郵件變得簡單快捷。mail通道會將消息組件轉化為漂亮的、響應式的、帶有純文本副本的HTML郵件模板。下面是一個通過mail通道生成的郵件示例:

注:發送郵件通知時,確保在配置文件 config/app.php 中設置了name的值,該值將會用在郵件通知消息的頭部和尾部。

自定義收件人
通過mail通道發送通知時,通知系統會自動在被通知實體上查找email屬性,你可以通過在該實體上定義一個routeNotificationForMail自定義使用哪個郵箱地址發送通知:

<?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; 
      }
}

自定義主題
默認情況下,郵件的主題就是格式為“標題化”的通知類名,因此,如果通知類被命名為InvoicePaid,郵件的主題就是Invoice Paid,如果你想要為消息指定明確的主題,可以在構建消息的時候調用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('...');
}

自定義模板
你可以通過發布通知擴展包的資源來修改郵件通知所使用的HTML和純文本模板。運行完下面這個命令之后,郵件通知模板將會存放到resources/views/vendor/notifications目錄:

php artisan vendor:publish --tag=laravel-notifications

錯誤消息
一些通知會告知用戶錯誤信息,例如一次失敗的單據支付,你可以在構建消息的時候調用error方法標識郵件消息是一個錯誤消息。當在一個郵件消息上使用error
方法時,動作按鈕的顏色將會由藍色變成紅色:

/** 
* 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、數據庫通知

預備知識
database通知通道會在數據表中存儲通知信息,該表包含諸如通知類型以及用于描述通知的自定義JSON數據之類的信息。
你可以在用戶界面中查詢這個數據表來展示通知,不過,在此之前,需要創建數據表來保存信息,你可以使用notifications:table命令來生成遷移然后生成數據表:

php artisan notifications:table
php artisan migrate

格式化數據庫通知
如果一個通知支持存放在數據表,則需要在通知類中定義toDatabasetoArray方法,該方法接收一個$notifiable實體并返回原生的PHP數組。返回的數組會被編碼為JSON格式然后存放到notifications表的data字段。讓我們來看一個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通道用來判斷廣播什么數據到JavaScript客戶端,如果你想要為databasebroadcast通道提供兩種不同的數組表示,則需要定義一個toDatabase方法來取代toArray方法。
訪問通知
通知被存放到數據表之后,需要在被通知實體中有一個便捷的方式來訪問它們。Laravel默認提供的App\User模型引入的Illuminate\Notifications\Notifiabletrait包含了返回實體對應通知的Eloquent關聯關系方法notifications,要獲取這些通知,可以像訪問其它Eloquent關聯關系一樣訪問該關聯方法,默認情況下,通知按照created_at時間戳排序:

$user = App\User::find(1);

foreach ($user->notifications as $notification) { 
        echo $notification->type;
}

如果你只想獲取未讀消息,可使用關聯關系unreadNotifications,同樣,這些通知也按照created_at時間戳排序:

$user = App\User::find(1);
foreach ($user->unreadNotifications as $notification) {         
      echo $notification->type;
}

注:要想從JavaScript客戶端訪問通知,需要在應用中定義一個通知控制器為指定被通知實體(比如當前用戶)返回通知,然后從JavaScript客戶端發送一個HTTP請求到控制器對應URI。

標記通知為已讀
一般情況下,我們會將用戶瀏覽過的通知標記為已讀,Illuminate\Notifications\Notifiabletrait提供了一個markAsRead方法,用于更新對應通知數據庫紀錄上的read_at字段:

$user = App\User::find(1);
foreach ($user->unreadNotifications as $notification) { 
      $notification->markAsRead();
}

如果覺得循環便利每個通知太麻煩,可以直接在通知集合上調用markAsRead
方法:

$user->unreadNotifications->markAsRead();

還可以使用批量更新方式標記通知為已讀,無需先從數據庫獲取通知:

$user = App\User::find(1);
$user->unreadNotifications()->update(['read_at' => Carbon::now()]);

當然,你也可以通過delete方法從數據庫中移除這些通知:

$user->notifications()->delete();

6、廣播通知

預備知識
在進行廣播通知之前,需要配置并了解事件廣播,事件廣播為JavaScript客戶端響應服務端事件觸發鋪平了道路。
格式化廣播通知
``broadcast通道廣播通知使用了Laravel的事件廣播服務,從而允許JavaScript客戶端實時捕獲通知。如果通知支持廣播,則需要在通知類上定義toBroadcasttoArray方法,該方法接收一個$notifiable實體并返回原生的PHP數組,返回的數組會編碼成JSON格式然后廣播到JavaScript客戶端。讓我們來看一個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, 
   ];
}

注:除了指定的數據,廣播通知還包含了一個type字段,用于表示通知類名。

toBroadcast Vs. toArray
toArray方法還可以用于database通道以判斷在數據表中存儲哪些數據。如果你想要為databasebroadcast通道提供兩種不同的數組表示方式,需要定義一個toBroadcast方法來取代toArray方法。
監聽通知
通知將會以格式化為{notifiable}.{id}的形式在私人頻道上廣播,因此,如果你要發送通知到ID為1App\User實例,那么該通知將會在私人頻道App.User.1上進行廣播,如果使用了Laravel Echo,可以使用輔助函數notification輕松在某個頻道上監聽通知:

Echo.private('App.User.' + userId) 
    .notification((notification) => { 
    console.log(notification.type);    
});

7、短信(SMS)通知

預備知識
Laravel基于Nexmo發送短信通知,在使用Nexmo發送通知前,需要安裝Composer包nexmo/client并在配置文件config/services.php
中進行少許配置。你可以從拷貝以下示例配置開始:

'nexmo' => [ 
    'key' => env('NEXMO_KEY'), 
    'secret' => env('NEXMO_SECRET'), 
    'sms_from' => '15556666666',
],

sms_from配置項就是你用于發送短信消息的手機號碼,你需要在Nexmo控制面板中為應用生成一個手機號碼。
格式化短信通知
如果通知支持以短信方式發送,需要在通知類上定義一個toNexmo方法。該方法接收一個$notifiable實體并返回Illuminate\Notifications\Messages\NexmoMessage實例:

/** 
* 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');
}

自定義來源號碼
如果你要通過與配置文件config/services.php中指定的手機號不同的其他號碼發送通知,可以使用NexmoMessage實例上的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通道發送通知的時候,通知系統會自動在被通知實體上查找phone_number屬性。如果你想要自定義通知被發送到的手機號碼,可以在該實體上定義一個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通知

預備知識
在通過Slack發送通知前,必須通過Composer安裝Guzzle HTTP庫:

composer require guzzlehttp/guzzle

此外,你還要為Slack組配置一個“Incoming Webhook”集成。該集成會在你進行Slack通知路由的時候提供一個URL。
格式化Slack通知
如果通知支持通過Slack消息發送,則需要在通知類上定義一個toSlack
方法,該方法接收一個$notifiable實體并返回Illuminate\Notifications\Messages\SlackMessage實例,該實例包含文本內容以及格式化額外文本或數組字段的“附件”。讓我們來看一個基本的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!');
}

在這個例子中,我們只發送一行簡單的文本到Slack,最終創建的消息如下:

basic-slack-notification

Slack附件
你還可以添加“附件”到Slack消息。相對簡單文本消息,附件可以提供更加豐富的格式選擇。在這個例子中,我們會發送一個在應用程序中出現的異常錯誤通知,包含鏈接到更多異常細節的鏈接:

/** 
* 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.'); 
          });
}

上述代碼會生成如下Slack消息:


basic-slack-attachment

附件還允許你指定要呈獻給用戶的數組數據。為了提高可讀性,給定的數組會以表格形式展示:

/** * 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:', ]); });}

上述代碼會生成如下Slack消息:

slack-fields-attachment

自定義發送者 & 接收者
你可以使用fromto方法自定義發送者和接收者,from
方法接收用戶名和 emoji 標識符,而to方法接收一個頻道或用戶名:

/** 
* 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通知到適當的位置,需要在被通知的實體上定義一個routeNotificationForSlack
方法,這將會返回通知被發送到的webhook URL。webhook URL可通過在Slack組上添加一個“Incoming Webhook”服務來生成:

<?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、通知事件

當通知被發送后,通知系統會觸發Illuminate\Notifications\Events\NotificationSent事件,該事件實例包含被通知的實體(如用戶)和通知實例本身。你可以在EventServiceProvider中為該事件注冊監聽器:

/** 
* The event listener mappings for the application. 
* 
* @var array 
*/
protected $listen = [ 
    'Illuminate\Notifications\Events\NotificationSent' => [ 
          'App\Listeners\LogNotification', 
    ],
];

注:在EventServiceProvider中注冊監聽器之后,使用Artisan命令event:generate快速生成監聽器類。

在事件監聽器中,可以訪問事件的 notifiablenotificationchannel屬性了解通知接收者和通知本身的更多信息:

/** 
* Handle the event. 
* 
* @param  NotificationSent  $event 
* @return void 
*/
public function handle(NotificationSent $event){ 
    // $event->channel 
    // $event->notifiable 
    // $event->notification
}

10、自定義頻道
通過上面的介紹,可見Laravel為我們提供了一大把通知通道,但是如果你想要編寫自己的驅動以便通過其他通道發送通知,也很簡單。首先定義一個包含send方法的類,該方法接收兩個參數:$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... 
   }
}

通知類被定義后,就可以在應用中通過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) { 
       // ... 
    }    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容

  • 原文鏈接 必備品 文檔:Documentation API:API Reference 視頻:Laracasts ...
    layjoy閱讀 8,619評論 0 121
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,799評論 18 139
  • 必備品文檔:DocumentationAPI: API Reference視頻:Laracasts速查表:Lara...
    ethanzhang閱讀 5,758評論 0 68
  • 點擊查看原文 Web SDK 開發手冊 SDK 概述 網易云信 SDK 為 Web 應用提供一個完善的 IM 系統...
    layjoy閱讀 13,840評論 0 15
  • 《山中行》/劉素 山川之上藏香茗, 一芽一葉山水間。 漫山遍野尋它渡, 只留杯香在人間...
    馬幫劉素閱讀 261評論 0 1