Every SaaS ends up building the same thing: a notification settings screen where users opt in/out of email, push, Slack, etc., per category. The logic always leaks into via() arrays and policy classes scattered across the app.
I extracted this into a package: Laravel Notify Matrix.
The problem
// Before — what every Laravel app eventually does:
public function via($notifiable): array
{
$channels = ['database'];
if ($notifiable->wantsMail('orders')) {
$channels[] = 'mail';
}
if ($notifiable->wantsSlack('orders') && config('app.slack_enabled')) {
$channels[] = 'slack';
}
return $channels;
}
The package
// User model
use Scabarcas\LaravelNotifyMatrix\Concerns\HasNotificationPreferences;
class User extends Authenticatable
{
use HasNotificationPreferences;
}
// Notification class
use Scabarcas\LaravelNotifyMatrix\Attributes\NotificationGroup;
#[NotificationGroup('orders')]
class OrderShipped extends Notification
{
public function via($notifiable): array
{
return ['mail', 'database'];
}
}
// Anywhere
$user->wants('orders', 'mail');
$user->disable('orders', 'mail');
$user->enable('orders', 'database');
$user->getPreferencesForGroup('orders');
$user->clearPreferences('orders');
The via() method stays the same — declarative, naive, no conditionals.
How it works under the hood
A listener on Illuminate\Notifications\Events\NotificationSending returns false for channels the user has opted out of. Forced channels bypass user preferences. Notifications without a #[NotificationGroup] attribute or class_map entry are ignored entirely.
The resolution order:
- Channel is in
groups.<group>.forced→ deliver. - User has a stored preference row → use it.
- Otherwise, group
default_policydecides (with fallback to the global default).
Architecture notes
-
PreferenceManagerorchestrates resolution. -
PreferenceRepositoryandGroupResolverare interfaces — swap for Redis, event-based resolvers, or anything else. - The trait is a thin facade over the manager.
- Tests run on Pest + Orchestra Testbench against SQLite in-memory.
Links
- Repo: https://github.com/scabarcas17/laravel-notify-matrix
- Packagist: https://packagist.org/packages/scabarcas/laravel-notify-matrix
Feedback welcome.
Top comments (0)