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

micro-module/broadway-bundle

Integrates Broadway event sourcing and CQRS into Symfony applications, wiring command and event buses, event stores, read models, and supporting services through bundle configuration. Helps teams apply domain-driven design with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Before installing anything, reconcile the stack mismatch: this is a Symfony bundle, not a Laravel package. It ships a Bundle subclass and a DependencyInjection extension, not a ServiceProvider. If you are working in a Laravel codebase, the realistic path is one of two options:

  1. Use broadway/broadway directly (composer require broadway/broadway broadway/event-store-dbal) and wire the buses, event store, and repository in a service provider yourself. This is what most Laravel teams do.

  2. Only adopt this bundle if you are actually inside a Symfony app (or a component that boots a Symfony kernel), then register it in config/bundles.php:

    MicroModule\BroadwayBundle\BroadwayBundle::class => ['all' => true],
    

Assuming Symfony, the first things to read are, in order:

  • README.md — for the config tree and the tag names it advertises.
  • DependencyInjection/BroadwayExtension.php and DependencyInjection/Configuration.php — the authoritative source for service IDs, aliases, and tag names. Do not trust blog posts; the bundle is small and undocumented outside the code.
  • composer.json — to see which broadway/* sub-packages it pulls in (core only, or also event-store-dbal).

A minimal first use case: persist a single aggregate through the command bus and read it back. Define one command, one CommandHandler, one EventSourcedAggregateRoot, and a SimpleEventBus subscriber that logs the event. Configure the DBAL event store against your existing connection, create the event_store / snapshots tables, dispatch the command from a controller, and dump the event store rows. If that round-trip works, the rest of the bundle's value (projections, sagas) is incremental.

Implementation Patterns

  • Command dispatch from the edge. Inject the command bus into controllers/HTTP handlers and dispatch a command object; never let the controller touch an aggregate repository directly. The bus should be the only entry point; in a Laravel port you register SimpleCommandBus as a singleton and build a handler map from your app/Commands namespace.

  • Handler registration via tags (Symfony) or a map (Laravel). Broadway's SimpleCommandBus resolves handlers by command class name, so the wiring is mechanical. In Symfony the bundle expects handlers tagged (look for broadway.command_handler or similar in the extension) with #[AutoconfigureTag] or YAML. In a hand-rolled Laravel wiring, build the map explicitly in the provider or use a convention-based scan — the latter is fragile, prefer the explicit map.

  • Event store as the source of truth, projections as disposable. Configure the DBAL event store with your existing Doctrine connection and a SimpleInterfaceSerializer (or Symfony's serializer). Treat projections as rebuildable caches: expose an artisan/console command that truncates the read model and replays from offset zero. This is the single most important operational pattern; without it, a schema change forces a full outage.

  • Projectionist for read models. Register projections as event subscribers with Projectionist::project(). For Symfony, tag them; for Laravel, subscribe them on the event bus and dispatch inside a DB::transaction if the projection is not idempotent. Keep projections synchronous in dev, async in production — see gotchas.

  • Sagas for cross-aggregate workflows (StatefulSagaOf). Use only when you genuinely have a long-running process. For a Laravel developer the mental model is a queued job with persisted state, but with event-sourced replay semantics.

  • Testing pattern. Unit-test command handlers against an in-memory event store (Broadway\EventStore\InMemoryEventStore) — no DB, no kernel. Reserve full-stack tests for the projection rebuild path, since that is where serialization and offset bugs live.

  • Integration tip for mixed stacks. If you must run this bundle inside a Laravel app via a container bridge, isolate it behind a facade or a single EventSourcing service; do not let bundle-managed service IDs leak into application code, or you will be unable to swap it out.

Gotchas and Tips

  • It is not a Laravel package. There is no BroadwayServiceProvider, no facade, no published config. Any tutorial that says "just composer require in Laravel" is wrong. Budget for manual wiring; treat the bundle as reference implementation for how to structure that wiring.

  • Zero dependents, zero stars, last release July 2023. This is effectively an unmaintained personal bundle. Pin the exact version in composer.json and vendor-fork it if you depend on it in production. Prefer depending on broadway/broadway and broadway/event-store-dbal directly — they are the maintained upstream.

  • The event store schema is not auto-migrated. You must create the tables yourself (typically event_store and snapshots plus indexes on uuid and playhead). Missing indexes show up as slow aggregate loads only after a few hundred thousand events, not in testing. Add them up front.

  • Serialization is the sharp edge. Events must round-trip through the serializer byte-for-byte. Adding a property to an event class breaks old rows unless you version events or write an upcaster. Adopt a convention (EventV1, EventV2) from day one; retrofitting is painful.

  • Concurrency and optimistic locking. Broadway's EventSourcingRepository relies on the event store rejecting a write when the aggregate's playhead does not match. Confirm the DBAL store is configured with the concurrency check enabled, otherwise parallel commands silently corrupt an aggregate.

  • Synchronous event handlers hide failures until production. In dev, a single process makes everything look transactional; in production, an async projection that throws will stall the consumer. Decide early whether projections are in-process or queued and make the choice explicit in config rather than defaulting.

  • Configuration quirks live in Configuration.php, not the README. The bundle's config tree is short; read it before guessing key names. Unknown keys are typically silently ignored unless the extension calls validate(), which small bundles often omit.

  • Extension points are limited. If the bundle does not expose the service you need, override it by alias in services.yaml rather than editing the vendor copy. The cleanest escape hatch in either framework is to ignore the bundle's auto-wiring and register Broadway's plain classes yourself — you lose nothing, because the bundle is thin.

  • Debugging tip. Log every command and every event with the aggregate UUID and playhead at the bus boundary. When a projection is wrong, the question is almost always "was the event written, or was it written twice?" — and that log answers it in seconds.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource