Skip to content

Commit

Permalink
step 10: introduce domain events
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Lelaisant committed Nov 7, 2022
1 parent 95ccd9c commit 15db081
Show file tree
Hide file tree
Showing 19 changed files with 354 additions and 11 deletions.
9 changes: 9 additions & 0 deletions config/packages/messenger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ framework:

buses:
command.bus:
default_middleware: true
middleware:
- Infrastructure\Symfony\Messenger\Middleware\DomainEventDispatcher
- dispatch_after_current_bus
- doctrine_transaction

query.bus: ~

event.bus:
default_middleware: allow_no_handlers
middleware:
- dispatch_after_current_bus
- doctrine_transaction
2 changes: 2 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ services:

Application\:
resource: '../src/Application/'
exclude:
- '../src/Application/DomainEventsHandler/'
12 changes: 12 additions & 0 deletions config/services/domain_events.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
services:
_defaults:
autowire: true
public: false

Domain\EventsRegisterer: ~

Application\DomainEventsHandler\:
resource: '%kernel.project_dir%/src/Application/DomainEventsHandler/**.php'
tags:
- { name: messenger.message_handler, bus: event.bus }
9 changes: 9 additions & 0 deletions config/services/messenger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ services:
autoconfigure: true
public: false

Infrastructure\Symfony\Messenger\Middleware\:
resource: '%kernel.project_dir%/src/Infrastructure/Symfony/Messenger/Middleware/**.php'

Infrastructure\Symfony\Messenger\CommandBus:
$messageBus: '@command.bus'

Expand All @@ -16,3 +19,9 @@ services:

Application\MessageBus\QueryBus:
alias: Infrastructure\Symfony\Messenger\QueryBus

Infrastructure\Symfony\Messenger\EventBus:
$messageBus: '@event.bus'

Application\MessageBus\EventBus:
alias: Infrastructure\Symfony\Messenger\EventBus
18 changes: 8 additions & 10 deletions src/Application/Controller/DinosaursController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
use Application\Form\Type\DinosaurType;
use Application\Form\Type\SearchType;
use Application\MessageBus\CommandBus;
use Application\MessageBus\EventBus;
use Application\MessageBus\QueryBus;
use Domain\Event\DinosaurIsBorn;
use Domain\Exception\DinosaurNotFoundException;
use Domain\Query\GetSingleDinosaur;
use Domain\Query\GetAllDinosaurs;
Expand All @@ -22,7 +24,8 @@ class DinosaursController extends AbstractController
{
public function __construct(
private CommandBus $commandBus,
private QueryBus $queryBus
private QueryBus $queryBus,
private EventBus $eventBus
) {}

#[Route('/dinosaurs', name: 'app_list_dinosaurs')]
Expand Down Expand Up @@ -54,15 +57,10 @@ public function list(Request $request): Response
)]
public function single(string $id): Response
{
$dinosaur = $this
->dinosaursCollection
->find($id)
;

if ($dinosaur === false) {
throw $this->createNotFoundException(
'The dinosaur you are looking for does not exists.'
);
try {
$dinosaur = $this->queryBus->dispatch(new GetSingleDinosaur\Query($id));
} catch (DinosaurNotFoundException $e) {
throw $this->createNotFoundException();
}

return $this->render('dinosaur.html.twig', [
Expand Down
35 changes: 35 additions & 0 deletions src/Application/DomainEventsHandler/LogWhenDinosaurDied.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Application\DomainEventsHandler;

use Domain\Event\DinosaurDied;
use Domain\Event\EventInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;

class LogWhenDinosaurDied implements MessageSubscriberInterface
{
public function __construct(
private LoggerInterface $logger
) {
}

public function __invoke(EventInterface $event): void
{
if (!$event instanceof DinosaurDied) {
return;
}

$this->logger->info(sprintf(
'Dinosaur %s died',
$event->getDinosaurName()
));
}

public static function getHandledMessages(): iterable
{
yield DinosaurDied::class;
}
}
43 changes: 43 additions & 0 deletions src/Application/DomainEventsHandler/LogWhenDinosaurIsBorn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Application\DomainEventsHandler;

use Domain\Collection\DinosaursCollection;
use Domain\Event\DinosaurIsBorn;
use Domain\Event\EventInterface;
use Domain\Exception\DinosaurNotFoundException;
use Domain\Model\Dinosaur;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;

class LogWhenDinosaurIsBorn implements MessageSubscriberInterface
{
public function __construct(
private DinosaursCollection $dinosaursCollection,
private LoggerInterface $logger
) {
}

public function __invoke(EventInterface $event): void
{
$dinosaurId = $event->getAggregateRootId();

$dinosaur = $this->dinosaursCollection->find($dinosaurId);

if (!$dinosaur instanceof Dinosaur) {
throw new DinosaurNotFoundException($dinosaurId);
}

$this->logger->info(sprintf(
'Dinosaur %s was born',
$dinosaur->getName()
));
}

public static function getHandledMessages(): iterable
{
yield DinosaurIsBorn::class;
}
}
10 changes: 10 additions & 0 deletions src/Application/MessageBus/EventBus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Application\MessageBus;

interface EventBus
{
public function dispatch(object $event): void;
}
27 changes: 27 additions & 0 deletions src/Domain/Event/DinosaurDied.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Domain\Event;

use Domain\Model\Dinosaur;

final class DinosaurDied implements EventInterface
{
private string $dinosaurName;

public function __construct(private Dinosaur $dinosaur)
{
$this->dinosaurName = $dinosaur->getName();
}

public function getAggregateRootId(): string
{
return (string) $this->dinosaur->getId();
}

public function getDinosaurName(): string
{
return $this->dinosaurName;
}
}
20 changes: 20 additions & 0 deletions src/Domain/Event/DinosaurIsBorn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Domain\Event;

use Domain\Model\Dinosaur;

class DinosaurIsBorn implements EventInterface
{
public function __construct(
private Dinosaur $dinosaur
) {
}

public function getAggregateRootId(): string
{
return (string) $this->dinosaur->getId();
}
}
10 changes: 10 additions & 0 deletions src/Domain/Event/EventInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Domain\Event;

interface EventInterface
{
public function getAggregateRootId(): string;
}
31 changes: 31 additions & 0 deletions src/Domain/EventsRegisterer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Domain;

use Domain\Event\EventInterface;

class EventsRegisterer
{
/** @var array<EventInterface> */
private array $events = [];

public function register(EventInterface ...$events): void
{
array_push($this->events, ...$events);
}

/**
* @return array<EventInterface>
*/
public function getEvents(): array
{
return $this->events;
}

public function flush(): void
{
$this->events = [];
}
}
30 changes: 30 additions & 0 deletions src/Domain/HasEventsRegisterer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Domain;

use Domain\Event\EventInterface;

trait HasEventsRegisterer
{
private EventsRegisterer $eventsRegisterer;

/**
* @required
*/
public function setEventsRegisterer(EventsRegisterer $eventsRegisterer): void
{
$this->eventsRegisterer = $eventsRegisterer;
}

public function getEventsRegisterer(): EventsRegisterer
{
return $this->eventsRegisterer;
}

public function registerEvents(EventInterface ...$events): void
{
$this->eventsRegisterer->register(...$events);
}
}
11 changes: 11 additions & 0 deletions src/Domain/Model/AggregateRoot.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Domain\Model;

interface AggregateRoot
{
public function getId(): int;
}

2 changes: 1 addition & 1 deletion src/Domain/Model/Dinosaur.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Domain\Model;

class Dinosaur
class Dinosaur implements AggregateRoot
{
private int $id;
private string $name;
Expand Down
6 changes: 6 additions & 0 deletions src/Domain/UseCase/CreateDinosaur/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@

use Domain\Collection\DinosaursCollection;
use Domain\Collection\SpeciesCollection;
use Domain\Event\DinosaurIsBorn;
use Domain\Exception\DinosaurAlreadyExistsException;
use Domain\Exception\SpeciesNotFoundException;
use Domain\HasEventsRegisterer;
use Domain\Model\Dinosaur;

class Handler
{
use HasEventsRegisterer;

public function __construct(
private DinosaursCollection $dinosaursCollection,
private SpeciesCollection $speciesCollection
Expand Down Expand Up @@ -48,6 +52,8 @@ public function __invoke(Input $input): Output

$this->dinosaursCollection->add($dinosaur);

$this->registerEvents(new DinosaurIsBorn($dinosaur));

return new Output($dinosaur);
}
}
6 changes: 6 additions & 0 deletions src/Domain/UseCase/RemoveDinosaur/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
namespace Domain\UseCase\RemoveDinosaur;

use Domain\Collection\DinosaursCollection;
use Domain\Event\DinosaurDied;
use Domain\Exception\DinosaurNotFoundException;
use Domain\HasEventsRegisterer;

class Handler
{
use HasEventsRegisterer;

public function __construct(
private DinosaursCollection $dinosaursCollection
) {
Expand All @@ -27,6 +31,8 @@ public function __invoke(Input $input): Output

$this->dinosaursCollection->remove($dinosaur);

$this->registerEvents(new DinosaurDied($dinosaur));

return new Output();
}
}
Loading

0 comments on commit 15db081

Please sign in to comment.