I'm not sure if I'm overcomplicating events/listeners/notifications in Laravel, but it feels like maybe I am, and I'm getting some unexpected results, although technically it's working.
My basic structure is this:
MonthlySummaryCompletedEvent
is fired.- The
HandleMonthlySummaryCompletedEvent
listener listens for the event. - It triggers a
SendMonthlySummaryCreatedNotification
notification.
This is all working (locally at least), except for 2 things:
- I've had to put in a 5 second sleep in my livewire component that receives the notification because of timing issues. It almost seems like the pusher notification arrives before the notification has been written to the database.
- It appears that 2 messages are sent to pusher:
Here's the code for my event:
class MonthlySummaryCompletedEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public User $requestedBy;
public string $fileDownloadUrl;
public string $fileName;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($event, string $fileDownloadUrl, string $fileName)
{
$this->requestedBy = $event->requestedBy;
$this->fileDownloadUrl = $fileDownloadUrl;
$this->fileName = $fileName;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('users.' . $this->requestedBy->id);
}
}
here's the code for my listener:
class HandleMonthlySummaryCompletedEvent implements ShouldQueue
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
Notification::send($event->requestedBy, new SendMonthlySummaryCreatedNotification($event));
}
}
and here's the code for the notification:
class SendMonthlySummaryCreatedNotification extends Notification implements ShouldQueue, ShouldBroadcast
{
use Queueable;
public $fileDownloadUrl;
public $fileName;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($event)
{
$this->fileDownloadUrl = $event->fileDownloadUrl;
$this->fileName = $event->fileName;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['database', 'broadcast'];
}
/**
* Get the broadcastable representation of the notification.
*
* @param mixed $notifiable
* @return BroadcastMessage
*/
public function toBroadcast($notifiable)
{
Log::debug($notifiable->toArray());
return new BroadcastMessage([
'title' => 'Monthly Summary Complete',
'message' => "{$this->fileName} is ready. ",
'link' => $this->fileDownloadUrl,
'link_text' => 'Click here to download',
'show_toast' => true,
'user_id' => $notifiable->id
]);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toDatabase($notifiable)
{
return [
'title' => 'Monthly Summary Complete',
'message' => "{$this->fileName} is ready. ",
'link' => $this->fileDownloadUrl,
'link_text' => 'Click here to download',
'show_toast' => true,
'user_id' => $notifiable->id
];
}
}
And here's my front end livewire component:
public function getListeners()
{
return [
"echo-private:users.{$this->user->id},StatementCompleted" => 'notifyUser',
"echo-private:users.{$this->user->id},MonthlySummaryCompletedEvent" => 'notifyUser',
];
}
public function mount()
{
$this->user = Auth::user();
$this->refreshNotifications();
$this->showNotificationsBadge = ($this->notificationCount > 0) ? true : false;
}
public function render()
{
return view('livewire.components.notifications');
}
public function notifyUser()
{
$this->showNotificationsBadge = true;
sleep(5);
$this->refreshNotifications();
$message = $this->notifications->first()->data['message'];
if (isset($this->notifications->first()->data['show_toast']) && $this->notifications->first()->data['show_toast'] == true) {
$this->dispatchBrowserEvent('triggerToast', [Helper::notification('Success', $message)]);
}
}