Weave 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

Broadway Bundle Laravel Package

matiux/broadway-bundle

Symfony bundle that integrates Broadway, the event sourcing and CQRS library for PHP. It wires command and query buses, event stores, read models and event handlers into the container, so you can add CQRS and event sourcing to a Symfony app with minimal boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Dublin Bundle is a Symfony bundle that wires the Dublin CQRS/Event Sourcing library into a Symfony application. It is the maintained successor to broadway/broadway-bundle and ships with 1.0.0 as its first stable release. If you are coming from a Laravel background, be aware up front that this is not a Laravel package — there is no service provider, no config/dublin.php, and no facade. It registers as a Symfony Bundle and exposes services through the Symfony DI container. The CQRS/ES concepts (commands, command handlers, events, aggregates, event store, projections) transfer cleanly; the wiring does not.

Where to look first:

  1. composer require matiux/dublin-bundle (and confirm the matiux/dublin constraint resolves to ^3.0).
  2. Enable the bundle in config/bundles.php (Matiux\DublinBundle\DublinBundle::class => ['all' => true]).
  3. Look at the bundle's Resources/config / config/packages/dublin.yaml reference to see which tags (dublin.command_handler, dublin.event_listener, dublin.projector) exist and how the buses are wired.
  4. Read the README migration section — it is the authoritative "drop-in replacement" checklist.

First use case: define a command, an aggregate with handle* methods, a command handler tagged so the bundle registers it on the command bus, and a projector that reads from the event store. Dispatch the command from a controller ($commandBus->dispatch(new CreateThing(...))) and verify the projection updated. That single loop exercises the bundle's default wiring and surfaces almost every configuration issue you'll hit.

Implementation Patterns

Drop-in migration from Broadway Bundle. The release notes explicitly pitch this as a replacement for broadway/broadway-bundle. The mechanical step is swapping the Composer dependency, but you should also grep for Broadway\ namespaces — Dublin is API-compatible in spirit but not byte-for-byte, so imports, tag names, and any custom compiler passes referencing Broadway service IDs need a pass. Do the migration on a branch with the event store read path covered by a test before touching writes.

Tag-based handler discovery. The bundle's main value is auto-registration: tag command handlers, event listeners, and projectors in services.yaml and the bundle wires them onto the correct bus. A typical service definition:

App\Application\Command\CreateUserHandler:
    tags: [{ name: dublin.command_handler, bus: command_bus }]

Centralise this in one services.yaml block rather than scattering tags — a misnamed tag means a silently unregistered handler and a command that "dispatches" into the void.

Bus-per-context aliasing. If you need separate command buses (e.g. default, sync, async), define named buses in config and reference them explicitly from handlers and controllers. Avoid relying on the default alias in production code; be explicit so a later config change doesn't route your async work onto the synchronous bus.

Event store as a first-class fixture. In tests, point the event store at an in-memory or SQLite driver rather than the configured production store. Because the bundle wires the store as a service, you can override it per-environment in config/packages/test/dublin.yaml. This is the pattern that keeps event-sourced integration tests fast.

Projectors as the read-model boundary. Treat every projector as the only thing allowed to write to read tables. Application code should query the read model directly, never rehydrate aggregates for reads. This is the discipline that makes the bundle's bus wiring pay off.

Async listeners. Route event subscribers that do slow work (emails, external APIs) to an async transport. The bundle supports standard Symfony messenger integration for the event bus; keep the projector synchronous and offload side effects.

Gotchas and Tips

  • It is a Symfony bundle, not Laravel. Do not expect php artisan commands, facades, or a Laravel service provider. If you must use this from a Laravel app, you are effectively embedding a Symfony kernel/container or re-implementing the bundle's wiring by hand — usually the wrong trade. Prefer the standalone matiux/dublin library and wire it yourself, or accept a hybrid setup knowingly.
  • 1.0.0 is the first stable, but it is a fork. The changelog notes "internal cleanups" and "maintenance updates." Treat the 0.7.0 → 1.0.0 diff as more than a version bump; run your full event-sourcing test suite (aggregate rehydration, projection replay, snapshot behavior) after upgrading.
  • Drop-in replacement ≠ no-op upgrade. The release says "replace the dependency… update Composer configuration… review the README." Old broadway/broadway-bundle config keys, bundle class names, and service tags may differ. Diff your config/packages/*.yaml against the README's example config before trusting it.
  • Silent handler registration failures. A typo in a tag name or a missing autoconfigure: true means the handler never reaches the bus, and the failure mode is "nothing happened" rather than an exception. Debug with bin/console debug:container --tag=dublin.command_handler to confirm registration.
  • Event store choice is load-bearing. The bundle wires whatever event store you configure; the default is not necessarily production-grade. For anything with real write volume use a proper store (e.g. Doctrine DBAL, an outbox, or an external event store), and verify the serialiser round-trips your payloads — especially if you use value objects or enums.
  • Version constraints matter. Lock to matiux/dublin:^3.0 alongside the bundle; the notes say compatibility is with Dublin 3.x. Mixing a 2.x Dublin library with a 1.0 bundle will produce confusing service-definition failures.
  • Extension points. If the default wiring doesn't fit, the bundle exposes its compiler passes and config tree — you can add a custom compiler pass or override the bus definitions. Do this in DublinBundle's DependencyInjection/ layer rather than post-processing the container at runtime.
  • No Laravel ecosystem tooling. No migrations, no model factories, no queue integration via ShouldQueue. For async work, lean on Symfony Messenger and configure it explicitly; do not assume Laravel-style dispatch semantics.
  • Pin the version and watch the fork. Because this is a single-maintainer fork, pin ^1.0 and keep an eye on the changelog; future releases will "track Symfony and PHP evolution more closely," which likely means occasional breaking changes to the wiring contract even within the 1.x series if minimum Symfony/PHP versions are bumped.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle