use NotificationFoundation\QueuedBaseNotification;
class OrderShippedNotification extends QueuedBaseNotification
{
public function __construct(Order $order, User $recipient)
{
// Shared data is merged into every active channel's payload automatically
$sharedData = [
'order_id' => (string) $order->id,
'order_code' => $order->code,
'user_name' => $recipient->name,
];
$this->setSharedData($sharedData)
// FCM gets a tailored title and body on top of shared data
->setDataForFcmChannel([
'title' => 'Your order has shipped',
'body' => "Order #{$order->code} is on its way.",
])
// Database relies on shared data alone — no extra data needed
// SMS is off by default in the service provider; turn it on for this notification
->useSmsChannel()
->setDataForSmsChannel([
'body' => "Hi {$recipient->name}, order #{$order->code} has shipped.",
])
// This order does not trigger an email
->useEmailChannel(false);
}
}
class OrderShippedNotification extends QueuedBaseNotification
{
public function __construct(private string $category, private Order $order)
{
$this->setSharedData(['order_id' => (string) $order->id]);
}
public function toFcm(mixed $notifiable): FcmMessage
{
return parent::toFcm($notifiable)
->mergeData([
'category' => $this->category,
'order_code' => $this->order->code,
]);
}
}
class OrderShippedNotification extends QueuedBaseNotification
{
public function __construct(private Order $order)
{
$this->setSharedData(['order_id' => (string) $order->id]);
}
public function toFcm(mixed $notifiable): FcmMessage
{
return FcmMessage::create()
->title('Your order has shipped')
->body("Order #{$this->order->id} is on its way.")
->setData($this->getSharedData())
->android(['priority' => 'high'])
->apns(['headers' => ['apns-priority' => '10']]);
}
}
(new OrderShippedNotification($order))
->useFcmChannel(false)
->useSmsChannel(true)
->useEmailChannel(); // any registered channel works the same way
public function boot(): void
{
BaseNotification::registerChannel('database', 'database', true);
BaseNotification::registerChannel('fcm', FcmChannel::class, true);
BaseNotification::registerChannel('sms', SmsChannel::class, false);
// Custom channels get the same toggle and data-setter API automatically
// BaseNotification::registerChannel('mail', 'mail', false);
// BaseNotification::registerChannel('slack', SlackChannel::class, false);
}
use NotificationFoundation\Contracts\FcmDriverContract;
use NotificationFoundation\Contracts\SmsDriverContract;
$this->app->bind(FcmDriverContract::class, YourFcmDriver::class);
$this->app->bind(SmsDriverContract::class, YourSmsDriver::class);
use NotificationFoundation\Contracts\FcmDriverContract;
use NotificationFoundation\Messages\FcmMessage;
class MyFcmDriver implements FcmDriverContract
{
public function send(FcmMessage $message, string|array $tokens): void
{
if (is_array($tokens)) {
$this->sendMany($message, $tokens);
} else {
$this->sendOne($message, $tokens);
}
}
private function sendOne(FcmMessage $message, string $token): void
{
// send $message->toArray($token) to the FCM HTTP v1 API
}
private function sendMany(FcmMessage $message, array $tokens): void
{
// use a batch API if your provider supports it, or loop sendOne()
foreach ($tokens as $token) {
$this->sendOne($message, $token);
}
}
}
use NotificationFoundation\Contracts\SmsDriverContract;
use NotificationFoundation\Messages\SmsMessage;
class MyProvider implements SmsDriverContract
{
public function send(SmsMessage $message): void
{
// deliver $message->getContent() to $message->getTo()
// optionally route to sendOne() / sendMany() based on recipient type
}
}
public function routeNotificationForFcm($notification): string|array
{
return $this->fcm_tokens; // single token or array for multi-device
}
// On the notifiable model:
public function routeNotificationForSms($notification): string
{
return $this->phone_number;
}
// Or in toSms():
return SmsMessage::create('Your OTP is 1234')->to($notifiable->phone);
return SmsMessage::create('Your OTP is 1234')
->to($notifiable->phone)
->from('MyApp');
protected function setUp(): void
{
parent::setUp();
BaseNotification::flushChannelRegistry();
}
protected function tearDown(): void
{
BaseNotification::flushChannelRegistry();
parent::tearDown();
}