happyr/simplebus-bundle
Symfony bundle that integrates SimpleBus with the framework’s DI container, helping wire command, query, and event buses, register handlers and middleware, and use message buses in Symfony apps with minimal configuration.
This bundle is thin glue between Symfony's DI container and SimpleBus. It does not implement a bus itself — it registers the SimpleBus services, the middleware stack, and a compiler pass that collects your handlers. Treat it as wiring, not framework.
composer.json in the repo for its symfony/*, php, and simple-bus/* constraints against your project. On anything newer than Symfony 3.4 / PHP 7.1 you will almost certainly be fighting the dependency solver, and there is no Flex recipe — registration is manual.composer require happyr/simplebus-bundle, then add new Happyr\SimpleBusBundle\SimpleBusBundle() (confirm the exact class name in the repo) to AppKernel::registerBundles(). On Symfony 4+ there is no recipe, so you must also create config/bundles.php entry and hand-write the config file.DependencyInjection/Configuration.php and Resources/config/services.xml (or .yml) in vendor/happyr/simplebus-bundle/. This tells you the exact service IDs and the middleware list far more reliably than the README, which is minimal. Also open the bundle's compiler pass — that is where handler auto-registration behavior lives.bin/console debug:container --tag=<handler-tag> that your handler is actually collected before you blame the bus.If step 1 reveals incompatible constraints, stop and evaluate Symfony Messenger (native since 4.1) or Tactician instead — migrating later costs more than starting elsewhere.
Commands as DTOs, dispatched from controllers. Keep commands dumb (public properties or constructor-promoted scalars/IDs), never inject services into them. Controllers should depend on the bus service and call dispatch($command). Since the bundle-era SimpleBus used interface-based handler detection (handles() returning the message class in 2.x, or per-bus handler interfaces in 1.x), confirm which SimpleBus major version you resolved to before writing handlers.
One handler per command, many subscribers per event. Use the command bus for write operations and the event bus for side effects. The classic pattern with this bundle: a command handler mutates an aggregate; the aggregate records domain events; an event-dispatching middleware (if configured) releases them onto the event bus after the command returns. That ordering is the whole point of the middleware stack — read the middleware list in the bundle config to see whether event release is built in or something you must add.
Handler registration via tags, not autowiring. With this generation of bundles, handlers are typically collected by tag through a compiler pass, not by autoconfigure. Register them explicitly in services.yml:
App\Command\CreateOrderHandler:
tags: [{ name: <tag-name-from-compiler-pass> }]
Prefer explicit tags over wildcard resource loading, because a missed tag fails silently — the bus just throws "no handler" at runtime, not at compile time.
Inject an interface, not the bundle service. Define your own CommandBus port in your domain and have a thin adapter delegate to the container's bus service. This is your escape hatch when you eventually replace the bundle with Symfony Messenger — the adapter is the only thing that changes.
Middleware for cross-cutting concerns. Transaction wrapping (Doctrine flush/commit around the command), logging, and event release are all middleware in SimpleBus. If the bundle doesn't ship the middleware you need, implement MessageBusMiddleware in your app, register it as a service, and prepend it to the configured middleware array. Order is significant: transaction middleware should generally wrap event release so subscribers run inside the same unit of work, or explicitly outside it — decide and document which.
Integration tip: nested dispatch. Dispatching a command from inside a command handler is legal and common for orchestration, but it re-enters the middleware stack (including transactions) unless you use a separate bus instance. Keep nesting shallow or route orchestration through events instead.
DefinitionDecorator, ContainerAware, public/private service defaults), or SimpleBus 2.x API shifts. Pin your versions and budget for replacement.debug:container --tag=<tag> after adding a handler, and consider making handler services public in dev.handles() contract changed between 1.x and 2.x, and the query bus arrived later than this bundle's last release. If you need queries, you may have to register the query bus services yourself rather than relying on the bundle.kernel.terminate listener.MessageBusMiddleware, the bundle's compiler pass (subclass or replicate it if you want a different discovery convention), and the service definitions file (override service IDs in your app config to swap implementations). Overriding service definitions is the cleanest way to inject your own naming strategy or handler resolver without forking.debug:container <bus-service-id> to see the actual middleware chain and debug:event-dispatcher won't help here — events are SimpleBus events, not Symfony kernel events. Add a trivial logging middleware at the top of the stack during bring-up; it saves hours compared to guessing where a dispatch disappeared.How can I help you explore Laravel packages today?