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

Mercure Bundle Laravel Package

symfony/mercure-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**
   ```bash
   composer require symfony/mercure-bundle

Add the bundle to config/bundles.php:

return [
    // ...
    Symfony\Mercure\Bundle\MercureBundle::class => ['all' => true],
];
  1. Configure .env Add your Mercure Hub URL (e.g., a public hub like https://mercure.rocks or a self-hosted instance):

    MERCURE_URL=https://your-mercure-hub/.well-known/mercure
    MERCURE_PUBLIC_URL=https://your-mercure-hub/.well-known/mercure
    MERCURE_JWT_SECRET=your-secret-key  # Required for private hubs
    
  2. First Push Inject MercureUpdatePublisherInterface in a controller or service:

    use Symfony\Mercure\Update\MercureUpdatePublisherInterface;
    
    public function publishUpdate(MercureUpdatePublisherInterface $publisher)
    {
        $publisher->publish(
            new Update('https://example.com/updates', 'New update!', new \DateTimeImmutable())
        );
    }
    
  3. Subscribe in JavaScript Use the Mercure client to listen for updates:

    const eventSource = new EventSource('https://your-mercure-hub/.well-known/mercure?topic=https://example.com/updates');
    eventSource.onmessage = (e) => console.log(e.data);
    

Implementation Patterns

Common Workflows

  1. Real-Time Notifications

    • Publish updates after CRUD operations (e.g., afterSave in Doctrine events):
      $entityManager->getEventManager()->addEventListener(
          [YourEntity::class, 'postPersist'],
          function ($event) use ($publisher) {
              $publisher->publish(new Update(
                  'https://example.com/updates/' . $event->getObject()->getId(),
                  'New item created!'
              ));
          }
      );
      
  2. Topic-Based Updates

    • Use URL paths as topics (e.g., https://example.com/updates/{resource}) to segment updates by resource/type.
    • Example: Broadcast to all users subscribed to a specific dashboard:
      $publisher->publish(new Update(
          'https://example.com/dashboard/updates',
          json_encode(['status' => 'active', 'data' => $newData])
      ));
      
  3. Authentication & Private Topics

    • For private hubs, generate JWTs for authenticated users:
      use Symfony\Mercure\HubInterface;
      use Symfony\Mercure\JWT\StaticJWTGenerator;
      
      $hub = $container->get(HubInterface::class);
      $jwt = StaticJWTGenerator::createJWT(
          ['sub' => 'user:123'],
          $container->getParameter('mercure.jwt_secret')
      );
      $hub->publish(new Update(
          'https://example.com/private-updates',
          'Secret data',
          new \DateTimeImmutable(),
          $jwt
      ));
      
  4. Batching Updates

    • Use Symfony’s EventDispatcher to batch multiple updates (e.g., after bulk operations):
      $dispatcher->dispatch(new BatchUpdateEvent($updates), BatchUpdateEvent::NAME);
      

Integration Tips

  1. Symfony Messenger Combine with Messenger for async publishing:

    $message = new MercureUpdateMessage(
        new Update('https://example.com/updates', 'Async update')
    );
    $bus->dispatch($message);
    
  2. ReactPHP For non-HTTP clients (e.g., CLI tools), use the MercureHubClient:

    $hub = new MercureHubClient('https://your-mercure-hub');
    $hub->subscribe('https://example.com/updates', function ($update) {
        // Handle update
    });
    
  3. Caching Responses Cache frequent updates (e.g., with Symfony Cache component) to reduce hub load:

    $cache = $container->get('cache.app');
    if (!$cache->has('last_update')) {
        $publisher->publish(new Update('https://example.com/updates', 'Cached update'));
        $cache->set('last_update', true, 3600);
    }
    
  4. Testing Use MercureTestHub in PHPUnit:

    $hub = new MercureTestHub();
    $publisher = new MercureUpdatePublisher($hub);
    $publisher->publish(new Update('https://example.com/test', 'Test data'));
    $this->assertCount(1, $hub->getUpdates());
    

Gotchas and Tips

Pitfalls

  1. Twig Extension Registration (Symfony Mercure 0.7+)

    • If using Symfony Mercure 0.7+, ensure the Twig extension is properly registered. The symfony/mercure-bundle v0.4.2 fixes a regression where the Twig extension might not register automatically.
    • Fix: Clear your cache after updating:
      php bin/console cache:clear
      
    • If issues persist, manually register the Twig extension in your services.yaml:
      Symfony\Mercure\Twig\MercureExtension:
          tags: ['twig.extension']
      
  2. JWT Validation

    • If using a private hub, ensure the mercure.jwt_secret matches the hub’s configuration. Mismatches will cause 401 Unauthorized errors.
    • Fix: Double-check the secret in .env and hub settings.
  3. CORS Issues

    • Mercure requires CORS headers for browser clients. Configure your hub (e.g., mercure-hub Docker image) with:
      MERCURE_CORS_ALLOWED_ORIGINS=http://localhost:3000,https://your-app.com
      
    • Fix: Add allowed origins explicitly; * may not work due to Mercure’s security model.
  4. Topic URL Encoding

    • Topics must be URL-encoded. Invalid URLs (e.g., spaces, special chars) will fail silently.
    • Fix: Use urlencode() or Symfony’s UrlGenerator:
      $topic = 'https://example.com/updates/' . urlencode($resourceId);
      
  5. Connection Limits

    • Mercure hubs may throttle or drop connections if too many clients subscribe to the same topic.
    • Fix: Use topic prefixes (e.g., https://example.com/user:123/updates) for per-user topics.
  6. EventSource Retries

    • Browsers retry failed EventSource connections (default: 3 attempts). Rapid failures may flood your hub.
    • Fix: Implement exponential backoff in client-side JS:
      eventSource.onerror = () => {
          setTimeout(() => {
              eventSource = new EventSource(url);
          }, 1000 * Math.pow(2, errorCount++));
      };
      

Debugging

  1. Hub Logs

    • Enable debug logging in config/packages/mercure.yaml:
      mercure:
          hubs:
              default:
                  url: '%env(MERCURE_URL)%'
                  jwt: '%env(MERCURE_JWT_SECRET)%'
                  debug: true  # Enable debug logs
      
    • Check Symfony logs (var/log/dev.log) for hub communication errors.
  2. Network Tab

    • Inspect the EventSource connection in Chrome DevTools (Network > WS). Look for:
      • 401 Unauthorized: JWT or URL issues.
      • 404 Not Found: Incorrect topic URL or hub misconfiguration.
  3. Mercure Hub CLI

    • Test hub connectivity with curl:
      curl -H "Authorization: Bearer YOUR_JWT" https://your-mercure-hub/.well-known/mercure
      
    • Should return 200 OK with hub metadata.
  4. Twig Extension Verification

    • Verify the Twig extension is loaded by checking if mercure_hub() or mercure_update() functions are available in your Twig templates. If not, the extension may not be registered.

Extension Points

  1. Custom Update Classes Extend Update to add metadata:

    class CustomUpdate extends Update {
        public function __construct(string $topic, string $data, \DateTimeImmutable $date, array $metadata = []) {
            parent::__construct($topic, $data, $date);
            $this->metadata = $metadata;
        }
    }
    
  2. Middleware Add processing before publishing (e.g., sanitize data):

    $publisher = new MercureUpdatePublisher($hub);
    $publisher->addMiddleware(function
    
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.
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle
dmstr/api-platform-utils-bundle
dmstr/api-configuration-bundle
chrisdev/ux-components
baks-dev/finances
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle