Found a flexible way to allow all channels to attempt sending, even if one fails. This approach also lets you handle specific errors (e.g., clearing an FCM token upon failure). The core idea is to override the Notification class to set a temporary channel and create a custom NotificationService that iterates through each channel by setting the temporary channel .
class NotificationService
{
public function notify(object $notifiable, BaseNotification $notification)
{
$listOfChannels = $notification->via($notifiable);
foreach ($listOfChannels as $channel) {
$notification->setCurrentChannel($channel);
try {
$notifiable->notify($notification);
} catch (CouldNotSendNotification $e) {
// TODO: specific error handling (e.g., clear FCM token)
} catch (\Exception $e) {
// TODO: general error handling
}
}
$notification->clearCurrentChannel();
}
}
class BaseNotification extends Notification
{
public string $currentChannel;
public function via($notifiable)
{
return $this->currentChannel ? [$this->currentChannel] : ['database', 'mail', FcmChannel::class];
}
public function setCurrentChannel(string $channel): void
{
$this->currentChannel = $channel;
}
public function getCurrentChannel(): string
{
return $this->currentChannel;
}
public function clearCurrentChannel(): void
{
$this->currentChannel = '';
}
}
class MyProgramOrJob {
public function run()
{
// $notifiable
// $notification - you custom notificaiton that extend BaseNotification
(new NotificationService)->notify(
$notifiable,
$notification,
);
}
}