Thông báo

Giới thiệu

Ngoài việc hỗ trợ sending email, Laravel còn cung cấp gửi thông báo qua nhiều cách, gồm mail, SMS (qua Nexmo), và Slack. Thông báo có thể được lưu trong cơ sở dữ liệu và họ có thể hiển thị trên webiste.

Thông thường, thông báo nên ngắn gọn, thông tin thông báo là để báo cho người dùng cái gì xảy ra trong ứng dụng. Ví dụ, nếu bạn viết một ứng dụng thanh toán, bạn phải gửi một thông báo "Hóa đơn thanh toán" đến người dùng qua email và SMS.

Tạo thông báo

Trong Laravel, mỗi một thông báo là một thể hiện của một lớp (thường lưu trong thư mục app/Notifications). Đừng lo lắng nếu bạn không nhìn thấy thư mục này, nó sẽ được tạo ra khi bạn chạy lệnh make:notification:

php artisan make:notification InvoicePaid

Lệnh này sẽ thêm một class trong thư mục app/Notifications. Mỗi class thông báo chưa một hàm via và một biến số thông báo của phương thức (như là toMail hoặc toDatabase) chuyển thông báo thành nội dung tối ưu nó cho các channel.

Gửi Notifications

Sử dụng Notifiable Trait

Thông báo thể được gửi thông qua 2 cách: sử dụng hàm notify của Notifiable trait hoặc sử dụng Notification facade. Đầu tiên, hãy xem Notifiable trait. Nó được sử dụng bởi model App\User mặc định và chưa một hàm có thể được dùng để gửi thông báo: notify. Hàm notify nhận một thông báo:

use App\Notifications\InvoicePaid;

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

Ghi nhớ, bạn có thể dùng Illuminate\Notifications\Notifiable trait trong bất cứ model nào. Bạn không bị giới giạn chỉ ở model User.

Sử dụng Notification Facade

Ngoài ra, bạn có thể gửi thông báo qua Notification facade. Nó sẽ hữu ích khi bạn cần gửi một thông báo đến nhiều thực thể như một collection của người dùng. Để gửi thông báo sử dụng facade, truyền tất cả các thực thể và thông báo vào hàm send:

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

Specifying Delivery Channels

Mọi class thông báo có một hàm via để xác định kênh thông báo sẽ được phục vụ. Thông báo có thể được gửi bằng mail, database, broadcast, nexmo, và slack.

Nếu bạn muốn sử dụng kênh phục vụ khác như Telegram hoặc Pusher, xem tại Laravel Notification Channels website.

Hàm via nhận một $notifiable, là thể hiện của class đang được gửi. YBạn có thể dùng $notifiable để xác định kênh thông báo được phục vụ:

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

Queueing Notifications

Trước khi queue thông báo bạn nên cấu hình queue và start a worker.

Gửi thông báo có thể mất thời gian, đặc biệt nếu kênh cần một API ngoài để gọi phục vụ thông báo. Để tăng tốc ứng dụng của bạn, bạn cần đặt nó vào queue bởi ShouldQueue interface và Queueable trait trong class. Interface và trait được thêm vào tất cả các thông báo được tạo ra sử dụng lệnh make:notification, vì vậy bạn có thể trực tiếp them chúng vào trong class thông bá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;

    // ...
}

Khi ShouldQueue interface được thêm vào ứng dụng, bạn có thể gửi thông báo bình thương. Laravel sẽ xác định ShouldQueue interface trong class và tự động queue phục vụ thông báo:

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

Nếu bạn muốn hoãn thông báo, bạn có thể chain hàm delay vào trong instantiation thông báo:

$when = Carbon::now()->addMinutes(10);

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

Thông báo Mail

Formatting Mail Messages

Nếu một thông báo được gửi như email, bạn nên định nghĩa một hàm toMail trong class thông báo. Hàm này sẽ nhận một thực thể $notifiable và nên trả về một Illuminate\Notifications\Messages\MailMessage instance. Nội dung mailcó thể chứa nhiều dòng text như "call to action". Hãy xem một ví dụ hàm toMail bên dưới:

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

Nếu chúng ta sử dụng $this->invoice->id trong hàm message. Bạn có thể truyền bất kỳ thông báo cần thiết để tạo nội dung thông báo vào hàm constructor.

Trong ví dụ này, chúng ta đăng ký một buổi gặp mặt, một dòng text, một hành động, và một dòng text khác. Hàm này cung cấp bởi MailMessage object tạo nó đơn giản và nhanh để format transactional emails nhỏ. Kênh mail sẽ được dịch nội dung có css cho bạn, responsive HTML email template với một bản sao plain-text. Đây là một ví dụ tạo mail bởi kênh mail:

Khi gửi thông báo mail, đảm bảo rằng đã đặt giá trị name tên vào trong file cấu hình config/app.php. Giá trị này sẽ được sử dụng trong header và footer của nội dung thông báo mail.

Tùy biến người nhận

Khi gửi thông báo qua kênh mail, thông báo hệ thống sẽ tự động tìm thuộc tính email trong thực thể notifiable. Bạn có thể tùy biến mail được sử dụng để phục vụ gửi thông báo bằng cách định nghĩa một hàm routeNotificationForMail trong thực thể:

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

Tùy biến chủ đề

Mặc định, chủ để của mail trong tên class của thông báo có dạng "title case". Vì vậy, nếu tên class thông báo của bạn là InvoicePaid, mail sẽ có chủ đề là Invoice Paid. Nếu bạn muốn thay đổi, bạn có thể gọi hàm subject khi xây dựng nội dung:

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

Tùy biến Templates

Bạn có thể chỉnh sửa HTML và plain-text template sử dụng thông báo mail bằng cách publishing gói thông báo resources. Sau khi chạy lệnh này, templates mail thông báo sẽ nằm tại resources/views/vendor/notifications:

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

Error Messages

Một số thông báo lỗi cho người dùng, như thanh toán hóa đơn thất bại. Bạn có thể biểu hiện nó bằng một email thông báo lỗi bằng cách gọi hàm error method when building your message. When using the error trong mail thông báo, nó sẽ có một action có màu đỏ thay vì màu xanh:

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

Thông báo Database

Điều kiện cần thiết

Kênh database lưu thông tin thông báo vào database. Bảng này sẽ chứa thông tin như là kiểu thông báo cũng như kiểu JSON để miêu tả thông tin của thông báo.

Bạn có thể truy vấn vào bảng để hiển thị thông báo nên ứng dụng. Nhưng, trước khi bạn làm điều này, bạn cần tạo một bảng để lưu nó lại. Bạn dùng lệnhnotifications:table để tao file migrate chứa các thuộc tính của bảng:

php artisan notifications:table

php artisan migrate

Formatting Database Notifications

Nếu một thông báo lưu trong cơ sở dữ liệu, bạn nên định nghĩa một hàm toDatabase hoặc toArray trong class thông báo. Hàm này sẽ nhận về một thực thể $notifiable và lên trả về một mảng plain PHP. mảng trả về sẽ được encode JSON và lưu tại cột data của bảng notifications. Hãy xem ví dụ hàm 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 với toArray

Hàm toArray ngoài ra được sử dụng bởi kênhbroadcast để xác định thông tin vào broadcast vào JavaScript client. Nếu bạn muốn có hai mảng representations cho kênhdatabasebroadcast, bạn nên định nghĩa một hàm toDatabase thay thế hàm toArray.

Accessing The Notifications

Khi thông báo đã được lưu vào database, bạn sẽ lấy nó khá là đơn giản. Illuminate\Notifications\Notifiable trait, nó được mặc định thêm vào bởi Laravel trong model App\User, them một notifications Eloquent relationship sẽ trả về thông báo của thực thể. Để làm mới thông báo, bạn có thể truy cập phương thức này như bất kỳ Eloquent relationship. Mặc định, thông báo sẽ được sắp xếp theo created_at timestamp:

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

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

Nếu bạn muốn nhận những thông báo "chưa đọc", bạn có thể sử dụng unreadNotifications relationship. Một lần nữa, những thông báo đó sẽ sắp xếp theo created_at timestamp:

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

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

Để truy cập thông báo từ JavaScript client, bạn nên định nghĩa một controller thông báo cho ứng dụng mà sẽ trả về những thông báo cho thực thể notifiable, như người dùng hiện tại. Bạn có thể tạo một HTTP request vào controller URI từ JavaScript client.

Marking Notifications As Read

Thông thường, bạn muốn đánh dấu thông báo "đã đọc" khi nghười dùng xem nó. Hàm Illuminate\Notifications\Notifiable trait cung cấp một hàm markAsRead, nó sẽ cập nhật cột read_at trong bảng record notification database:

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

foreach ($user->unreadNotifications as $notification) {
    $notification->markAsRead();
}

Tuy nhiên, thay vì dùng vòng lặp qua mỗi thông báo, bạn có thể sử dụng hàm markAsRead trong một collection của thông báo:

$user->unreadNotifications->markAsRead();

Ngoài ra bạn có thể sử dụng cập nhật hàng loạt để đánh dấu tất cả các thông báo đã đọc mà không cần nhận chúng từ database:

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

$user->unreadNotifications()->update(['read_at' => Carbon::now()]);

Tất nhiên, bạn có thể dùng hàm delete để xóa chúng khỏi bảng:

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

Broadcast Notifications

Điều kiện cần thiết

Trước khi broadcasting thông báo, bạn nên cấu hình giống với event broadcasting services. Event broadcasting cung cấp một cách để tiếp cận vào server-side bắn ra Laravel từ JavaScript client.

Formatting Broadcast Notifications

Kênh broadcast thông báo broadcasts sử dụng event broadcasting services của Laravel, cho phép JavaScript client để bắt thông báo realtime. Nếu một thông báo broadcasting, bạn nên định nghĩa một hàm toBroadcast hoặc toArray trong class thông báo. Hàm này sẽ nhận về một thực thể $notifiable và nên trả về một mảng plain PHP. Và mảng này sẽ được encoded thành JSON và broadcast vào JavaScript client. Hãy xem ví dụ hàm toArray sau:

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

Ngoài các dữ liệu bạn chỉ định, thông báo broadcast ngoài ra còn chứa trường type chứa tên class của thông báo.

toBroadcast với toArray

Hàm toArray ngoài ra còn được sử dụng bởi kênh database để xác định dữ liệu nào được lưu vào database. Nếu bạn muốn có hai mảng khác representations cho kênh databasebroadcast, bạn nên định nghĩa một hàm toBroadcast thay cho hàm toArray.

Listening For Notifications

Thông báo sẽ được broadcast trong private kênh sử dụng {notifiable}.{id}. Vì vậy, nếu bạn gửi thông báo vào một App\User instance với id là 1, thông báo sẽ broadcast trong App.User.1 kênh private. Khi sử dụng Laravel Echo, bạn có thể dễ dàng lắng nghe một kênh sử dụng hàm notification helper:

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

SMS Notifications

Điều kiện cần thiết

Gửi thông báo SMS trong Laravel bởi Nexmo. Để gửi được thông báo qua Nexmo, bạn cần cài đặt nexmo/client Composer package và thêm một vài cấu hình tùy chọn vào trong file cấu hìnhconfig/services.php. Bạn có thể copy ví dụ cấu hình sau để bắt đầu:

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

Tùy chọn sms_from là số điện thoại gửi SMS sẽ được gửi. Bạn nên tạo một số điện thoại trong Nexmo control panel.

Formatting SMS Notifications

Nếu một thông báo hỗ trợ gửi SMS, bạn nên định nghĩa một hàm toNexmo trong class thông báo. Nó sẽ nhận một thực thể $notifiable và trả về một Illuminate\Notifications\Messages\NexmoMessage instance:

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

Customizing The "From" Number

Nếu bạn muốn gửi thông báo từ một số điện thoại khác với số điện thoải từ file cấu hình config/services.php, bạn có thể dùng hàm from trong NexmoMessage instance:

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

Routing SMS Notifications

Khi gửi thông báo qua kênh nexmo, thông báo sẽ tự động tìm thuộc tính phone_number trong thực thể notifiable. Nếu bạn muốn tùy biến số điện thoại được phục vụ, định nghĩa một hàm routeNotificationForNexmo trong thực thể:

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

Slack Notifications

Điều kiện cần thiết

Trước khi bạn có thể gửi qua Slack, bạn cần cài thư viện Guzzle HTTP library qua Composer:

composer require guzzlehttp/guzzle

Ngoài ra bạn cần cấu hình tích hợp "Incoming Webhook" cho team Slack. Slack này sẽ cung cấp cho bạn một URL routing Slack notifications.

Formatting Slack Notifications

Nếu một thông báo hỗ trợ qua thông báo của Slack, bạn nên định nghĩa một hàm toSlack trong class thông báo. Hàm này sẽ nhận một thực thể $notifiable và trả về một Illuminate\Notifications\Messages\SlackMessage instance. Thông báo Slack có thể chứa nội dung text cũng như "đính kèm". Hãy xem ví dụ đơn giản 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!');
}

Trong ví dụ trên chúng ta chỉ gửi một dòng text vào Slack, nó sẽ tạo ra một dòng text và nhìn như bên dưới:

Slack Attachments

Ngoài ra bạn có thể "attachments" vào Slack. Attachments cung cấp nhiều loại hơn là text. Trong ví dụ này, chúng ta sẽ gửi một thông báo lỗi về exception xảy ra trong ứng dụng, gồm link để xem chi tiết về exception:

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

Ví dụ trên sẽ sinh ra một thông báo slack nhìn giống như sau:

Attachments ngoài ra còn cho phép bạn chỉ định một mảng được gửi cho người dùng. Mảng này sẽ được hiện theo kiểu bảng rất dễ để đọc:

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

Ví dụ trên sẽ sinh ra một thông báo slack giống như sau:

Customizing The Sender & Recipient

Bạn có thể dùng hàm fromto để tùy biến sender và recipient. Hàm from nhận tên người dùng mà emoji identifier, trong khi to nhận tên kênh hoặc username:

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

Routing Slack Notifications

Để route Slack notifications để lơi muốn đến, định nghĩa một hàm routeNotificationForSlack trong thực thể notifiable. Hàm này sẽ trả về một webhook URL nơi mà thông báo sẽ được phục vụ. Webhook URLs có thể được sinh bởi "Incoming Webhook" service vào Slack team:

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

Notification Events

Khi một thông báo được gửi, Event Illuminate\Notifications\Events\NotificationSent được bắn ra bởi thông báo hệ thống. Nó chứa thực thể "notifiable" và thông báo instance của chính nó. YBạn có thể đăng ký lắng nghe cho event này trong EventServiceProvider:

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

Sau khi đăng ký EventServiceProvider, sử dụng lệnh event:generate để tạo nhanh listener classes.

Bên trong event listener, bạn có thể truy cập thuộc tính notifiable, notification, và channel trong event để tìm hiểu thêm về thông báo nhận hoặc thông báo của chính nó:

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

Custom Channels

Laravel chỉ có sẵn vài kênh thông bao, nhưng nếu bạn muốn viết riêng một drivers để phục vụ thông báo các kênh khác. Laravel làm điều này rất đơn giản. Để bắt đầu, định nghĩa một class chứa một hàm send. Hamfnayf nhận hai tham số: $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...
    }
}

Khi class kênh của bạn được định nghĩa, bạn có thể trả về tên class từ hàm via của bất kỳ thông báo nào:

<?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)
    {
        // ...
    }
}
Nguồn: https://laravel.com/docs/5.3/notifications