PHPackages                             dev1/notify-laravel - 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. dev1/notify-laravel

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

dev1/notify-laravel
===================

Laravel adapter for DEV1 Notify Core

v1.2.1(2mo ago)078MITPHPPHP ^7.4|^8.0CI passing

Since Sep 23Pushed 2mo agoCompare

[ Source](https://github.com/DEV1-Softworks/notify-laravel)[ Packagist](https://packagist.org/packages/dev1/notify-laravel)[ RSS](/packages/dev1-notify-laravel/feed)WikiDiscussions master Synced today

READMEChangelog (2)Dependencies (14)Versions (11)Used By (0)

DEV1 Notify Laravel Adapter
===========================

[](#dev1-notify-laravel-adapter)

[![CI](https://github.com/DEV1-Softworks/notify-laravel/actions/workflows/tests.yml/badge.svg)](https://github.com/DEV1-Softworks/notify-laravel/actions/workflows/tests.yml)[![Release](https://github.com/DEV1-Softworks/notify-laravel/actions/workflows/release.yml/badge.svg)](https://github.com/DEV1-Softworks/notify-laravel/actions/workflows/release.yml)[![Coverage](https://camo.githubusercontent.com/655824942d358074af54b8e9b0852968a3b2f272e931c61d2be694d9ecb61466/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f676973742e67697468756275736572636f6e74656e742e636f6d2f525a45524f535445524e2f64656461393938613334306637366265316536396366376666303764616230632f7261772f6e6f746966792d636f7665726167652e6a736f6e)](#)[![Latest Stable Version](https://camo.githubusercontent.com/5c654dffc68ce63e053aba99c547ac946b57427257f226fb330af6c416ad4c1a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f646576312f6e6f746966792d6c61726176656c2e737667)](https://packagist.org/packages/dev1/notify-laravel)[![Total Downloads](https://camo.githubusercontent.com/4c11035c0456efdaa484daba1f700b08cc6e47841e639f0b9343fdecd15b731d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f646576312f6e6f746966792d6c61726176656c2e737667)](https://packagist.org/packages/dev1/notify-laravel)[![License](https://camo.githubusercontent.com/9bf72f8fc06f086575bf5e66a34724ad892f614c7eeada336ad30e87c5f66fe9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f646576312f6e6f746966792d6c61726176656c2e737667)](LICENSE)

Adapter package to integrate [DEV1 Notify Core](https://packagist.org/packages/dev1/notify-core) into **Laravel 8 – 13** (PHP 7.4 – 8.5).

Provides:

- Service provider + auto-discovered `Notify` facade.
- Config publishing (`config/notify.php`).
- Custom Laravel Notification channel (`dev1-notify`).
- Logger bridge to Laravel's PSR-3 logger.
- PSR-16 token cache wiring (share OAuth tokens across processes/workers).
- Configurable retry/backoff passthrough for the FCM HTTP v1 driver.

---

Installation
------------

[](#installation)

```
composer require dev1/notify-laravel
php artisan vendor:publish --tag=notify-config
```

The service provider (`Dev1\NotifyLaravel\NotifyServiceProvider`) and the `Notify` facade alias are registered automatically via Laravel's package auto-discovery — no manual changes to `config/app.php` are required.

For FCM v1, create a Firebase project and generate a service account key JSON file at the [Firebase Console](https://console.firebase.google.com/). Place it somewhere **outside** `public/` — the default looks for `storage/app/firebase/service-account.json`. Add it to `.gitignore`.

Configuration
-------------

[](#configuration)

.env example:

```
NOTIFY_DEFAULT=fcm
NOTIFY_FCM_PROJECT_ID=your-firebase-project-id
NOTIFY_FCM_SA_PATH=app/firebase/service-account.json

# Optional
NOTIFY_FCM_CACHE_LEEWAY=30            # seconds subtracted from token expiry
NOTIFY_FCM_CACHE_STORE=redis          # Laravel cache store to share OAuth tokens (null = disabled)
NOTIFY_FCM_CACHE_KEY=                 # override cache key (defaults to a hash of client_email)
NOTIFY_FCM_MAX_RETRIES=2              # retries on 5xx / 429 / transport errors
NOTIFY_FCM_RETRY_BASE_DELAY_MS=200    # initial backoff (doubles per attempt, +jitter)
NOTIFY_LOG=true
NOTIFY_LOG_CHANNEL=
```

Config file (`config/notify.php`) — published shape:

```
return [
    'default' => env('NOTIFY_DEFAULT', 'fcm'),

    'clients' => [
        'fcm' => [
            'driver' => 'fcm_v1',
            'project_id' => env('NOTIFY_FCM_PROJECT_ID'),

            // Path to a JSON file OR an inline JSON string.
            'service_account_json' => storage_path(env('NOTIFY_FCM_SA_PATH', 'app/firebase/service-account.json')),

            'scopes' => [
                'https://www.googleapis.com/auth/firebase.messaging',
            ],

            // Seconds subtracted from OAuth token expiry before considering it expired.
            'cache_leeway' => env('NOTIFY_FCM_CACHE_LEEWAY', 30),

            // Optional PSR-16 cache for OAuth tokens. Set to a Laravel cache
            // store name (e.g. 'redis', 'file') to share tokens across processes.
            // null disables caching (each process fetches its own token).
            'cache_store' => env('NOTIFY_FCM_CACHE_STORE'),
            'cache_key'   => env('NOTIFY_FCM_CACHE_KEY'),

            // Retry behavior on transient 5xx / 429 / transport errors.
            // Exponential backoff with jitter is applied by notify-core.
            'max_retries'         => env('NOTIFY_FCM_MAX_RETRIES', 2),
            'retry_base_delay_ms' => env('NOTIFY_FCM_RETRY_BASE_DELAY_MS', 200),

            'platform_defaults' => [
                'android' => [
                    // 'priority' => 'HIGH',
                    // 'ttl' => 3600, // seconds; transport converts to "3600s"
                    // 'notification' => ['icon' => 'ic_stat_notify'],
                ],
                'apns' => [
                    // 'headers' => ['apns-priority' => '10', 'apns-push-type' => 'alert'],
                    // 'aps'     => ['sound' => 'default', 'mutable-content' => 1],
                    // 'custom'  => [],
                ],
            ],
        ],
    ],

    'logging' => [
        'enabled' => env('NOTIFY_LOG', true),
        'channel' => env('NOTIFY_LOG_CHANNEL', null),
    ],
];
```

> **Production tip — PSR-16 token cache.** Set `NOTIFY_FCM_CACHE_STORE=redis` (or any shared Laravel cache store) so OAuth tokens are reused across web workers and queue workers. Without it, every PHP process fetches its own token from Google on first send.

---

Usage
-----

[](#usage)

We have two ways to use Notify in Laravel, with a Facade or via the Notification Channel. Use the one that best fits your needs.

### Via Facade

[](#via-facade)

Simplest way to send a one-off notification. The `Notify` alias is registered by auto-discovery, so you can use it directly.

```
use Dev1\NotifyLaravel\Facades\Notify;
use Dev1\NotifyCore\Platform\AndroidOptions;
use Dev1\NotifyCore\Platform\ApnsOptions;

$android = AndroidOptions::make()
    ->withChannelId('your_channel_id')
    ->withPriority('HIGH')
    ->withTtl(900);

$apns = ApnsOptions::make()
    ->withHeaders(['apns-priority' => '10', 'apns-push-type' => 'alert'])
    ->withAps(['sound' => 'default']);

$result = Notify::send(
    // Target: exactly ONE of token / topic / condition must be non-null.
    ['token' => 'AAA', 'topic' => null, 'condition' => null],
    [
        'title'   => 'Hello',
        'body'    => 'Test message',
        'data'    => ['foo' => 'bar'], // optional
        'android' => $android,          // AndroidOptions or array, optional
        'apns'    => $apns,             // ApnsOptions or array, optional
    ],
    'fcm' // client name; omit or pass null to use the default
);

// $result is an instance of Dev1\NotifyCore\DTO\PushResult.
// See "Handling send results" below.
```

> **Target rule (since core 1.2.0).** Pass exactly one of `token` / `topic` / `condition`. The adapter treats missing keys and empty strings as null; passing more than one real value throws `InvalidArgumentException`.

> **Silent / data-only pushes.** Leave `title` and `body` empty (or omit them) to send a data-only message — core will drop the `notification` block automatically.

### Via Notification channel

[](#via-notification-channel)

Intended for Laravel notifications — you get queues, fan-out, testing helpers, etc.

```
use Illuminate\Notifications\Notification;
use Dev1\NotifyCore\Platform\AndroidOptions;
use Dev1\NotifyCore\Platform\ApnsOptions;

class OrderPaid extends Notification
{
    public function via($notifiable): array
    {
        return ['dev1-notify'];
    }

    public function toDev1Notify($notifiable): array
    {
        $token = $notifiable->fcm_token; // however you store the token

        $android = AndroidOptions::make()
            ->withChannelId('your_channel_id')
            ->withPriority('HIGH')
            ->withNotification(['image' => 'https://cdn.example.com/paid.png']);

        $apns = ApnsOptions::make()
            ->withHeaders(['apns-priority' => '10', 'apns-push-type' => 'alert'])
            ->withAps(['sound' => 'default']);

        return [
            'client' => 'fcm', // optional; falls back to notify.default
            'target' => [
                'token'     => $token,
                'topic'     => null,
                'condition' => null,
            ],
            'payload' => [
                'title'   => 'Payment Received',
                'body'    => 'Your order has been paid. Enjoy!',
                'data'    => ['order_id' => 123],
                'android' => $android,
                'apns'    => $apns,
            ],
        ];
    }
}

// Trigger:
$user->notify(new OrderPaid());
```

---

Events
------

[](#events)

Every push sent through the `dev1-notify` channel dispatches `Dev1\NotifyLaravel\Events\NotifySent`:

- `$result` — `Dev1\NotifyCore\DTO\PushResult`
- `$notifiable` — the notifiable entity
- `$notification` — the `Illuminate\Notifications\Notification` instance
- `$client` — resolved client name (or `null` for the default)
- `$target`, `$payload` — the arrays that were sent

Typical listener:

```
// app/Providers/EventServiceProvider.php
protected $listen = [
    \Dev1\NotifyLaravel\Events\NotifySent::class => [
        \App\Listeners\HandleNotifyResult::class,
    ],
];
```

### Handling send results

[](#handling-send-results)

`PushResult` exposes helpers for the common FCM error codes — use them in a `NotifySent` listener or right after `Notify::send()`:

```
if ($result->isUnregistered()) {
    // Token no longer valid — prune it from your DB.
    $user->tokens()->where('fcm_token', $token)->delete();
} elseif ($result->isQuotaExceeded()) {
    // FCM is rate-limiting — back off before retrying.
} elseif ($result->isTransient()) {
    // 5xx / transport blip — safe to retry later
    // (core already retried per max_retries before surfacing this).
} elseif ($result->isInvalidArgument()) {
    // Payload shape is wrong — log and investigate, don't retry blindly.
}
```

Raw fields are also available: `$result->success`, `$result->id`, `$result->errorCode`, `$result->errorMessage`, `$result->raw`.

---

Testing
-------

[](#testing)

You can run the tests with:

```
./vendor/bin/phpunit
```

### CI &amp; CD

[](#ci--cd)

CI/CD is provided with GitHub Actions.

**CI** — [`tests.yml`](.github/workflows/tests.yml) runs on every push and pull request to `master`:

- PHPUnit with Orchestra Testbench.
- Coverage badge updated via Gist.
- **Enforces ≥ 80% coverage** (the job fails and blocks deployment otherwise).

**CD** — [`release.yml`](.github/workflows/release.yml) runs after a successful `tests.yml` on a push to `master`:

- Extracts the latest `## [X.Y.Z]` version from `CHANGELOG.md`.
- If `vX.Y.Z` is not yet tagged, creates an annotated tag at the tested commit and pushes it.
- Publishes a GitHub Release with auto-generated notes.
- Notifies Packagist via its update-package API so the new version is indexed immediately.

Required repository secrets for releases:

- `PACKAGIST_USERNAME` — your packagist.org username.
- `PACKAGIST_TOKEN` — API token from packagist.org/profile/.
- `GIST_TOKEN` + `COVERAGE_GIST_ID` — already used by the coverage badge step.

If the Packagist secrets are absent the release still tags + creates the GitHub Release; the Packagist ping is skipped with a warning (useful when Packagist is already wired via its own webhook).

Contributing
============

[](#contributing)

We welcome contributions! Please follow these steps:

1. Fork the repo and create a feature branch.
2. Run tests with `./vendor/bin/phpunit`.
3. Ensure coverage ≥ 80%.
4. Submit a PR.

Issues and suggestions are welcome on GitHub.

Made with ❤️ in Mexico 🇲🇽 by [DEV1 Softworks Labs](https://labs.dev1.mx)

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance86

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 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.

###  Release Activity

Cadence

Every ~35 days

Recently: every ~53 days

Total

7

Last Release

70d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3065243?v=4)[Marco Ramírez](/maintainers/rzerostern)[@RZEROSTERN](https://github.com/RZEROSTERN)

---

Top Contributors

[![RZEROSTERN](https://avatars.githubusercontent.com/u/3065243?v=4)](https://github.com/RZEROSTERN "RZEROSTERN (22 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/dev1-notify-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/dev1-notify-laravel/health.svg)](https://phpackages.com/packages/dev1-notify-laravel)
```

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.6M3.1k](/packages/craftcms-cms)[moonshine/moonshine

Laravel administration panel

1.3k253.1k81](/packages/moonshine-moonshine)[spatie/laravel-export

Create a static site bundle from a Laravel app

674146.0k6](/packages/spatie-laravel-export)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M574](/packages/shopware-core)[laravel-notification-channels/apn

Apple APN Push Notification Channel

2022.2M8](/packages/laravel-notification-channels-apn)[mailersend/laravel-driver

MailerSend Laravel Driver

90875.7k9](/packages/mailersend-laravel-driver)

PHPackages © 2026

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