Weave Code
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

broadway/broadway-bundle

Symfony bundle that integrates Broadway CQRS/ES into your app. Symfony Flex installs and configures it automatically, with in-memory event store and read models by default and options for persistent implementations. Documentation available at broadway.github.io.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require symfony/flex
    composer config extra.symfony.allow-contrib true
    composer require broadway/broadway-bundle
    

    Symfony Flex auto-configures the bundle with in-memory implementations.

  2. First Use Case: Define a command and handler to test the command bus:

    // src/Command/ExampleCommand.php
    class ExampleCommand implements Command
    {
        public function __construct(public string $message) {}
    }
    
    // src/CommandHandler/ExampleCommandHandler.php
    class ExampleCommandHandler implements CommandHandler
    {
        public function handle(ExampleCommand $command): void
        {
            // Business logic here
        }
    }
    

    Register the handler in config/services.yaml:

    App\CommandHandler\ExampleCommandHandler:
        tags: [broadway.command_handler]
    
  3. Dispatch a Command: Inject broadway.command_handling.command_bus and dispatch:

    $commandBus->dispatch(new ExampleCommand("Hello, Broadway!"));
    

Implementation Patterns

Core Workflows

  1. Event-Driven Architecture:

    • Use projectors (tagged with broadway.domain.event_listener) to update read models:
      App\Projector\ExampleProjector:
          tags: [broadway.domain.event_listener]
      
    • Example projector:
      class ExampleProjector implements DomainEventListener
      {
          public function handle(DomainEvent $event): void
          {
              // Update read models (e.g., Elasticsearch, MongoDB)
          }
      }
      
  2. Metadata Enrichment:

    • Add contextual data (e.g., user IP, request ID) to events:
      App\Metadata\IpMetadataEnricher:
          arguments: ["@request_stack"]
          tags: [broadway.metadata_enricher]
      
  3. Sagas for Long-Running Workflows:

    • Enable sagas in config/packages/broadway.yaml:
      broadway:
          saga:
              enabled: true
      
    • Register a saga:
      App\Saga\ReservationSaga:
          arguments: ["@broadway.command_handling.command_bus", "@broadway.uuid.generator"]
          tags: [broadway.saga, { type: reservation }]
      
  4. Persistent Storage:

    • Swap in-memory stores for production-ready ones (e.g., DBAL, MongoDB):
      composer require broadway/event-store-dbal
      
    • Update config/packages/broadway.yaml:
      broadway:
          event_store: broadway.event_store.dbal
      

Integration Tips

  • Symfony Messenger Bridge: Use broadway.command_handling.command_bus alongside Symfony Messenger for hybrid architectures.
  • Doctrine ORM: Combine with Doctrine for hybrid event-sourcing/CQRS patterns (e.g., use Doctrine for aggregates, Broadway for events).
  • Testing: Mock broadway.event_store and broadway.read_model in tests for isolation:
    $this->container->set('broadway.event_store', $mockEventStore);
    

Gotchas and Tips

Pitfalls

  1. In-Memory Stores in Production:

    • Default in-memory implementations reset on app restart. Always configure persistent stores (DBAL/MongoDB) for production.
    • Fix: Update broadway.yaml as shown in Event Store.
  2. Event Serialization:

    • Broadway uses broadway.simple_interface_serializer by default, which may not support all PHP types (e.g., DateTimeImmutable).
    • Fix: Customize serializers in broadway.yaml:
      broadway:
          serializer:
              payload: App\Serializer\CustomPayloadSerializer
      
  3. Saga State Persistence:

    • Sagas require a persistent state repository (e.g., MongoDB). The default in-memory repo won’t work for sagas.
    • Fix: Install broadway/broadway-saga and configure:
      broadway:
          saga:
              state_repository: broadway.saga.state.mongodb_repository
      
  4. Command Bus Dispatch Events:

    • By default, dispatch_events: false in broadway.yaml. Set to true if you need to publish events after command handling.
    • Warning: This can lead to event loops if not managed carefully.
  5. UUID Generation:

    • Broadway uses its own UUID generator. If you rely on Symfony’s Uuid component, ensure consistency by using the same generator service.

Debugging Tips

  • Event Store Inspection: Use Symfony’s debug container to inspect stored events:

    ./bin/console debug:container broadway.event_store
    

    For DBAL stores, query the event_entry table directly.

  • Projector Debugging: Log domain events to track projector execution:

    broadway:
        command_handling:
            logger: "@monolog.logger.broadway"
    
  • Saga Debugging: Enable saga logging in config/packages/monolog.yaml:

    handlers:
        broadway_saga:
            type: stream
            path: "%kernel.logs_dir%/broadway_saga.log"
            level: debug
    

Extension Points

  1. Custom Event Store: Implement Broadway\EventStore\EventStore and register it in broadway.yaml:

    broadway:
        event_store: App\EventStore\CustomEventStore
    
  2. Read Model Projections: Extend Broadway\ReadModel\Projector to create custom projections:

    class CustomProjection extends Projector
    {
        protected function whenSomethingHappened(SomethingHappened $event): void
        {
            // Update your read model
        }
    }
    
  3. Metadata Enrichers: Chain enrichers for layered metadata (e.g., user + IP + request ID):

    class CompositeMetadataEnricher implements MetadataEnricher
    {
        public function __construct(private iterable $enrichers) {}
    
        public function enrich(Metadata $metadata): Metadata
        {
            foreach ($this->enrichers as $enricher) {
                $metadata = $enricher->enrich($metadata);
            }
            return $metadata;
        }
    }
    
  4. Command Validation: Use Symfony Validator with Broadway commands:

    class ExampleCommandHandler implements CommandHandler
    {
        public function __construct(private ValidatorInterface $validator) {}
    
        public function handle(ExampleCommand $command): void
        {
            $errors = $this->validator->validate($command);
            if (count($errors) > 0) {
                throw new InvalidCommandException($errors);
            }
            // Proceed
        }
    }
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui