Skip to content

Commit

Permalink
Add a domain event dispatcher service to decouple publishing from dis…
Browse files Browse the repository at this point in the history
…patching (#15)
  • Loading branch information
wazum authored Aug 16, 2020
1 parent 566d8e1 commit b4be28e
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 8 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,51 @@ date/time, the reminder must also be modified. By implementing
providing that the previous _ReminderDue_ event had not been published, it will
be removed and superseded by the new _ReminderDue_ event.

### Event dispatching

By default only the DomainEvent is dispatched to the configured event bus.

You can overwrite the default event dispatcher with your own implementation to
annotate the message before dispatching it, e.g. to add an envelope with custom stamps.

Example:

```yaml
services:
headsnet_domain_events.domain_event_dispatcher_service:
class: App\Infrastructure\DomainEventDispatcher
```
```php
class PersonCreated implements DomainEvent, AuditableEvent
{
}
```

```php
class DomainEventDispatcher implements \Headsnet\DomainEventsBundle\EventSubscriber\DomainEventDispatcher
{
private MessageBusInterface $eventBus;

public function __construct(MessageBusInterface $eventBus)
{
$this->eventBus = $eventBus;
}

public function dispatch(DomainEvent $event): void
{
if ($event instanceof AuditableEvent) {
$this->eventBus->dispatch(
new Envelope($event, [new AuditStamp()])
);
} else {
$this->eventBus->dispatch($event);
}
}
}
```

### Messenger Component

By default, the bundle expects a message bus called `messenger.bus.event` to be
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyInjection/HeadsnetDomainEventsExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function load(array $configs, ContainerBuilder $container): void
private function useCustomMessageBusIfSpecified(array $config, ContainerBuilder $container): void
{
if (isset($config['message_bus']['name'])) {
$definition = $container->getDefinition('headsnet_domain_events.event_subscriber.publisher');
$definition = $container->getDefinition('headsnet_domain_events.domain_event_dispatcher_service');
$definition->replaceArgument(0, new Reference($config['message_bus']['name']));
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/EventSubscriber/DomainEventDispatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony HeadsnetDomainEventsBundle.
*
* (c) Headstrong Internet Services Ltd 2020
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Headsnet\DomainEventsBundle\EventSubscriber;

use Headsnet\DomainEventsBundle\Domain\Model\DomainEvent;

interface DomainEventDispatcher
{
public function dispatch(DomainEvent $event): void;
}
34 changes: 34 additions & 0 deletions src/EventSubscriber/NoEnvelopeDomainEventDispatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony HeadsnetDomainEventsBundle.
*
* (c) Headstrong Internet Services Ltd 2020
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Headsnet\DomainEventsBundle\EventSubscriber;

use Headsnet\DomainEventsBundle\Domain\Model\DomainEvent;
use Symfony\Component\Messenger\MessageBusInterface;

class NoEnvelopeDomainEventDispatcher implements DomainEventDispatcher
{
/**
* @var MessageBusInterface
*/
private $eventBus;

public function __construct(MessageBusInterface $eventBus)
{
$this->eventBus = $eventBus;
}

public function dispatch(DomainEvent $event): void
{
$this->eventBus->dispatch($event);
}
}
11 changes: 5 additions & 6 deletions src/EventSubscriber/PublishDomainEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Serializer\SerializerInterface;

final class PublishDomainEventSubscriber implements EventSubscriberInterface
{
/**
* @var MessageBusInterface
* @var DomainEventDispatcher
*/
private $eventBus;
private $domainEventDispatcher;

/**
* @var EventStore
Expand All @@ -47,12 +46,12 @@ final class PublishDomainEventSubscriber implements EventSubscriberInterface
private $lockFactory;

public function __construct(
MessageBusInterface $eventBus,
DomainEventDispatcher $domainEventDispatcher,
EventStore $eventStore,
SerializerInterface $serializer,
LockFactory $lockFactory
) {
$this->eventBus = $eventBus;
$this->domainEventDispatcher = $domainEventDispatcher;
$this->eventStore = $eventStore;
$this->serializer = $serializer;
$this->lockFactory = $lockFactory;
Expand Down Expand Up @@ -102,7 +101,7 @@ private function publishEvent(StoredEvent $storedEvent): void
);
assert($domainEvent instanceof DomainEvent);

$this->eventBus->dispatch($domainEvent);
$this->domainEventDispatcher->dispatch($domainEvent);
$this->eventStore->publish($storedEvent);

$lock->release();
Expand Down
9 changes: 8 additions & 1 deletion src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@
just configure the default lock using the framework bundle configuration -->
<service id="headsnet_domain_events.lock_factory_service" alias="lock.factory"/>

<!-- Clients can override this to change the default domain event dispatcher -->
<service id="headsnet_domain_events.domain_event_dispatcher_service"
class="Headsnet\DomainEventsBundle\EventSubscriber\NoEnvelopeDomainEventDispatcher"
public="false">
<argument type="service" id="messenger.bus.event"/>
</service>

<service id="headsnet_domain_events.event_subscriber.publisher"
class="Headsnet\DomainEventsBundle\EventSubscriber\PublishDomainEventSubscriber"
public="false">
<argument type="service" id="messenger.bus.event"/>
<argument type="service" id="headsnet_domain_events.domain_event_dispatcher_service"/>
<argument type="service" id="headsnet_domain_events.repository.event_store_doctrine"/>
<argument type="service" id="serializer"/>
<argument type="service" id="headsnet_domain_events.lock_factory_service"/>
Expand Down

0 comments on commit b4be28e

Please sign in to comment.