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_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ặctoArray
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 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,
buildPayload
method được thêm mới vàoDatabaseChannel
. Methodsend
sẽ 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 overwritebuildPayload
thay 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
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 classCustomDatabaseNotification
- làDatabaseChannel
đã tự tạo ở trên. Như vậy channelCustomDatabaseNotification
mới được áp dụng.
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 trongDatabaseChanel
ta 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
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.
@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_id
cần lưu. - B3: Thêm method
via
vào Notification, để áp dụng lưu dữ liệu quaCustomDatabaseChannel
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.
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);