Asked May 25th, 2018 2:11 AM 141 2 1
  • 141 2 1
+3

Lấy thông tin người dùng để show notification

Share
  • 141 2 1

Mọi người cho em hỏi, notifications table như thế thì làm sao lấy ra được thông tin của người dùng đã comment được không ạ? Vì em đang làm thông báo khi có người nào đó comment vào bài viết post và gửi thông báo (notification) đến tác giả của bài viết ạ... Nhưng e chưa biết cách làm ạ..

E làm theo cách như trong video

public function up()
{
    Schema::create('notifications', function (Blueprint $table) {
        $table->uuid('id')->primary();
        $table->string('type');
        $table->morphs('notifiable');
        $table->text('data');
        $table->timestamp('read_at')->nullable();
        $table->timestamps();
    });
}

1 ANSWERS


Answered May 25th, 2018 3:31 AM
Accepted
+5

Cách hoạt Notificaion hoạt động

@minhtuancnttk39 Ý bạn là: Người dùng U1 comments bài post của ông U2. Notification báo về cho U2 rằng ông U1 đã comment vào bài viết. Chúng ta sẽ coi U1 là người đóng vai trò gửi notification ở đây.

  • Cách 1: Bạn có thể lưu thêm sender_id tức id của người dùng U1 - tác nhân dẫn tới gửi notification. Lưu thêm sender_id như vậy thì việc truy vấn sẽ linh hoạt hơn sau này.
  • Cách 2: Ngoài ra, nếu chỉ để hiển thị thông tin người gửi ra cho U2 thôi thì bạn có thể return thêm thông tin người người qua method: toDatabase hoặc toArray bên trong class Notification.
public function toArray()
{
    return [
        'sender' => [
            'id' => 1,
            'name' => 'Nguyen Huu Kim',
            'avatar' => 'da1ad1-fdsafa',
            'url' => '/u/huukimit',
        ],
    ];
}

Implement theo Cách 1

Cách 2 đơn giản hơn, tuy nhiên nó không linh hoạt, giả sử như avatar U1 thay đổi thì dữ liệu notification ko thay đổi, U1 vẫn thấy thông tin cũ. Hay trang /u/huukimit thay đổi, khi click vào notification cũ sẽ bị lỗi. Bởi vậy nên mình nói là nó ko linh hoạt.

Trước hết, bạn cần hiểu thêm một chút về hoạt động của Notification. Chúng ta có khái niệm Channel, tạm hiểu là một kênh để thực hiện vận chuyển thông tin của notification đi tới đích.

Chẳng hạn:

  • Để gửi realtime notification tới người U2, Dữ liệu Notification được gửi qua BroadcastChannel.
  • Để lưu vào database, dữ liệu của notification được gửi qua Illuminate\Notifications\Channels\DatabaseChannel.
  • Sau này để push notification, bạn có thể tạo thêm một Channel riêng như FirebaseCloudMessageChannel chẳng hạn.

Thực hiện lưu thêm sender_id

Một Notification có thể gửi qua nhiều Channels. Tất nhiên chúng đều có một method cần implement có tên là send. Và bạn đã biết DatabaseChannel là nơi thực hiện lưu dữ liệu vào database.

Để lưu được sender_id, bạn thực hiện các bước sau giúp mình:

  • Tạo một migration mới, thực hiện thêm column sender_id vào table notifications.
  • Tạo một DatabaseChannel mới, thực hiện overwrite lại method send. Ở đây bạn lưu thêm mọi thứ tùy ý bạn, không chỉ có sender_id.

Lấy thông tin sender:

Đến đây mọi thứ đã sáng tỏ và bạn có thể dễ dàng database query, join notification tới table users và lấy được thông tin sender_id. Chúng bạn thành công.

UPDATE LARAVEL 5.6


  • Kể từ phiển bản laravel 5.6, buildPayload method được thêm mới vào DatabaseChannel. Method send sẽ gọi sang buildPayload để lấy dữ liệu thay vì tự định nghĩa bên trong nó. Chính vì thế, chúng ta overwrite buildPayload thay cho overwrite send để lưu thêm dữ liệu sender.
  • Ngoài ra, mình bổ sung thêm để câu trả lời được hoàn chỉnh hơn, chúng ta cần thêm method via trong class của những Notification cần lưu vào database (Chắc có lẽ là hầu hết). Return một array chứa tên class CustomDatabaseNotification - là DatabaseChannel đã tự tạo ở trên. Như vậy channel CustomDatabaseNotification mới được áp dụng.
Share
Nguyễn Minh Tuấn @minhtuancnttk39
May 25th, 2018 4:25 PM

Bạn cho mình hỏi:

  • Tạo DatabaseChanel mới như thế thì mình đặt tên khác chứ đúng không bạn? Vì DatabaseChanel có sẵn rồi ạ?

  • A có thể cho em hỏi buildPayload method trong DatabaseChanel ta có thể thêm user_id được không ạ? (Ý em là thêm như thế để e có thể truy xuất được người gửi comment để thông báo cho author ấy ạ..

+1
| Reply
Share
May 25th, 2018 4:43 PM

@minhtuancnttk39

Tạo DatabaseChanel mới như thế thì mình đặt tên khác chứ đúng không bạn? Vì DatabaseChanel có sẵn rồi ạ?

Bạn đặt tên như nào cũng được, miễn là class bạn tạo khác namespace và extends cái class cũ. Và overwrite lại method send.

A có thể cho em hỏi buildPayload method trong DatabaseChanel ta có thể thêm user_id được không ạ? (Ý em là thêm như thế để e có thể truy xuất được người gửi comment để thông báo cho author ấy ạ..

Chính xác! Từ phiên bản Laravel 5.6, thay vì khai báo trực tiếp một array trong method send, thì method send sẽ gọi sang buildPayload (được thêm mới) để lấy dữ liệu. Chắc chắn bạn đang dùng Laravel 5.6, như vậy bạn overwrite lại buildPayload là được.

+2
| Reply
Share
Nguyễn Minh Tuấn @minhtuancnttk39
May 25th, 2018 4:51 PM

@huukimit Đây là code chưa custom của buildPayload method ạ...

protected function buildPayload($notifiable, Notification $notification)
    {
        return [
            'id' => $notification->id,
            'type' => get_class($notification),
            'data' => $this->getData($notifiable, $notification),
            'read_at' => null,
        ];
    }

Sau khi e custom lại như code dưới, cùng trong DatabaseChanel luôn ạ, thì nó không lưu được vào DB để query nữa... E đang tìm hiểu tại sao ạ?

protected function buildPayload($notifiable, Notification $notification)
    {
        return [
            'id' => $notification->id,
            'type' => get_class($notification),
            'idUser' => Auth::user()->id,
            'data' => $this->getData($notifiable, $notification),
            'read_at' => null,
        ];
    }
+1
| Reply
Share
May 25th, 2018 5:04 PM

@minhtuancnttk39 Mình có bổ sung thêm thông tin ở cuối câu trả lời để câu trả lời được hoàn chỉnh, có thể tóm gọn lại như sau:

  • B1: Tạo migration, thêm cột mới.
  • B2: Tạo CustomDatabaseChannel, overwrite buildPayload để trả về thêm dữ liệu sender_id cần lưu.
  • B3: Thêm method via vào Notification, để áp dụng lưu dữ liệu qua CustomDatabaseChannel thay thế:
public function via($notifiable)
{
    return [CustomDatabaseChannel::class];
}

Sau khi thực hiện đủ các bước trên, nếu vẫn lỗi bạn mở laravel.log xem nó báo lỗi như nào nha.

+2
| Reply
Share
May 25th, 2018 5:06 PM

Nếu thấy câu trả lời, comment của mình hay và hữu ích, bạn đừng quên vote up nha :v Mục đích không phải vì điểm Viblo cho mình mà là để tạo sự uy tín/hữu ích cho câu trả lời hay comment. Để người khác giống bạn vào đây có cơ sở chọn lọc thông tin mà giải quyết vấn đề. Cũng là giúp nội dung trên Viblo trở nên chất lượng hơn!

+2
| Reply
Share
Nguyễn Minh Tuấn @minhtuancnttk39
May 25th, 2018 5:17 PM

@huukimit Em hiểu ạ.. e rất muốn voteup nhưng e chưa đủ 50 reputations nên e chưa vote được ạ... a thông cảm cho em với ạ... 😦

+2
| Reply
Share
Tú Trần @redmix0901
Aug 13th, 2018 4:15 AM

@huukimit mình muốn truyền thông tin sender_id từ ngoài vào.

public function send($notifiable,$sender_id, Notification $notification)
    {
        return $notifiable->routeNotificationFor('database', $notification)->create(
            $this->buildPayload($notifiable,$sender_id, $notification)
        );
    }

thì truyền vào từ đâu vậy, mình ko hiểu cái send này gọi từ đâu hết.

0
| Reply
Share
Aug 17th, 2018 4:23 AM

@redmix0901 Bạn khởi tạo Notification kèm $sender luôn. Send là method abstract của laravel chỉ có 2 params $notifiable và $notification, bạn không thể can thiệp như kia được.

0
| Reply
Share
Aug 17th, 2018 4:24 AM

Hãy dùng:

$notification = new MyNotification(User $sender, Model $myResource);
$user->notifiy($notification);
0
| Reply
Share