From defe686f2af18ed741bf1a9a5fa89beb541551c9 Mon Sep 17 00:00:00 2001 From: Carlos Buenosvinos Date: Tue, 22 Mar 2022 06:58:03 +0100 Subject: [PATCH] [Chapter 8] Improvements --- .../NotifyToAuthorAboutNewFollowerCommand.php | 43 +++++++++++++++++ ...ToAuthorAboutNewFollowerCommandHandler.php | 36 ++++++++++++++ .../Author/Command/WelcomeCommand.php | 29 +++++++++++ .../Author/Command/WelcomeCommandHandler.php | 35 ++++++++++++++ ...crementFollowersProjectionEventHandler.php | 28 +++++++++++ ...orFollowedThenNotifyAuthorEventHandler.php | 29 +++++++++++ .../Event/AuthorFollowedEventHandler.php | 15 +++++- ...FollowersCounterProjectionEventHandler.php | 26 ++++++++++ ...horSignedThenWelcomeAuthorEventHandler.php | 26 ++++++++++ .../Event/NewAuthorSignedEventHandler.php | 9 ++++ .../IncrementCountFollowersProjection.php | 31 ++++++++++++ ...rementCountFollowersProjectionHandler.php} | 10 ++-- .../DomainModel/Notifier/Notifier.php | 12 +++++ .../Event/AuthorFollowedEventHandler.php | 48 +++++++++++++++++++ 14 files changed, 369 insertions(+), 8 deletions(-) create mode 100644 src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommand.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommandHandler.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommand.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommandHandler.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenIncrementFollowersProjectionEventHandler.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenNotifyAuthorEventHandler.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenCreateEmptyFollowersCounterProjectionEventHandler.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenWelcomeAuthorEventHandler.php create mode 100644 src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjection.php rename src/Cheeper/{Chapter8/Application/Author/Projection/CountFollowersProjectionHandler.php => Chapter7/Application/Author/Projection/IncrementCountFollowersProjectionHandler.php} (50%) create mode 100644 src/Cheeper/Chapter7/DomainModel/Notifier/Notifier.php create mode 100644 src/Cheeper/Chapter8/Application/Author/Event/AuthorFollowedEventHandler.php diff --git a/src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommand.php b/src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommand.php new file mode 100644 index 0000000..00c26e1 --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommand.php @@ -0,0 +1,43 @@ +stampAsNewMessage(); + } + + public function fromAuthorId(): string + { + return $this->fromAuthorId; + } + + public function toAuthorId(): string + { + return $this->toAuthorId; + } + + public function followId(): string + { + return $this->followId; + } + + public static function fromArray(array $array): self + { + return new self( + $array['from_author_id'] ?? '', + $array['to_author_id'] ?? '', + ); + } +} diff --git a/src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommandHandler.php b/src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommandHandler.php new file mode 100644 index 0000000..6cd5102 --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Command/NotifyToAuthorAboutNewFollowerCommandHandler.php @@ -0,0 +1,36 @@ +toAuthorId()); + $author = $this->authors->ofId($authorId); + $this->checkAuthorExist($author, $authorId); + + $this->notifier->notify($author); + } + + private function checkAuthorExist(?Author $author, AuthorId $authorId): void + { + if (null === $author) { + throw AuthorDoesNotExist::withAuthorIdOf($authorId); + } + } +} diff --git a/src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommand.php b/src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommand.php new file mode 100644 index 0000000..d7039d8 --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommand.php @@ -0,0 +1,29 @@ +stampAsNewMessage(); + } + + public static function ofAuthorId(string $authorId): self + { + return new self($authorId); + } + + public function authorId(): string + { + return $this->authorId; + } +} diff --git a/src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommandHandler.php b/src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommandHandler.php new file mode 100644 index 0000000..065a77e --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Command/WelcomeCommandHandler.php @@ -0,0 +1,35 @@ +authorId()); + $author = $this->authors->ofId($authorId); + $this->checkAuthorExist($author, $authorId); + $this->notifier->notify($author); + } + + private function checkAuthorExist(?Author $author, AuthorId $authorId): void + { + if (null === $author) { + throw AuthorDoesNotExist::withAuthorIdOf($authorId); + } + } +} diff --git a/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenIncrementFollowersProjectionEventHandler.php b/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenIncrementFollowersProjectionEventHandler.php new file mode 100644 index 0000000..bdb774c --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenIncrementFollowersProjectionEventHandler.php @@ -0,0 +1,28 @@ +projectionBus->project( + IncrementCountFollowersProjection::ofAuthor( + $event->toAuthorId() + ) + ); + } +} +//end-snippet diff --git a/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenNotifyAuthorEventHandler.php b/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenNotifyAuthorEventHandler.php new file mode 100644 index 0000000..1209f5a --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowed/WhenAuthorFollowedThenNotifyAuthorEventHandler.php @@ -0,0 +1,29 @@ +commandBus->handle( + NotifyToAuthorAboutNewFollowerCommand::fromArray([ + 'from_author_id' => $event->fromAuthorId(), + 'to_author_id' => $event->toAuthorId(), + ]) + ); + } +} +//end-snippet diff --git a/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowedEventHandler.php b/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowedEventHandler.php index bbdcfc5..1621050 100644 --- a/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowedEventHandler.php +++ b/src/Cheeper/Chapter7/Application/Author/Event/AuthorFollowedEventHandler.php @@ -19,8 +19,19 @@ final class AuthorFollowedEventHandler public function __invoke(AuthorFollowed $event): void { $this->projectionHandler->__invoke( - CountFollowersProjection::ofAuthor($event->toAuthorId()) + CountFollowersProjection::ofAuthor( + $event->toAuthorId() + ) ); + + // Other actions, like welcoming the new author, + // can be added here. Alternatively, a more + // scalable design is to create one Event Handler + // for each of the needed actions to happen in + // reaction. All of those listening to the same + // AuthorFollowed Domain Event. + // @see: WhenAuthorFollowedThenCreateFollowersCounterProjectionEventHandler + // @see: WhenAuthorFollowedThenWelcomeAuthorEventHandler } } -//end-snippet +//end-snippet \ No newline at end of file diff --git a/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenCreateEmptyFollowersCounterProjectionEventHandler.php b/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenCreateEmptyFollowersCounterProjectionEventHandler.php new file mode 100644 index 0000000..d8ade4f --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenCreateEmptyFollowersCounterProjectionEventHandler.php @@ -0,0 +1,26 @@ +projectionHandler->__invoke( + CountFollowersProjection::ofAuthor($event->authorId()) + ); + } +} +//end-snippet diff --git a/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenWelcomeAuthorEventHandler.php b/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenWelcomeAuthorEventHandler.php new file mode 100644 index 0000000..8cc7813 --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSigned/WhenNewAuthorSignedThenWelcomeAuthorEventHandler.php @@ -0,0 +1,26 @@ +commandBus->handle( + WelcomeCommand::ofAuthorId($event->authorId()) + ); + } +} +//end-snippet diff --git a/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSignedEventHandler.php b/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSignedEventHandler.php index 234d27e..5c83d87 100644 --- a/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSignedEventHandler.php +++ b/src/Cheeper/Chapter7/Application/Author/Event/NewAuthorSignedEventHandler.php @@ -24,6 +24,15 @@ final class NewAuthorSignedEventHandler $event->authorUsername() ) ); + + // Other actions, like welcoming the new author, + // can be added here. Alternatively, a more + // scalable design is to create one Event Handler + // for each of the needed actions to happen in + // reaction. All of those listening to the same + // NewAuthorSigned Domain Event. + // @see: WhenNewAuthorSignedThenCreateEmptyFollowersCounterProjectionEventHandler + // @see: WhenNewAuthorSignedThenWelcomeAuthorEventHandler } } //end-snippet diff --git a/src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjection.php b/src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjection.php new file mode 100644 index 0000000..21aa94d --- /dev/null +++ b/src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjection.php @@ -0,0 +1,31 @@ +stampAsNewMessage(); + } + + public function authorId(): string + { + return $this->authorId; + } +} +//end-snippet diff --git a/src/Cheeper/Chapter8/Application/Author/Projection/CountFollowersProjectionHandler.php b/src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjectionHandler.php similarity index 50% rename from src/Cheeper/Chapter8/Application/Author/Projection/CountFollowersProjectionHandler.php rename to src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjectionHandler.php index dfc9f57..d591557 100644 --- a/src/Cheeper/Chapter8/Application/Author/Projection/CountFollowersProjectionHandler.php +++ b/src/Cheeper/Chapter7/Application/Author/Projection/IncrementCountFollowersProjectionHandler.php @@ -2,21 +2,19 @@ declare(strict_types=1); -namespace Cheeper\Chapter8\Application\Author\Projection; +namespace Cheeper\Chapter7\Application\Author\Projection; -use Cheeper\Chapter7\Application\Author\Projection\CountFollowersProjection; -use Cheeper\Chapter7\Application\Author\Projection\CreateFollowersCounterProjectionHandler; use Redis; -//snippet projector-count-followers -final class CountFollowersProjectionHandler +//snippet snippet +final class IncrementCountFollowersProjectionHandler { public function __construct( private Redis $redis ) { } - public function __invoke(CountFollowersProjection $projection): void + public function __invoke(IncrementCountFollowersProjection $projection): void { $this->redis->hIncrBy( sprintf( diff --git a/src/Cheeper/Chapter7/DomainModel/Notifier/Notifier.php b/src/Cheeper/Chapter7/DomainModel/Notifier/Notifier.php new file mode 100644 index 0000000..11bcab7 --- /dev/null +++ b/src/Cheeper/Chapter7/DomainModel/Notifier/Notifier.php @@ -0,0 +1,12 @@ +projectionBus->project( + IncrementCountFollowersProjection::ofAuthor( + $event->toAuthorId() + ) + ); + + // Other actions, like notifying the author + // about the new follower can be added here. + // Alternatively, a more scalable design is + // to create one Event Handler for each of + // the needed actions to happen in reaction. + // All of those listening to the same + // AuthorFollowed Domain Event. + // @see: WhenAuthorFollowedThenIncrementFollowersProjectionEventHandler + // @see: WhenAuthorFollowedThenWelcomeAuthorEventHandler + + $this->commandBus->handle( + NotifyToAuthorAboutNewFollowerCommand::fromArray([ + 'from_author_id' => $event->fromAuthorId(), + 'to_author_id' => $event->toAuthorId(), + ]) + ); + } +} +//end-snippet