PHPackages                             w3bdeveloper7/laravel-dynamic-notifier - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. w3bdeveloper7/laravel-dynamic-notifier

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

w3bdeveloper7/laravel-dynamic-notifier
======================================

Dynamic, permission-aware and resolver-driven notifications for Laravel.

00PHPCI passing

Since May 28Pushed 1mo agoCompare

[ Source](https://github.com/W3bDeveloper7/laravel-dynamic-notifier)[ Packagist](https://packagist.org/packages/w3bdeveloper7/laravel-dynamic-notifier)[ RSS](/packages/w3bdeveloper7-laravel-dynamic-notifier/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel Dynamic Notifier
========================

[](#laravel-dynamic-notifier)

Dynamic, permission-aware, resolver-driven notification package for Laravel with **hybrid storage** support.

Install
-------

[](#install)

```
composer require w3bdeveloper7/laravel-dynamic-notifier
php artisan vendor:publish --tag=dynamic-notifier-config
php artisan vendor:publish --tag=dynamic-notifier-migrations
php artisan migrate
```

For Laravel-native mirroring, ensure the Laravel notifications table exists:

```
php artisan notifications:table
php artisan migrate
```

What you get
------------

[](#what-you-get)

- Dynamic recipient resolution by resolver key.
- Permission-based targeting through a pluggable backend contract.
- Preconfigured channel drivers: `database`, `log`, `fcm` (pluggable transport).
- Queue-ready dispatch with retries/backoff from config.
- Idempotency protection for duplicate sends.
- Fail-closed behavior when permission backend is not configured.
- **Hybrid storage**: package audit tables + optional Laravel notifications bridge.

Storage modes
-------------

[](#storage-modes)

Configure in `config/dynamic-notifier.php`:

ModePackage tablesLaravel `notifications` table`canonical`Source of truthNo`laravel`NoSource of truth`hybrid` (default)Source of truthMirrored after successful send```
'storage' => [
    'mode' => env('DYNAMIC_NOTIFIER_STORAGE_MODE', 'hybrid'),
],

'bridge' => [
    'enabled' => env('DYNAMIC_NOTIFIER_BRIDGE_ENABLED', false),
    'write_to_laravel_notifications' => true,
    'via_notification_class' => null, // optional custom notification class name
],
```

### Reliability rules

[](#reliability-rules)

- In `hybrid` mode, package tables remain the canonical audit source.
- Bridge failures do **not** fail canonical delivery; errors are stored in delivery `payload.bridge_error`.
- In `laravel`-only mode, bridge failures fail the job.
- Idempotency applies to both canonical dispatch and Laravel bridge writes.

Architecture
------------

[](#architecture)

 ```
flowchart LR
    AppEvent[AppEvent] --> DynamicNotifier
    DynamicNotifier --> ResolverPipeline[ResolverPipeline]
    ResolverPipeline --> CanonicalStore[CanonicalStore]
    CanonicalStore --> QueueJob[QueueJob]
    QueueJob --> ChannelDriver[ChannelDriver]
    ChannelDriver --> DeliveryLog[DeliveryLog]
    ChannelDriver --> BridgeDecision{BridgeEnabled}
    BridgeDecision -->|yes| LaravelBridge[LaravelBridge]
    BridgeDecision -->|no| EndNoBridge[EndNoBridge]
    LaravelBridge --> LaravelTable[LaravelNotificationsTable]
```

      Loading Quick usage
-----------

[](#quick-usage)

```
use W3bDeveloper7\DynamicNotifier\Contracts\DynamicNotifierInterface;
use W3bDeveloper7\DynamicNotifier\DTO\NotificationContext;

$notifier = app(DynamicNotifierInterface::class);

$notifier->dispatch('booking_confirmed', new NotificationContext(
    entity: $booking,
    replacements: ['user_name' => $booking->bookedByUser->name],
    extra: ['action_id' => $booking->id]
), [
    'title' => 'Booking confirmed',
    'message' => 'Hi :user_name, your booking is confirmed.',
]);
```

Configuring notification types
------------------------------

[](#configuring-notification-types)

`config/dynamic-notifier.php`

```
'notification_types' => [
    'booking_confirmed' => [
        'sends' => [
            [
                'resolver' => 'permission',
                'channels' => ['database', 'fcm'],
                'config' => [
                    'permissions' => ['bookings.show', 'bookings.create'],
                ],
                'title' => 'Booking confirmed',
                'message' => 'A booking has been confirmed',
                'priority' => 'high',
            ],
        ],
    ],
],
```

Laravel bridge requirements
---------------------------

[](#laravel-bridge-requirements)

When mirroring to Laravel notifications, recipients must include notifiable metadata:

```
'recipients' => [
    [
        'id' => 1,
        'meta' => [
            'notifiable_type' => App\Models\User::class,
            'notifiable_id' => 1,
        ],
    ],
],
```

Plug your permission system
---------------------------

[](#plug-your-permission-system)

Implement:

`W3bDeveloper7\DynamicNotifier\Contracts\PermissionBackendInterface`

And bind it in your app service provider:

```
use W3bDeveloper7\DynamicNotifier\Contracts\PermissionBackendInterface;

$this->app->singleton(PermissionBackendInterface::class, App\Notifications\MyPermissionBackend::class);
```

If you do not bind this contract, permission resolver returns empty recipients (safe default).

Pass center scope via context:

```
new NotificationContext(
    extra: ['center_ids' => [$booking->center_id]]
);
```

### Edge Back-End integration

[](#edge-back-end-integration)

When used in Edge Back-End, `Modules\Admin\App\Adapters\AdminPermissionBackendAdapter` is bound automatically. It reuses `Admin::withPermissions()` and center scoping (`manage_all_centers` + `managedCenters`).

FCM uses `KreaitFcmTransport` via `NotificationServiceProvider` when Kreait Firebase is available.

FCM transport
-------------

[](#fcm-transport)

`FcmDriver` delegates to `FcmTransportInterface`:

TransportClassWhen to useLog (default)`LogFcmTransport`Local/dev, package testsKreait`KreaitFcmTransport`Production with `kreait/laravel-firebase````
DYNAMIC_NOTIFIER_FCM_TRANSPORT=W3bDeveloper7\DynamicNotifier\Support\KreaitFcmTransport
```

Or bind in a service provider:

```
$this->app->singleton(FcmTransportInterface::class, KreaitFcmTransport::class);
```

Events
------

[](#events)

EventWhen`NotificationDispatched`Jobs queued for a notification rule`NotificationDelivered`Channel driver finished (sent or failed)`BridgeFailed`Laravel notifications mirror failed in hybrid modeListen for observability, metrics, or custom audit hooks.

Service contract
----------------

[](#service-contract)

Inject `DynamicNotifierInterface` (or use the `DynamicNotifier` facade) for easier mocking in tests.

Migration guidance
------------------

[](#migration-guidance)

### New project (recommended)

[](#new-project-recommended)

1. Set `storage.mode` to `hybrid`.
2. Publish and run package migrations.
3. Run `php artisan notifications:table && php artisan migrate`.
4. Implement `PermissionBackendInterface` for your RBAC system.

### Existing Laravel notifications app

[](#existing-laravel-notifications-app)

1. Start with `storage.mode = laravel` to mirror only to native table.
2. Move to `hybrid` when you want delivery audit/history in package tables.

### Analytics-first setup

[](#analytics-first-setup)

1. Use `storage.mode = canonical`.
2. Disable bridge: `DYNAMIC_NOTIFIER_BRIDGE_ENABLED=false`.

Idempotency
-----------

[](#idempotency)

Duplicate sends are suppressed using cache-backed idempotency keys:

- Pass an explicit key: `['idempotency_key' => 'booking:123']` in the dispatch payload.
- Or rely on implicit dedup via `action_id` in context `extra`: `new NotificationContext(extra: ['action_id' => $booking->id])`.

Keys are scoped per recipient and channel. Idempotency is checked at dispatch time (skip duplicate jobs) and again in the queued job (skip duplicate delivery after success).

Testing
-------

[](#testing)

```
composer install
composer test
```

Notes
-----

[](#notes)

- Default FCM transport logs payloads only; swap to `KreaitFcmTransport` for real push delivery.
- CI runs `composer test` and `composer lint` on PHP 8.2/8.3 with Laravel 11/12.

###  Health Score

19

—

LowBetter than 9% of packages

Maintenance59

Moderate activity, may be stable

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/27648452?v=4)[Ahmed Mahmoud](/maintainers/W3bDeveloper7)[@W3bDeveloper7](https://github.com/W3bDeveloper7)

---

Top Contributors

[![W3bDeveloper7](https://avatars.githubusercontent.com/u/27648452?v=4)](https://github.com/W3bDeveloper7 "W3bDeveloper7 (1 commits)")

### Embed Badge

![Health badge](/badges/w3bdeveloper7-laravel-dynamic-notifier/health.svg)

```
[![Health](https://phpackages.com/badges/w3bdeveloper7-laravel-dynamic-notifier/health.svg)](https://phpackages.com/packages/w3bdeveloper7-laravel-dynamic-notifier)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
