Installation
composer require symfony/mercure
Add to composer.json if using Laravel’s autoloader:
"autoload": {
"psr-4": {
"App\\": "app/",
"Symfony\\Component\\Mercure\\": "vendor/symfony/mercure/"
}
}
Run composer dump-autoload.
First Use Case: Pushing a Notification
Create a MercureHub instance (Laravel service provider recommended):
// config/services.php
'mercure' => [
'hub_url' => env('MERCURE_HUB_URL', 'http://localhost:.12033'),
'jwt_secret' => env('MERCURE_JWT_SECRET', '!ChangeThisSecretKey!'),
],
Register in AppServiceProvider:
public function register()
{
$this->app->singleton(MercureHub::class, function ($app) {
return new MercureHub($app['config']['services.mercure.hub_url']);
});
}
Push a Message
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
$hub = app(MercureHub::class);
$update = new Update(
'http://example.com/.well-known/mercure',
json_encode(['message' => 'Hello, world!'])
);
$hub->publish($update);
Real-Time Event Broadcasting Replace Laravel Echo/Pusher for custom events:
// In an event listener
event(new OrderShipped($order));
$hub->publish(new Update(
route('mercure.order.'.$order->id),
json_encode(['status' => 'shipped'])
));
Authentication & Topics Use JWT for secure topics:
$update = new Update(
'https://example.com/orders',
json_encode(['order_id' => 123]),
new \DateTimeImmutable('+1 hour'),
['authorization' => 'Bearer ' . $this->generateJWT()]
);
Batching Updates For performance, batch updates in a queue job:
// app/Jobs/PublishMercureUpdates.php
public function handle()
{
$hub = app(MercureHub::class);
foreach ($this->updates as $update) {
$hub->publish($update);
}
}
Route::get('/.well-known/mercure', function () {
return response()->json(['hub' => config('services.mercure.hub_url')]);
});
const eventSource = new EventSource('https://example.com/.well-known/mercure?topic=http://example.com/orders');
eventSource.onmessage = (e) => console.log(JSON.parse(e.data));
MercureHub in PHPUnit:
$mockHub = Mockery::mock(MercureHub::class);
$mockHub->shouldReceive('publish')->once();
$this->app->instance(MercureHub::class, $mockHub);
CORS Issues Ensure your Mercure hub URL is whitelisted in browser clients. Use:
// In your hub config (e.g., via Symfony MercureBundle)
cors_origins: ["https://your-app.com"]
Laravel middleware may block requests; add:
Route::middleware(['cors'])->get('/.well-known/mercure', ...);
JWT Validation If using JWT, ensure the secret matches between server and hub. Test with:
curl -H "Authorization: Bearer YOUR_JWT" http://hub-url/.well-known/mercure
Connection Limits Mercure hubs (e.g., Docker) default to 100 connections. Adjust in config:
# docker-compose.yml
mercure:
environment:
MERCURE_MAX_CONNECTIONS: 500
docker logs mercure
Update::validate() to catch malformed payloads:
if (!Update::validate($update->getData())) {
throw new \RuntimeException('Invalid Mercure update');
}
Custom Middleware
Extend MercureHub to add logic before publishing:
class CustomMercureHub extends MercureHub
{
public function publish(Update $update, array $options = [])
{
$update->setData($this->sanitizeData($update->getData()));
parent::publish($update, $options);
}
}
Retry Logic Implement exponential backoff for failed pushes:
use Symfony\Component\Mercure\Exception\MercureException;
try {
$hub->publish($update);
} catch (MercureException $e) {
if ($attempts < 3) {
sleep(2 ** $attempts);
$attempts++;
retry();
}
}
Analytics Track published updates via a listener:
$hub->on('publish', function (Update $update) {
\App\Models\MercureLog::create([
'topic' => $update->getUrl(),
'data' => $update->getData(),
]);
});
How can I help you explore Laravel packages today?