訊息通知系統記錄

xiaofan086發表於2018-08-07

簡介

Laravel 自帶了一套訊息通知系統,還支援多種通知頻道,包括資料庫、郵件、簡訊等。
此處我們詳細說明資料庫通知頻道

建立通知類

Laravel 中一條通知就是一個類,(通常在 app/Notifications 檔案裡),命令如下:

php artisan make:notification TopicReplied

每個通知類都包含一個 via 方法 以及多個訊息構造方法( 如toMail或toDatabase )
via() 決定了通知在哪個頻道上傳送,如在資料庫作為通知:

public function via($notifiable)
{
    // 開啟通知的頻道
    return ['database'];
}

而toDatabase($notifiable)方法會返回一個陣列將被轉化為json格式並儲存到 notifications 資料表中的data欄位中。

資料庫通知

資料庫通知頻道會在一張資料表裡儲存所有資訊,包含了比如通知型別、JSON 格式資料等描述通知的資訊。
可以查詢此表的內容在應用介面上展示通知。

1.首先建立生成遷移表

php artisan notifications:table

會生成 database/migrations/{$timestamp}_create_notifications_table.php 遷移檔案

2.生成資料表

php artisan migrate

3.記錄未讀通知

在users表中新增 notification_count 欄位,用來跟蹤使用者有多少通知

php artisan make:migration add_notification_count_to_users_table --table=users

開啟生成的檔案,修改如下:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->integer('notification_count')->unsigned()->default(0);
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('notification_count');
    });
}

應用資料庫修改

php artisan migrate

傳送通知

1.讀取通知說明

在User模型類使用了Notifiable trait,而Notifiable中又引入了 HasDatabaseNotifications trait。
HasDatabaseNotifications中有3個函式,分別是 獲取所有通知、獲取未讀通知 和 已讀通知。

trait HasDatabaseNotifications
{
    public function notifications()
    {
        return $this->morphMany(DatabaseNotification::class, 'notifiable')
                            ->orderBy('created_at', 'desc');
    }

    public function readNotifications()
    {
        return $this->notifications()
                            ->whereNotNull('read_at');
    }

    public function unreadNotifications()
    {
        return $this->notifications()
                            ->whereNull('read_at');
    }
}

由上可見,HasDatabaseNotifications 通過 關聯DatabaseNotification類讀取通知,在DatabaseNotification類中定義了$table = 'notifications' 。
此外 獲取未讀通知 unreadNotifications 方法 是根據 read_at 欄位作為判斷條件。
還有 DatabaseNotification 模型類中 定義了 標記訊息已讀的方法 markAsRead 和 標記訊息未讀的方法markAsUnread 。

2.觸發通知說明

Notifiable中引用了RoutesNotifications trait ,而RoutesNotifications定義了 notify($instance) 方法用來傳送通知

3.相關程式碼

app/Observers/ReplyObserver.php:

use App\Notifications\TopicReplied;
class ReplyObserver
{
    public function created(Reply $reply)
    {
        $topic = $reply->topic;
        $topic->increment('reply_count', 1);

        // 通知作者話題被回覆了
        $topic->user->notify(new TopicReplied($reply));
    }
}

app/Models/User.php

use Auth;

class User extends Authenticatable
{
    use Notifiable {
        notify as protected laravelNotify; // 把系統的notify方法重新命名為laravelNotify
    }
    // 對notify()方法的重寫
    public function notify($instance)
    {
        // 如果要通知的人是當前使用者,就不必通知了!
        if ($this->id == Auth::id()) {
            return;
        }
        $this->increment('notification_count');
        $this->laravelNotify($instance);
    }
}

相關檢視

生成控制器

php artisan make:controller NotificationsController

修改路由

Route::resource('notifications', 'NotificationsController', ['only' => ['index']]);

通知檢視

class NotificationsController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function index()
    {
        // 獲取登入使用者的所有通知
        $notifications = Auth::user()->notifications()->paginate(20);
        return view('notifications.index', compact('notifications'));
    }
}

標記通知為已讀

在 app/Models/User.php 中新增

public function markAsRead()
{
    $this->notification_count = 0;
    $this->save();
    $this->unreadNotifications->markAsRead();
}

修改NotificationsController中index()新增

// 標記為已讀,未讀數量清零
Auth::user()->markAsRead();
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章