iguazoft/yii2-sse-notification

Yii2 Server-Sent Events & Web Push Notification Extension

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

Type:yii2-extension

pkg:composer/iguazoft/yii2-sse-notification

v1.0.0 2026-02-06 23:41 UTC

This package is auto-updated.

Last update: 2026-02-06 23:49:25 UTC


README

Real-time notifications for Yii2 applications using Server-Sent Events (SSE) and Web Push (VAPID).

Latest Stable Version Total Downloads License

Features

  • Server-Sent Events (SSE) - Real-time notifications for online users
  • Web Push Notifications (VAPID) - Browser notifications for offline users
  • Automatic Routing - Intelligently routes notifications via SSE or Web Push
  • Multiple Notification Types - Private, authenticated broadcast, and public
  • Flexible Storage - Redis and ActiveRecord drivers included
  • Service Worker - Pre-configured for Web Push
  • Connection Management - Automatic online/offline detection
  • Modern UI - Toast notifications with customizable styling

Requirements

  • PHP >= 8.1
  • Yii2 >= 2.0.14
  • One of:
    • Redis (recommended for production)
    • MongoDB
    • MySQL/PostgreSQL (via ActiveRecord)

Installation

Install via Composer:

composer require iguazoft/yii2-sse-notification

Quick Start

1. Configure the Module

Add the SSE module to your config/web.php:

'modules' => [
    'sse' => [
        'class' => 'iguazoft\sse\Module',
        'vapid' => [
            'subject' => 'mailto:admin@yourdomain.com',
            'publicKey' => 'YOUR_VAPID_PUBLIC_KEY',
            'privateKey' => 'YOUR_VAPID_PRIVATE_KEY',
        ],
    ],
],

2. Generate VAPID Keys

Generate your VAPID keys for Web Push:

# Using web-push CLI
npx web-push generate-vapid-keys

# Or using PHP
vendor/bin/web-push generate-vapid-keys

3. Configure Storage Driver

Choose your notification storage driver in config/web.php:

Option A: Redis (Recommended)

'components' => [
    'redis' => [
        'class' => 'yii\redis\Connection',
        'hostname' => 'localhost',
        'port' => 6379,
        'database' => 0,
    ],
],
'container' => [
    'definitions' => [
        'iguazoft\sse\interfaces\NotificationSourceInterface' => [
            'class' => 'iguazoft\sse\drivers\RedisDriver',
        ],
    ],
],

Option B: ActiveRecord (MySQL/PostgreSQL)

'container' => [
    'definitions' => [
        'iguazoft\sse\interfaces\NotificationSourceInterface' => [
            'class' => 'iguazoft\sse\drivers\ActiveRecordDriver',
            'notificationClass' => 'app\models\Notification',
        ],
    ],
],

4. Run Database Migration

Create the required tables:

php yii migrate --migrationPath=@vendor/iguazoft/yii2-sse/src/migrations

This creates:

  • notification - Stores notifications (if using ActiveRecord)
  • push_subscription - Stores Web Push subscriptions
  • user_connection - Tracks online/offline status

5. Copy Service Worker

Copy the Service Worker to your web root:

cp vendor/iguazoft/yii2-sse/src/assets/sw.js web/sw.js

6. Add to Layout

Include the SSE assets in your layout (views/layouts/main.php):

<?php
use iguazoft\sse\assets\SseAsset;
use yii\helpers\Url;

SseAsset::register($this);

$sseUrl = Url::to(['/sse/stream/index']);
$pushConfig = json_encode([
    'publicKey' => Yii::$app->getModule('sse')->vapid['publicKey'],
    'subscriptionUrl' => Url::to(['/sse/push/subscribe']),
    'serviceWorkerUrl' => '/sw.js',
]);

