Lấy thông tin người dùng để show notification
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 CÂU TRẢ LỜI
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_idtứ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:
toDatabasehoặctoArraybê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ư
FirebaseCloudMessageChannelchẳ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
DatabaseChannelmới, thực hiện overwrite lại methodsend. Ở đâ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,
buildPayloadmethod được thêm mới vàoDatabaseChannel. Methodsendsẽ gọi sangbuildPayloadđể lấy dữ liệu thay vì tự định nghĩa bên trong nó. Chính vì thế, chúng ta overwritebuildPayloadthay cho overwritesendđể lưu thêm dữ liệusender. - 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
viatrong 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 classCustomDatabaseNotification- làDatabaseChannelđã tự tạo ở trên. Như vậy channelCustomDatabaseNotificationmới được áp dụng.
Bạn cho mình hỏi:
-
Tạo
DatabaseChanelmới như thế thì mình đặt tên khác chứ đúng không bạn? VìDatabaseChanelcó sẵn rồi ạ? -
A có thể cho em hỏi
buildPayloadmethod trongDatabaseChanelta có thể thêmuser_idđược không ạ? (Ý em là thêm như thế để e có thể truy xuất được người gửicommentđể thông báo cho author ấy ạ..
Tạo
DatabaseChanelmới như thế thì mình đặt tên khác chứ đúng không bạn? VìDatabaseChanelcó 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.
@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,
];
}
@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ệusender_idcần lưu. - B3: Thêm method
viavào Notification, để áp dụng lưu dữ liệu quaCustomDatabaseChannelthay 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.
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!
@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 ạ... 
@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.
@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.
Hãy dùng:
$notification = new MyNotification(User $sender, Model $myResource);
$user->notifiy($notification);