Notification System
Introduction
BowPHP's messaging system is a powerful tool that lets you send notifications through different channels (email, database, SMS). It is designed to be flexible, extensible, and easy to use.
Whether you need to send welcome emails, activity notifications, or system alerts, the messaging system has you covered.
Configuration
Preparing the Model
To get started, your model must use the WithNotifier trait. This trait adds all the methods needed to send notifications.
use Bow\Notifier\WithNotifier;
use Bow\Database\Barry\Model;
class User extends Model
{
use WithNotifier;
}
Creating Notifications
Basic Structure
A notification is a class that extends Notifier. Here is a complete example of a welcome notification:
use Bow\Notifier\Notifier;
use Bow\Mail\Envelop;
use Bow\Database\Barry\Model;
class WelcomeNotifier extends Notifier
{
/**
* Constructor - passes data to the notification
*/
public function __construct(
private string $customMessage = "Bienvenue!"
) {
}
/**
* Configures the email message
*/
public function toMail(Model $context): ?Envelop
{
return (new Envelop())
->to($context->email)
->subject('Bienvenue sur notre plateforme!')
->view('emails.welcome', [
'user' => $context,
'message' => $this->customMessage
]);
}
/**
* Configures the database notification
*/
public function toDatabase(Model $context): array
{
return [
'type' => 'welcome_notification',
'data' => [
'user_id' => $context->id,
'message' => $this->customMessage,
'created_at' => now()
]
];
}
/**
* Defines the channels to use
*/
public function channels(Model $context): array
{
// You can add conditional logic
if ($context->preferences['email_notifications']) {
return ['mail', 'database'];
}
return ['database'];
}
}
Common Notification Examples
Password Reset Notification
class PasswordResetNotifier extends Notifier
{
public function __construct(
private string $token
) {
}
public function toMail(Model $context): Envelop
{
$resetUrl = url("/password/reset/{$this->token}");
return (new Envelop())
->to($context->email)
->subject('Réinitialisation de votre mot de passe')
->view('emails.password-reset', [
'user' => $context,
'resetUrl' => $resetUrl,
'expiresIn' => '60 minutes'
]);
}
public function channels(Model $context): array
{
return ['mail'];
}
}
Activity Notification
class NewCommentNotifier extends Notifier
{
public function __construct(
private array $commentData
) {
}
public function toMail(Model $context): Envelop
{
return (new Envelop())
->to($context->email)
->subject('Nouveau commentaire sur votre post')
->view('emails.new-comment', [
'user' => $context,
'comment' => $this->commentData
]);
}
public function toDatabase(Model $context): array
{
return [
'type' => 'new_comment',
'data' => [
'post_id' => $this->commentData['post_id'],
'comment_id' => $this->commentData['id'],
'commenter' => $this->commentData['user_name'],
'excerpt' => substr($this->commentData['content'], 0, 100)
]
];
}
public function channels(Model $context): array
{
return ['mail', 'database'];
}
}
Sending Notifications
Simple Sending
Simple sending is synchronous and immediate:
// Send a basic welcome notification
$user->sendMessage(new WelcomeNotifier());
// Send with a custom message
$user->sendMessage(new WelcomeNotifier("Ravi de vous avoir parmi nous!"));
// Send a password reset notification
$user->sendMessage(new PasswordResetNotifier($token));
// Send a new comment notification
$user->sendMessage(new NewCommentNotifier([
'id' => 1,
'post_id' => 123,
'user_name' => 'John Doe',
'content' => 'Super article!'
]));
Queued Sending
Queued sending is asynchronous and delivers better performance. Use this method for non-critical notifications.
// Default queue
$user->setMessageQueue(new WelcomeNotifier());
// Specific queue with priority
$user->sendMessageQueueOn('high-priority', new PasswordResetMessage($token));
// Delayed sending (useful for reminders)
$user->sendMessageLater(
3600, // delay in seconds (1 hour)
new ReminderMessage("N'oubliez pas de compléter votre profil!")
);
// Delayed sending on a specific queue
$user->sendMessageLaterOn(
1800, // 30 minutes
'reminders',
new ReminderMessage("Finalisez votre commande!")
);
Notification Channels
BowPHP ships with five channels by default. Each one corresponds to a
to<Channel>() method that you may (or may not) implement in your notification:
| Channel | Key | Method to implement | Bundled adapter |
|---|---|---|---|
mail | toMail(Model) | MailChannelAdapter | |
| Database | database | toDatabase(Model) | DatabaseChannelAdapter |
| SMS | sms | toSms(Model) | SmsChannelAdapter |
| Slack | slack | toSlack(Model) | SlackChannelAdapter |
| Telegram | telegram | toTelegram(Model) | TelegramChannelAdapter |
Your notification's channels(Model) method decides which channels to enable
for a given context. Only the channels it returns call their to<Channel>()
method; the other to* methods inherited from Notifier remain unused.
Email
The email channel is perfect for important communications. Here is a complete example of an email notification:
public function toMail(Model $context): Envelop
{
return (new Envelop())
->to($context->email)
->cc('support@example.com')
->bcc('archives@example.com')
->subject('Sujet Important')
->view('emails.template', [
'user' => $context,
'data' => $this->data
])
->attach('/chemin/vers/fichier.pdf')
->priority('high');
}
Database
The database channel is ideal for in-app notifications.
Here is the complete structure of the notifications table required for the database channel:
CREATE TABLE notifications (
id CHAR(36) PRIMARY KEY,
concern_id BIGINT NOT NULL,
concern_type VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL,
data JSON NOT NULL,
read_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Advanced usage example:
public function toDatabase(Model $context): array
{
return [
'type' => 'system_notification',
'data' => [
'title' => 'Mise à jour Système',
'message' => 'Une nouvelle version est disponible',
'action_url' => '/settings/updates',
'action_text' => 'Mettre à jour maintenant',
'severity' => 'high',
'icon' => 'update-icon',
'metadata' => [
'version' => '2.0.0',
'changes' => ['feature1', 'feature2']
]
]
];
}
Extending the System
You can create your own custom channels to send notifications through other means (SMS, Slack, Push, etc.).
Creating a New Channel
A custom channel is a class that implements
Bow\Notifier\Contracts\ChannelAdapterInterface and exposes a
send(Model $context, Notifier $notifier): void method.
Example of a channel that logs notifications:
namespace App\Notifier\Channels;
use Bow\Database\Barry\Model;
use Bow\Notifier\Contracts\ChannelAdapterInterface;
use Bow\Notifier\Notifier;
class LogChannel implements ChannelAdapterInterface
{
public function send(Model $context, Notifier $notifier): void
{
if (!method_exists($notifier, 'toLog')) {
throw new \InvalidArgumentException('The notifier must define a toLog method.');
}
$log = $notifier->toLog($context);
logger()->log($log);
}
}
Registering the New Channel
To register your new channel, you must add it to the application configuration. In your App\Configurations\ApplicationConfiguration.php file, add the following code to the create() method:
public function create(Loader $config): void
{
Notifier::pushChannels([
'log' => LogChannel::class
]);
}
Best Practices
Follow these best practices for a robust and high-performing messaging system.
- Segmentation - Create specific notifications for each use case
- Queues - Use queues for non-urgent notifications
- Personalization - Let users choose their preferred channels
- Testing - Test your notifications with real-world cases
- Monitoring - Watch for sending failures and put retry strategies in place
Debugging
To debug your notifications, you can:
// Log the sends
Log::info('Envoi de notification', [
'type' => get_class($notification),
'user' => $context->id,
'channels' => $notification->channels($context)
]);
// Test in a local environment (the second argument writes to the config)
config('mail.default', 'log');
Is something missing?
If you run into problems with the documentation or have suggestions to improve the documentation or the project in general, please open an issue for us, or send a tweet mentioning the Twitter account @bowframework or directly on github.