$this->registerJs("
    const sseClient = new NotificationClient('$sseUrl');
    const pushClient = new PushClient($pushConfig);
    
    // Bind Subscribe Button
    const btnSub = document.getElementById('btn-subscribe');
    if (btnSub) {
        btnSub.addEventListener('click', () => {
            pushClient.subscribe().then(() => {
                alert('Successfully subscribed to notifications!');
            }).catch(err => {
                console.error('Subscription failed', err);
            });
        });
    }
");
?>

<!-- Notification container -->
<div id="notification-container" style="position: fixed; top: 70px; right: 20px; z-index: 9999; width: 350px;"></div>

7. Add Subscribe Button (Optional)

Add a button to allow users to subscribe to Web Push:

<button id="btn-subscribe" class="btn btn-primary">
    🔔 Subscribe to Notifications
</button>

Usage

Sending Notifications

Method 1: Using NotificationDispatcher

use iguazoft\sse\components\NotificationDispatcher;
use Yii;

$dispatcher = Yii::createObject(NotificationDispatcher::class);

// Send private notification
$dispatcher->send([
    'type' => 'private',
    'user_id' => 123,
    'message' => [
        'title' => 'New Message',
        'body' => 'You have a new message from John',
        'icon' => '/images/notification-icon.png',
        'url' => '/messages/view/456',
    ],
]);

Method 2: Using HTTP Endpoint

curl -X POST http://yourapp.com/index.php?r=sse/notification/create \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "type=private" \
  -d "user_id=123" \
  -d "message[title]=New Message" \
  -d "message[body]=You have a new message"

Method 3: Direct Driver Access

use iguazoft\sse\interfaces\NotificationSourceInterface;
use Yii;

$driver = Yii::createObject(NotificationSourceInterface::class);

$driver->createNotification([
    'type' => 'private',
    'user_id' => 123,
    'message' => [
        'title' => 'Direct Notification',
        'body' => 'Sent directly via driver',
    ],
]);

Notification Types

Private Notification - Sent to a specific user:

[
    'type' => 'private',
    'user_id' => 123,
    'message' => [...],
]

Authenticated Broadcast - Sent to all authenticated users:

[
    'type' => 'auth_broadcast',
    'message' => [...],
]

Public Broadcast - Sent to all connected users (including guests):

[
    'type' => 'public',
    'message' => [...],
]

Message Format

'message' => [
    'title' => 'Notification Title',      // Required
    'body' => 'Message content',          // Required
    'icon' => '/path/to/icon.png',        // Optional
    'badge' => '/path/to/badge.png',      // Optional
    'url' => '/target/page',              // Optional - where to redirect on click
    'data' => [                           // Optional - custom data
        'id' => 123,
        'type' => 'message',
    ],
]

How It Works

Intelligent Routing

The extension automatically routes notifications based on user status:

┌─────────────────────────┐
│  Notification Created   │
└───────────┬─────────────┘
            │
            ▼
    ┌───────────────┐
    │ Is User       │
    │ Online?       │
    └───┬───────┬───┘
        │       │
    YES │       │ NO
        │       │
        ▼       ▼
   ┌─────┐   ┌──────────┐
   │ SSE │   │ Web Push │
   └─────┘   └──────────┘
      │            │
      ▼            ▼
   Toast     OS Notification

SSE Flow (Online Users)

  1. User opens your app
  2. SSE connection established to /sse/stream/index
  3. Notification created → stored in Redis/DB
  4. SSE stream picks up notification
  5. JavaScript displays toast notification

Latency: < 2 seconds

Web Push Flow (Offline Users)

  1. User subscribes via browser
  2. Subscription saved to database
  3. User goes offline/closes browser
  4. Notification created → user detected as offline
  5. Push sent via VAPID to FCM/Mozilla servers
  6. Browser receives push event
  7. Service Worker displays OS notification

Latency: 2-10 seconds

Configuration Reference

Module Configuration

'modules' => [
    'sse' => [
        'class' => 'iguazoft\sse\Module',
        
        // VAPID keys for Web Push (required)
        'vapid' => [
            'subject' => 'mailto:admin@example.com',
            'publicKey' => 'YOUR_PUBLIC_KEY',
            'privateKey' => 'YOUR_PRIVATE_KEY',
        ],
    ],
],

Driver Configuration

Redis Driver (Recommended)

'container' => [
    'definitions' => [
        'iguazoft\sse\interfaces\NotificationSourceInterface' => [
            'class' => 'iguazoft\sse\drivers\RedisDriver',
            'keyPrefix' => 'sse:',  // Optional, default: 'sse:'
        ],
    ],
],

ActiveRecord Driver

'container' => [
    'definitions' => [
        'iguazoft\sse\interfaces\NotificationSourceInterface' => [
            'class' => 'iguazoft\sse\drivers\ActiveRecordDriver',
            'notificationClass' => 'app\models\Notification',  // Your AR model
        ],
    ],
],

Advanced Usage

Custom Notification Model

Create your own ActiveRecord model:

namespace app\models;

use yii\db\ActiveRecord;

class Notification extends ActiveRecord
{
    public static function tableName()
    {
        return 'notification';
    }
    
    public function rules()
    {
        return [
            [['type', 'message'], 'required'],
            [['user_id'], 'integer'],
            [['message'], 'safe'],
        ];
    }
}

Customizing Toast Notifications

Override the default toast styling in your CSS:

.notification-toast {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 12px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}

.notification-toast .title {
    font-weight: 700;
    font-size: 16px;
}

.notification-toast .body {
    opacity: 0.9;
}

Manually Managing Connections

use iguazoft\sse\components\ConnectionManager;
use Yii;

$cm = Yii::createObject(ConnectionManager::class);

// Mark user as online
$cm->connect(123);

// Check if user is online
if ($cm->isOnline(123)) {
    echo "User is connected";
}

// Mark user as offline
$cm->disconnect(123);

Direct PushService Usage

use iguazoft\sse\components\PushService;
use Yii;

$pushService = Yii::createObject(PushService::class);

// Send to specific user
$result = $pushService->sendToUser(123, [
    'title' => 'Direct Push',
    'body' => 'Sent directly via PushService',
    'data' => ['url' => '/dashboard'],
]);

print_r($result);
// Output: Array ( [0] => Sent to {subscription_id}: OK )

Troubleshooting

Notifications Not Appearing

SSE (Online Users)

  1. Check browser console for connection errors
  2. Verify SSE route is accessible: /index.php?r=sse/stream/index
  3. Check Redis/DB for stored notifications
  4. Ensure NotificationClient is initialized
  5. Verify CORS headers if using different domains

Web Push (Offline Users)

  1. Check browser permissions: Settings → Notifications → Allow
  2. Verify VAPID keys are correct
  3. Ensure Service Worker is registered: chrome://serviceworker-internals
  4. Check subscription exists in database
  5. On macOS: Chrome must be open (minimized is OK)

VAPID Errors

InvalidConfigException: VAPID keys are not configured

Solution: Ensure the sse module is loaded and VAPID keys are set in config/web.php.

Service Worker Not Found

GET /sw.js 404 (Not Found)

Solution: Copy sw.js to your web root:

cp vendor/iguazoft/yii2-sse/src/assets/sw.js web/sw.js

Subscription Fails for Guest Users

{status: "error", message: "You must be logged in"}

Solution: Ensure users are authenticated before subscribing to push notifications.

Architecture

Components

Component Purpose
NotificationDispatcher Routes notifications to SSE or Web Push
PushService Handles Web Push via VAPID
ConnectionManager Tracks user online/offline status
StreamController Serves SSE stream
NotificationController Provides notification creation API
PushController Handles push subscriptions

Drivers

Driver Storage Production Ready
RedisDriver Redis Lists ✅ Yes (Recommended)
ActiveRecordDriver MySQL/PostgreSQL ✅ Yes
MongoDriver MongoDB ⚠️ Experimental

Assets

File Purpose
sse.js SSE client (EventSource)
push.js Web Push client
sw.js Service Worker for push events

Security Considerations

  1. CSRF Protection: Enabled by default on all endpoints
  2. Authentication: Web Push subscriptions require authenticated users
  3. VAPID Keys: Keep private key secret, never expose in client-side code
  4. HTTPS Required: Web Push only works over HTTPS (except localhost)

Performance

Recommended Limits

  • Concurrent SSE Connections: Up to 10,000 per server
  • Notification Rate: Up to 1,000/second (Redis driver)
  • TTL for Stored Notifications: 24 hours (configurable)
  • Web Push Queue: Up to 100 pending per user

Optimization Tips

  1. Use Redis driver for production
  2. Implement message queue for bulk notifications
  3. Add CDN for static assets (sw.js, icons)
  4. Use Redis Pub/Sub for multi-server deployments
  5. Implement notification batching for high-volume scenarios

License

This extension is available under a dual license model:

Option 1: AGPL-3.0 (Free for Open Source)

Use this extension for free if your project is open source and licensed under AGPL-3.0 or a compatible license. You must:

  • ✅ Release your application source code under AGPL-3.0
  • ✅ Disclose all source code (including for SaaS applications)
  • ✅ License derivative works under AGPL-3.0

Option 2: Commercial License (For Proprietary Use)

If your application is closed-source, commercial, or proprietary, you must purchase a Commercial License. This includes:

  • ✅ No requirement to open source your code
  • ✅ Use in proprietary applications
  • ✅ Priority support and updates
  • ✅ Legal indemnification

📧 Purchase a Commercial License: licensing@iguazoft.com

See the LICENSE file for complete details.

Support

Credits

Developed by Iguazoft

Powered by: