simple-bus/symfony-bridge
Symfony integration bridge for SimpleBus/MessageBus. Provides CommandBusBundle, EventBusBundle, and DoctrineORMBridgeBundle to wire command and event buses into your Symfony app, with docs and upgrade guide.
Installation:
composer require simple-bus/symfony-bridge
Enable the required bundles in config/bundles.php:
return [
// ...
SimpleBus\SymfonyBridge\CommandBusBundle\CommandBusBundle::class => ['all' => true],
SimpleBus\SymfonyBridge\EventBusBundle\EventBusBundle::class => ['all' => true],
];
Configure the Bus:
Add a simple_bus configuration block in config/packages/simple_bus.yaml:
simple_bus:
command_bus:
messenger: true # Use Symfony Messenger (default)
# OR
# simple_bus: true # Use SimpleBus directly
event_bus:
messenger: true
First Use Case:
use App\Command\CreateUserCommand;
public function handle(CreateUserCommand $command)
{
// Logic here
}
// Dispatch
$this->bus->dispatch(new CreateUserCommand('John Doe'));
use App\Event\UserCreatedEvent;
$this->eventBus->publish(new UserCreatedEvent($userId));
Handlers:
Register handlers as services with the simple_bus.handler tag:
services:
App\CommandHandler\CreateUserCommandHandler:
tags: ['simple_bus.handler']
Define Commands:
namespace App\Command;
class CreateUserCommand {
public function __construct(public string $name) {}
}
Handle Commands:
namespace App\CommandHandler;
use App\Command\CreateUserCommand;
class CreateUserCommandHandler {
public function __invoke(CreateUserCommand $command) {
// Business logic
}
}
Dispatch Commands:
$this->bus->dispatch(new CreateUserCommand('Alice'));
Async Dispatch (Messenger):
Enable messenger: true in config to leverage Symfony Messenger’s async transport.
Define Events:
namespace App\Event;
class UserCreatedEvent {
public function __construct(public int $userId) {}
}
Handle Events:
namespace App\EventHandler;
use App\Event\UserCreatedEvent;
class UserCreatedEventHandler {
public function __invoke(UserCreatedEvent $event) {
// Side effects (e.g., notifications)
}
}
Publish Events:
$this->eventBus->publish(new UserCreatedEvent($userId));
Event Subscribers:
Use Symfony’s kernel.event_listener tag for event listeners:
services:
App\EventListener\UserCreatedListener:
tags: ['kernel.event_listener', { event: 'app.user_created', method: 'onUserCreated' }]
Dependency Injection: Inject the bus directly into services:
use SimpleBus\SymfonyBridge\CommandBus\CommandBusInterface;
public function __construct(private CommandBusInterface $bus) {}
Middleware: Add middleware to the bus (e.g., logging, validation):
simple_bus:
command_bus:
middleware: ['App\Middleware\LogCommandMiddleware']
Doctrine ORM Bridge: For command/event handlers requiring Doctrine:
use SimpleBus\SymfonyBridge\DoctrineORMBridge\DoctrineORMBus;
public function __construct(
DoctrineORMBus $bus,
EntityManagerInterface $em
) {}
Testing: Mock the bus in tests:
$bus = $this->createMock(CommandBusInterface::class);
$bus->expects($this->once())->method('dispatch');
$this->app->instance(CommandBusInterface::class, $bus);
Circular Dependencies: Avoid circular dependencies between commands/events and their handlers. Use DTOs (Data Transfer Objects) for complex data.
Handler Registration:
Forgetting to tag handlers with simple_bus.handler will result in silent failures. Verify with:
php bin/console debug:container simple_bus.handler
Messenger vs. SimpleBus:
messenger: true in config.simple_bus: true). Choose based on needs.Event Ordering: Events are published synchronously by default. For async publishing, combine with Symfony Messenger or a queue system.
Doctrine Transactions:
If using DoctrineORMBridgeBundle, ensure transactions are managed explicitly in handlers to avoid issues:
$em->beginTransaction();
try {
$this->bus->dispatch($command);
$em->commit();
} catch (\Exception $e) {
$em->rollback();
throw $e;
}
Handler Not Called:
debug:container).APP_DEBUG=true) to see unhandled exceptions.Middleware Issues: Debug middleware by temporarily removing them or logging their execution:
public function handle($message, callable $next) {
\Symfony\Component\Debug\Debug::info('Middleware executed');
return $next($message);
}
Configuration Errors:
Validate simple_bus.yaml syntax and available options. Use:
php bin/console config:dump-reference simple_bus
Custom Middleware: Create middleware for cross-cutting concerns (e.g., auth, metrics):
namespace App\Middleware;
use SimpleBus\Message\Bus\Middleware\Middleware;
class AuthMiddleware implements Middleware {
public function handle($message, callable $next) {
if (!$this->isAuthenticated()) {
throw new \RuntimeException('Unauthenticated');
}
return $next($message);
}
}
Dynamic Handlers: Use Symfony’s compiler passes or runtime logic to dynamically register handlers (e.g., based on user roles).
Event Dispatcher Bridge:
Combine with Symfony’s EventDispatcher for hybrid event handling:
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
$dispatcher->addListener('app.user_created', function (UserCreatedEvent $event) {
$this->eventBus->publish($event);
});
Async Command Handling: For long-running commands, pair with Symfony Messenger’s transports (e.g., Doctrine, Redis):
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
Testing Utilities: Extend the package’s test utilities for custom assertions:
$this->assertBusWasCalledWith($bus, new CreateUserCommand('Bob'));
How can I help you explore Laravel packages today?