laravel-notify-matrix maintained by scabarcas
Laravel Notify Matrix
Manage per-user notification preferences in Laravel. Each user can opt in or out of channels for each notification group.
Installation
composer require scabarcas/laravel-notify-matrix
php artisan vendor:publish --tag=notify-matrix-config
php artisan vendor:publish --tag=notify-matrix-migrations
php artisan migrate
Quick start
Add the trait to the user model (or any notifiable):
use Illuminate\Foundation\Auth\User as Authenticatable;
use Scabarcas\LaravelNotifyMatrix\Concerns\HasNotificationPreferences;
class User extends Authenticatable
{
use HasNotificationPreferences;
}
Tag each notification with the group it belongs to:
use Illuminate\Notifications\Notification;
use Scabarcas\LaravelNotifyMatrix\Attributes\NotificationGroup;
#[NotificationGroup('orders')]
class OrderShipped extends Notification
{
public function via($notifiable): array
{
return ['mail', 'database'];
}
}
Read and write preferences from the model:
$user->wants('orders', 'mail'); // true | false
$user->wants(OrderShipped::class, 'mail'); // resolves the group via the attribute
$user->setPreference('orders', 'mail', false);
$user->enable('orders', 'mail');
$user->disable('orders', 'mail');
$user->getPreferences();
$user->getPreferencesForGroup('orders');
$user->clearPreferences('orders');
With the trait on the notifiable and the attribute on the notification, the dispatch listener filters channels according to stored preferences. Forced channels are always delivered.
Configuration
return [
'table' => 'notification_preferences',
// Applied when no preference exists for a channel within a group.
// Each group may override this below. Supported: "opt_in", "opt_out".
'default_policy' => 'opt_in',
'groups' => [
'marketing' => [
'default_policy' => 'opt_out',
],
'security' => [
'default_policy' => 'opt_in',
'forced' => ['mail'],
],
],
'class_map' => [
// Map notifications that cannot be annotated directly.
// \Vendor\Pkg\Notifications\InvoicePaid::class => 'billing',
],
'cache' => [
'enabled' => true,
'ttl' => 300,
'store' => null,
],
];
Forced channels
Channels listed under groups.<group>.forced are delivered even when the user has opted out. Common use cases are security alerts and account verification messages.
Class map
Third-party notification classes that cannot be annotated with #[NotificationGroup] can be mapped to a group through the class_map entry. Annotated classes always take precedence over the map.
How it works
The package registers a listener for Illuminate\Notifications\Events\NotificationSending that runs before each channel dispatch:
- If the notifiable does not use
HasNotificationPreferences, the listener does not interfere. - If the notification has neither a
#[NotificationGroup]attribute nor aclass_mapentry, the listener does not interfere. - If the channel is listed as forced for the group, the channel is delivered.
- If the user has a stored preference for the channel, that value decides.
- Otherwise, the group default policy decides (or the global default if the group has none).
Testing
composer install
composer test
composer analyse
composer format
Author
Sebastian Cabarcas Berrio · sebastianberrio45@hotmail.com · @scabarcas17
License
MIT © Sebastian Cabarcas Berrio