Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Webpush Bundle Laravel Package

bentools/webpush-bundle

Symfony bundle to send Web Push notifications using the Web Push protocol. Manage user-to-subscription associations (multi-device and shared devices) with your own persistence (Doctrine or custom). Includes VAPID key generation and backend APIs for subscriptions.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require bentools/webpush-bundle
    

    Requires PHP 8.1+.

  2. Generate VAPID Keys

    php bin/console webpush:generate:keys
    

    Store the generated keys in config/packages/bentools_webpush.yaml:

    bentools_webpush:
        settings:
            public_key: '%env(WEB_PUSH_PUBLIC_KEY)%'
            private_key: '%env(WEB_PUSH_PRIVATE_KEY)%'
    
  3. Create UserSubscription Entity Implement BenTools\WebPushBundle\Model\Subscription\UserSubscriptionInterface (see example).

  4. Register the Subscription Manager Create a service implementing UserSubscriptionManagerInterface and tag it:

    services:
        App\Services\UserSubscriptionManager:
            arguments: ['@doctrine']
            tags:
                - { name: bentools_webpush.subscription_manager, user_class: 'App\Entity\User' }
    
  5. Frontend Integration Use webpush-client to handle subscription/unsubscription via the /webpush endpoint.


First Use Case: Send a Notification

use BenTools\WebPushBundle\Sender\PushMessageSender;
use BenTools\WebPushBundle\Model\Message\PushNotification;

// In a service/controller:
$sender = $this->container->get(PushMessageSender::class);
$notification = new PushNotification(
    'Order #123 Shipped!',
    'Your order has been dispatched.',
    ['icon' => '/images/notification-icon.png']
);

// Send to a user's subscriptions
$sender->send($notification, $user);

Implementation Patterns

Workflow: Subscription Handling

  1. Frontend

    • User subscribes via webpush-client (POST to /webpush).
    • Bundle validates the subscription and stores it via UserSubscriptionManager.
  2. Backend

    • Use UserSubscriptionManagerRegistry to fetch subscriptions for a user:
      $subscriptions = $registry->getManager($user)->findByUser($user);
      
  3. Sending Notifications

    • Create a PushNotification object and use PushMessageSender:
      $sender->send($notification, $user); // Sends to all subscriptions
      $sender->send($notification, $subscription); // Sends to a specific subscription
      

Integration Tips

  • Event-Driven Notifications Listen to domain events (e.g., OrderPlaced) and dispatch notifications:

    public static function getSubscribedEvents()
    {
        return [OrderEvents::PLACED => 'notifyOrderPlaced'];
    }
    
    public function notifyOrderPlaced(OrderEvent $event)
    {
        $notification = new PushNotification(...);
        $this->sender->send($notification, $event->getOrder()->getCustomer());
    }
    
  • Batch Processing Use PushMessageSender::sendBatch() for bulk notifications (e.g., newsletters):

    $sender->sendBatch([$notification1, $notification2], $user);
    
  • Custom Metadata Pass metadata via $options in UserSubscriptionManager::factory() (e.g., device type, browser):

    $subscription = $manager->factory($user, $hash, $subscriptionData, ['device' => 'mobile']);
    

Gotchas and Tips

Pitfalls

  1. VAPID Key Management

    • Never expose private keys in client-side code or logs.
    • Use environment variables or parameters.yml for keys.
    • Rotate keys periodically (e.g., via webpush:generate:keys).
  2. Subscription Hash Collisions

    • Ensure UserSubscriptionManager::hash() produces unique hashes for endpoints.
    • Default md5($endpoint) may suffice, but consider adding user context (e.g., md5($endpoint . $user->getId())).
  3. Apple Push Notification Service (APNs)

    • Apple requires the subject in config to be a URL or mailto: (e.g., https://yourdomain.com).
    • Set it explicitly in config:
      bentools_webpush:
          settings:
              subject: 'https://yourdomain.com'
      
  4. Frontend CORS Issues

    • Ensure your /webpush endpoint is accessible via CORS if frontend and backend are on different domains.
    • Configure CORS in Symfony (e.g., via nelmio_cors_bundle).
  5. Subscription Expiry

    • Web Push subscriptions can expire. Implement a cleanup job to remove stale subscriptions:
      // Example: Delete subscriptions older than 30 days
      $qb = $manager->getRepository(UserSubscription::class)->createQueryBuilder('us');
      $qb->delete('us', 'us')
         ->where('us.createdAt < :date')
         ->setParameter('date', new \DateTime('-30 days'));
      $qb->getQuery()->execute();
      

Debugging

  • Check Subscription Validity Use webpush-client to test subscriptions before sending:

    const subscription = await navigator.serviceWorker.ready.then(r => r.pushManager.subscription);
    const response = await fetch('/webpush', {
        method: 'POST',
        body: JSON.stringify(subscription),
        headers: {'Content-Type': 'application/json'}
    });
    console.log(await response.json());
    
  • Log Failed Sends Enable debug mode in config/packages/bentools_webpush.yaml:

    bentools_webpush:
        debug: true
    

    Check logs for errors like invalid subscriptions or VAPID key issues.

Extension Points

  1. Custom Notification Types Extend PushNotification or create a decorator for advanced payloads (e.g., interactive notifications):

    class InteractiveNotification extends PushNotification
    {
        public function __construct(string $title, string $body, array $actions = [])
        {
            parent::__construct($title, $body, ['actions' => $actions]);
        }
    }
    
  2. Priority Queues Use Symfony Messenger or a queue system (e.g., RabbitMQ) to defer non-critical notifications:

    $message = new SendPushNotification($notification, $user);
    $this->messageBus->dispatch($message);
    
  3. Analytics Track notification delivery and user engagement:

    // In a subscriber:
    public function onNotificationSent(NotificationSentEvent $event)
    {
        $this->analytics->track($event->getUser(), 'notification_sent', $event->getData());
    }
    
  4. Fallback for Unsupported Browsers Detect unsupported browsers (e.g., Safari without APNs) and fall back to email or in-app notifications:

    if (!$this->isBrowserSupported($request)) {
        $this->fallbackNotifier->notify($user, $notification);
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky