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 Laravel Package

micro-module/broadway

Broadway is a modular admin panel package for Laravel, offering dashboards, menus, user and permission management out of the box. Build back-office interfaces quickly and extend them with your own modules.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and inspect

composer require micro-module/broadway

Before writing any application code, read the package source. It is a thin Laravel wrapper around broadway/broadway, so the authoritative documentation for the core concepts (AggregateRoot, CommandBus, EventBus, EventStore, Sagas) lives at broadway.github.io/broadway/ — not in this package's README. Start with these files in the vendor directory:

  • The service provider (src/*ServiceProvider.php) — defines every binding, alias, and tag the package gives you.
  • Any config file (config/broadway.php) — check whether it is publishable: php artisan vendor:publish --provider="MicroModule\\Broadway\\...".
  • The testing helpers (look for a Testing/ or Concerns/ directory, or a trait such as InteractsWithBroadway) — this is the package's main value proposition.

2. Confirm the contract bindings

The wrapper's job is to bind Broadway's interfaces into Laravel's container. Verify with:

php artisan tinker
>>> app(\Broadway\CommandHandling\CommandBus::class);
>>> app(\Broadway\EventHandling\EventBus::class);
>>> app(\Broadway\EventStore\EventStore::class);

If any of these fail to resolve, the service provider is not registered (check composer.json → extra.laravel.providers and your bootstrap/providers.php / config/app.php).

3. First use case: a round-trip in a test

Do not start with your domain. Start with a single aggregate and prove the loop works: command → handler → aggregate → event → in-memory event store → read back.

use Broadway\CommandHandling\Testing\TraceableCommandBus;
use Broadway\EventStore\InMemoryEventStore;

public function test_account_can_be_opened(): void
{
    $store = new InMemoryEventStore();
    $repository = new SimpleEventSourcingRepository($store, new AccountAggregateFactory());
    // dispatch OpenAccount command, assert AccountOpened event is in the store
}

Once that test is green, you know the package's wiring (serializers, buses, repository factories) matches what Broadway expects. Only then configure the persistent (DBAL/Doctrine) event store.


Implementation Patterns

Command → handler wiring

Broadway is not Laravel-native; it will not auto-discover handlers the way laravel/bus discovers jobs. The idiomatic pattern is a hand-maintained SimpleCommandBus registration, typically inside a service provider or a dedicated CommandBusFactory:

$commandBus = new SimpleCommandBus();
$commandBus->subscribe(new OpenAccountHandler($repository));

If the package provides a container-aware command bus or handler tag (broadway.command-handler or similar), prefer tagging:

$this->app->tag([OpenAccountHandler::class], 'broadway.command_handler');

and then resolve $this->app->tagged('broadway.command_handler') in the bus factory. Check the provider for the exact tag name — this package deliberately stays small, so the convention is defined there, not in docs.

One service provider per bounded context

For anything beyond a demo, create a BillingServiceProvider per module that:

  1. Registers the aggregate repository (SimpleEventSourcingRepository + factory).
  2. Subscribes command handlers to the command bus.
  3. Subscribes projectors/read-model listeners to the event bus.
  4. Registers sagas.

Keeping each context's wiring isolated means you can swap the event store (in-memory for a context test, DBAL for integration) without touching the app-wide singleton.

Read models and projections

Broadway projectors are plain listeners. Map them in the same provider so the event bus and the read-model writes stay in sync:

$eventBus->subscribe(new OrderProjector($connection));

Because this package targets Laravel, the practical shortcut is to inject Illuminate\Database\Connection or an Eloquent model directly into projectors and drop Broadway's ReadModel abstraction — but do this consistently, not per-module, or you will end up with two parallel projection styles.

Testing patterns (the package's real payoff)

The testing helpers should let you drive the system without infrastructure. Typical shape:

use MicroModule\Broadway\Testing\InteractsWithBroadway;

class TransferMoneyTest extends TestCase
{
    use InteractsWithBroadway;

    public function test_money_is_transferred(): void
    {
        $this->given(new AccountOpened($id, 100));
        $this->when(new TransferMoney($id, $to, 40));
        $this->then(new MoneyTransferred($id, $to, 40));
    }
}

This is the given/when/then event-sourcing test style from Broadway's Scenario. Use it for every aggregate. If the package's trait exposes assertEventsEmitted, assertCommandHandled, or a traceable command bus, wrap them in your own base TestCase so you can swap the implementation if the package is abandoned.

Integration with the HTTP layer

Controllers should dispatch commands, never touch repositories:

public function store(OpenAccountRequest $request, CommandBus $bus): Response
{
    $bus->dispatch(new OpenAccount(Uuid::uuid4()->toString(), $request->input('name')));
    return response()->noContent(201);
}

If the package does not provide a Laravel command-bus decorator that participates in transactions, dispatch inside DB::transaction(...) yourself — event-sourced aggregates and read-model writes must not diverge on a failed write.


Gotchas and Tips

Maturity and maintenance risk

0 stars, 0 dependents, last release July 2023. Treat this as vendored code: pin an exact version ("micro-module/broadway": "1.0.3" rather than ^1.0), and be prepared to fork. Before committing, read composer.json — check the PHP constraint against your runtime and whether broadway/broadway is a loose (^) dependency, which can drag in breaking changes.

No auto-discovery guarantees

If the package predates Laravel 11's bootstrap/providers.php and only registers via extra.laravel.providers, it still works, but package discovery can silently fail under --no-dev optimized autoloaders if composer dump-autoload -o wasn't run. Symptom: Target [CommandBus] is not instantiable. Fix: php artisan optimize:clear && composer dump-autoload.

The in-memory event store is a test double, not a cache

InMemoryEventStore loses everything between requests. If a dev accidentally binds it in AppServiceProvider, tests pass and production silently forgets events. Guard against this: bind the in-memory store only inside TestCase::setUp() or a testing environment check, never in a shared provider.

Serialization is the usual failure point

Broadway serializes aggregates and events. When you add a field to an event class, old stored events still deserialize if you use SimpleSerializer, but renaming a class or property will break replay. Establish a rule from day one: event classes are append-only and immutable. Keep an upcaster if you must evolve them, and never "tidy up" event property names.

Debugging an event stream

There is no artisan inspector in this package. When a projector misbehaves, drop to SQL against your event store table:

SELECT * FROM event_store WHERE uuid = ? ORDER BY playhead;

and manually json_decode the payload. Keeping the DBAL event store on a normal MySQL/Postgres connection (rather than an opaque stream store) is the single biggest debugging ergonomics win.

No handler = silent no-op

SimpleCommandBus throws on an unhandled command, but some Broadway versions log-and-ignore depending on the configured bus. Assert in every command test that some event was emitted, not just that no exception was thrown. Likewise, subscribers registered after the bus is resolved from the container won't be attached to the singleton — register in a provider, not in a controller.

Extension points to know

  • Event store: swap InMemoryEventStore for Broadway's DBALEventStore (or your own implementing EventStore) — bind it in the provider; nothing else in the package should know which one is used.
  • Serializer: if the package doesn't expose it, instantiate SimpleSerializer yourself and pass it to the repository factory.
  • Buses: both CommandBus and EventBus are interfaces — to add middleware (logging, transactions), write a small decorator implementing the same interface and bind that. This is safer than modifying the package.

Migration path if abandoned

Because Broadway's interfaces are the real contract, you can drop the wrapper in an afternoon: register SimpleCommandBus/SimpleEventBus/your chosen event store directly in AppServiceProvider, and copy the testing trait into your tests/ directory. Design your handlers and projectors so they depend only on Broadway interfaces, never on MicroModule\Broadway\* classes, and the migration cost stays near zero.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource