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

Domain Event Dispatcher Laravel Package

ashleydawson/domain-event-dispatcher

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require ashleydawson/domain-event-dispatcher
    

    Register the service provider in config/app.php under providers:

    AshleyDawson\DomainEventDispatcher\DomainEventDispatcherServiceProvider::class,
    
  2. Define an Event Create a simple event class (must be serializable):

    namespace App\Events;
    class UserRegistered {
        public function __construct(public string $userId) {}
    }
    
  3. Create a Listener Implement __invoke() to handle the event:

    namespace App\Listeners;
    use App\Events\UserRegistered;
    
    class SendWelcomeEmail {
        public function __invoke(UserRegistered $event) {
            // Logic here
        }
    }
    
  4. Dispatch from a Model Use the singleton dispatcher directly in your domain model:

    use AshleyDawson\DomainEventDispatcher\DomainEventDispatcher;
    
    class User {
        public function register() {
            // ... business logic ...
            DomainEventDispatcher::getInstance()->dispatch(
                new UserRegistered($this->id)
            );
        }
    }
    
  5. Register Listeners Bind listeners in a service provider or boot method:

    DomainEventDispatcher::getInstance()->addListener(
        new SendWelcomeEmail()
    );
    

Implementation Patterns

Core Workflows

  1. Deferred Dispatching Use defer() to queue events for later processing (e.g., after transaction commit):

    DomainEventDispatcher::getInstance()->defer(
        new UserRegistered($userId)
    );
    

    Process deferred events via the processDeferred() method (e.g., in a command bus or job).

  2. Typed Listeners Leverage type-hinting in __invoke() for clarity and IDE support:

    public function __invoke(UserRegistered $event) { ... }
    
  3. Dynamic Registration Register listeners conditionally (e.g., based on config or environment):

    if (config('features.email_notifications')) {
        DomainEventDispatcher::getInstance()->addListener(
            new SendWelcomeEmail()
        );
    }
    
  4. Integration with Laravel Events Bridge to Laravel’s event system for broader compatibility:

    DomainEventDispatcher::getInstance()->addListener(
        new class implements ShouldQueue {
            public function __invoke(UserRegistered $event) {
                event(new \Illuminate\Queue\Events\JobProcessed(...));
            }
        }
    );
    
  5. Domain-Driven Dispatching Use in aggregate roots or domain services:

    class Order {
        public function place() {
            // ... validation ...
            $this->status = 'placed';
            DomainEventDispatcher::getInstance()->dispatch(
                new OrderPlaced($this->id)
            );
        }
    }
    

Integration Tips

  • Service Container Binding Bind the dispatcher to Laravel’s container for dependency injection:

    $app->singleton(DomainEventDispatcher::class, function () {
        return DomainEventDispatcher::getInstance();
    });
    

    Then inject DomainEventDispatcher into classes via constructor.

  • Testing Mock the dispatcher in tests:

    $dispatcher = Mockery::mock(DomainEventDispatcher::class);
    $dispatcher->shouldReceive('dispatch')->once();
    $this->app->instance(DomainEventDispatcher::class, $dispatcher);
    
  • Event Serialization Ensure events implement Serializable or use __serialize()/__unserialize() for deferred dispatching.


Gotchas and Tips

Pitfalls

  1. Singleton State The dispatcher is a singleton, so avoid shared state (e.g., static properties in listeners). Use dependency injection for shared dependencies.

  2. Deferred Event Order Deferred events are processed in FIFO order, but not transactionally. Use a queue (e.g., Laravel Queues) for reliability.

  3. Listener Order Listeners are invoked in registration order. Use priority flags (if extended) or explicit ordering logic.

  4. Circular Dependencies Avoid circular references between events/listeners (e.g., EventA dispatches EventB, which re-dispatches EventA).

  5. Performance Heavy listeners may block dispatching. Offload work to queues or background jobs.


Debugging

  • Listener Not Firing Verify:

    • The listener is registered before dispatching.
    • The event class matches the listener’s type-hint (if any).
    • No exceptions are silently caught in __invoke().
  • Deferred Events Lost Ensure processDeferred() is called (e.g., in a console command or HTTP middleware).

  • Serialization Errors Check for non-serializable properties in events. Use json_encode()/json_decode() for debugging:

    json_encode(new UserRegistered('123')); // Should not throw
    

Extension Points

  1. Custom Storage Override deferred event storage (e.g., database or Redis) by extending DomainEventDispatcher:

    class CustomDispatcher extends DomainEventDispatcher {
        protected function storeDeferredEvent($event) {
            // Custom logic
        }
    }
    
  2. Listener Priorities Add priority support:

    interface ListenerPriority {
        public const LOW = 0;
        public const HIGH = 100;
    }
    

    Modify addListener() to accept a priority parameter.

  3. Event Filtering Implement filtering (e.g., by event properties) in dispatch():

    if (!$this->shouldDispatch($event)) return;
    
  4. Laravel Integration Extend to support Laravel’s event system:

    DomainEventDispatcher::getInstance()->addListener(
        new class implements ShouldBroadcast {
            public function __invoke(UserRegistered $event) {
                broadcast(new UserRegisteredBroadcast($event));
            }
        }
    );
    

Config Quirks

  • No Built-in Config The package has no config file. Default behavior is fixed; extend the class for customization.

  • Service Provider Ensure the provider is registered before first use (e.g., in AppServiceProvider::boot()).

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.
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium