Splitting Application Event Handlers and Symfony Event Handlers (App vs. Infra)

This commit is contained in:
Carlos Buenosvinos
2022-01-26 19:53:54 +01:00
parent f75559de1d
commit edd36fb596
84 changed files with 225 additions and 192 deletions

View File

@@ -115,6 +115,9 @@ services:
Cheeper\Chapter7\Infrastructure\: Cheeper\Chapter7\Infrastructure\:
resource: '../src/Cheeper/Chapter7/Infrastructure/**/*.php' resource: '../src/Cheeper/Chapter7/Infrastructure/**/*.php'
Cheeper\Chapter7\Application\Event\:
resource: '../src/Cheeper/Chapter7/Application/Event/**/*Handler.php'
Cheeper\Chapter7\Application\Projector\: Cheeper\Chapter7\Application\Projector\:
resource: '../src/Cheeper/Chapter7/Application/Projector/**/*.php' resource: '../src/Cheeper/Chapter7/Application/Projector/**/*.php'
@@ -128,15 +131,15 @@ services:
tags: tags:
- { name: messenger.message_handler, bus: command.bus } - { name: messenger.message_handler, bus: command.bus }
Cheeper\Chapter7\Infrastructure\EventHandler\SymfonyNewAuthorSignedHandler: Cheeper\Chapter7\Infrastructure\Application\Event\Author\SymfonyNewAuthorSignedHandler:
tags: tags:
- { name: messenger.message_handler, bus: event.bus } - { name: messenger.message_handler, bus: event.bus }
class: 'Cheeper\Chapter7\Infrastructure\EventHandler\SymfonyNewAuthorSignedHandler' class: 'Cheeper\Chapter7\Infrastructure\Application\Event\Author\SymfonyNewAuthorSignedHandler'
Cheeper\Chapter7\Infrastructure\EventHandler\SymfonyCheepPostedHandler: Cheeper\Chapter7\Infrastructure\Application\Event\Cheep\SymfonyCheepPostedHandler:
tags: tags:
- { name: messenger.message_handler, bus: event.bus } - { name: messenger.message_handler, bus: event.bus }
class: 'Cheeper\Chapter7\Infrastructure\EventHandler\SymfonyCheepPostedHandler' class: 'Cheeper\Chapter7\Infrastructure\Application\Event\Cheep\SymfonyCheepPostedHandler'
Cheeper\Chapter7\Infrastructure\ProjectionHandler\SymfonyAddCheepToTimelineProjectionHandler: Cheeper\Chapter7\Infrastructure\ProjectionHandler\SymfonyAddCheepToTimelineProjectionHandler:
tags: tags:

Binary file not shown.

View File

@@ -15,4 +15,4 @@ final class Timeline
public ?UuidInterface $id = null; public ?UuidInterface $id = null;
public array $cheeps; public array $cheeps;
} }

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\Command; namespace App\Command;

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\Command; namespace App\Command;

View File

@@ -1,10 +1,10 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\Command; namespace App\Command;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector; use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers; use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Redis; use Redis;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\Command; namespace App\Command;

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\Controller\Chapter2; namespace App\Controller\Chapter2;

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Controller\Chapter4\Commands\Instantiation; namespace App\Controller\Chapter4\Commands\Instantiation;
use Cheeper\Application\Command\Author\SignUp;
use Cheeper\Application\Command\Cheep\PostCheep; use Cheeper\Application\Command\Cheep\PostCheep;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

View File

@@ -23,7 +23,7 @@ final class CountFollowersController extends AbstractController
$httpCode = Response::HTTP_ACCEPTED; $httpCode = Response::HTTP_ACCEPTED;
$httpContent = [ $httpContent = [
'_meta' => [], '_meta' => [],
'data' => [] 'data' => [],
]; ];
try { try {
@@ -45,4 +45,4 @@ final class CountFollowersController extends AbstractController
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -28,7 +28,7 @@ final class FollowAuthorController extends AbstractController
$commandBus->handle($command); $commandBus->handle($command);
$httpContent = [ $httpContent = [
'message_id' => $command->messageId()?->toString() 'message_id' => $command->messageId()?->toString(),
]; ];
} catch ( } catch (
AuthorDoesNotExist $exception AuthorDoesNotExist $exception

View File

@@ -28,7 +28,7 @@ final class GetTimelineController extends AbstractController
Timeline::fromArray([ Timeline::fromArray([
'author_id' => $authorId, 'author_id' => $authorId,
'offset' => $offset, 'offset' => $offset,
'size' => $size 'size' => $size,
]) ])
); );
@@ -40,4 +40,4 @@ final class GetTimelineController extends AbstractController
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -57,4 +57,3 @@ final class SignUpAuthorController extends AbstractController
); );
} }
} }

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\DataFixtures; namespace App\DataFixtures;

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace App\DataFixtures; namespace App\DataFixtures;

View File

@@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace App\Entity; namespace App\Entity;
@@ -211,7 +212,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
/** /**
* @see UserInterface * @see UserInterface
*/ */
public function eraseCredentials() public function eraseCredentials(): void
{ {
// If you store any temporary, sensitive data on the user, clear it here // If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null; // $this->plainPassword = null;

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace App\Messenger; namespace App\Messenger;
use function Functional\first;
use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\MessageBusInterface;
use function Functional\first;
// snippet command-bus // snippet command-bus
final class CommandBus final class CommandBus

View File

@@ -9,16 +9,14 @@ use Cheeper\Application\Command\Cheep\PostCheepHandler;
use Cheeper\Chapter6\Infrastructure\Application\Event\InMemoryEventBus; use Cheeper\Chapter6\Infrastructure\Application\Event\InMemoryEventBus;
use Cheeper\Infrastructure\Persistence\DoctrineOrmAuthors; use Cheeper\Infrastructure\Persistence\DoctrineOrmAuthors;
use Cheeper\Infrastructure\Persistence\DoctrineOrmCheeps; use Cheeper\Infrastructure\Persistence\DoctrineOrmCheeps;
use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\Configuration; use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Messenger\Handler\HandlersLocator; use Symfony\Component\Messenger\Handler\HandlersLocator;
use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
final class FromScratch final class FromScratch
{ {
public function __invoke() public function __invoke(): void
{ {
//snippet symfony-messenger-from-scratch //snippet symfony-messenger-from-scratch
$connection = \Doctrine\DBAL\DriverManager::getConnection([/** ... */]); $connection = \Doctrine\DBAL\DriverManager::getConnection([/** ... */]);

View File

@@ -11,17 +11,14 @@ use Cheeper\Application\Command\Cheep\PostCheepHandler;
use Cheeper\Chapter6\Infrastructure\Application\Event\InMemoryEventBus; use Cheeper\Chapter6\Infrastructure\Application\Event\InMemoryEventBus;
use Cheeper\Infrastructure\Persistence\DoctrineOrmAuthors; use Cheeper\Infrastructure\Persistence\DoctrineOrmAuthors;
use Cheeper\Infrastructure\Persistence\DoctrineOrmCheeps; use Cheeper\Infrastructure\Persistence\DoctrineOrmCheeps;
use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\Configuration; use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Monolog\Logger;
use Symfony\Component\Messenger\Handler\HandlersLocator; use Symfony\Component\Messenger\Handler\HandlersLocator;
use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
final class FromScratchWithCustomMiddleware final class FromScratchWithCustomMiddleware
{ {
public function __invoke() public function __invoke(): void
{ {
//snippet symfony-messenger-from-scratch-with-custom-middleware //snippet symfony-messenger-from-scratch-with-custom-middleware
$connection = \Doctrine\DBAL\DriverManager::getConnection([/** ... */]); $connection = \Doctrine\DBAL\DriverManager::getConnection([/** ... */]);

View File

@@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace App\Repository; namespace App\Repository;
@@ -28,7 +29,7 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{ {
if (!$user instanceof User) { if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user))); throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class));
} }
$user->setPassword($newHashedPassword); $user->setPassword($newHashedPassword);

View File

@@ -7,9 +7,9 @@ namespace Cheeper\AllChapters\Application\Command\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\Authors; use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\AllChapters\DomainModel\Follow\Follow as FollowAggregate;
use Cheeper\AllChapters\DomainModel\Follow\FollowId; use Cheeper\AllChapters\DomainModel\Follow\FollowId;
use Cheeper\AllChapters\DomainModel\Follow\Follows; use Cheeper\AllChapters\DomainModel\Follow\Follows;
use Cheeper\AllChapters\DomainModel\Follow\Follow as FollowAggregate;
final class FollowHandler final class FollowHandler
{ {

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\Application\Command\Author\SignUpWithEvents; namespace Cheeper\AllChapters\Application\Command\Author\SignUpWithEvents;
use Cheeper\AllChapters\Application\Command\Author\SignUp; use Cheeper\AllChapters\Application\Command\Author\SignUp;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\Author\Author; use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorAlreadyExists; use Cheeper\AllChapters\DomainModel\Author\AuthorAlreadyExists;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
@@ -14,6 +13,7 @@ use Cheeper\AllChapters\DomainModel\Author\BirthDate;
use Cheeper\AllChapters\DomainModel\Author\EmailAddress; use Cheeper\AllChapters\DomainModel\Author\EmailAddress;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\AllChapters\DomainModel\Author\Website; use Cheeper\AllChapters\DomainModel\Author\Website;
use Cheeper\Chapter6\Application\Event\EventBus;
//snippet sign-up-handler-with-events //snippet sign-up-handler-with-events
final class SignUpHandler final class SignUpHandler

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\Application\Command\Cheep; namespace Cheeper\AllChapters\Application\Command\Cheep;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\Author\Author; use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
@@ -13,6 +12,7 @@ use Cheeper\AllChapters\DomainModel\Cheep\Cheep;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId; use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\AllChapters\DomainModel\Cheep\CheepMessage; use Cheeper\AllChapters\DomainModel\Cheep\CheepMessage;
use Cheeper\AllChapters\DomainModel\Cheep\Cheeps; use Cheeper\AllChapters\DomainModel\Cheep\Cheeps;
use Cheeper\Chapter6\Application\Event\EventBus;
//snippet post-cheep-handler //snippet post-cheep-handler
final class PostCheepHandler final class PostCheepHandler

View File

@@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
namespace Cheeper\AllChapters\Application\Projection;
use Cheeper\AllChapters\DomainModel\Cheep\CheepPosted;
//snippet cheep-projection-interface
interface CheepProjection
{
public function whenCheepPosted(CheepPosted $event): void;
}
//end-snippet

View File

@@ -6,7 +6,6 @@ namespace Cheeper\AllChapters\DomainModel\Cheep;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\TriggerEventsTrait; use Cheeper\AllChapters\DomainModel\TriggerEventsTrait;
use DateTimeImmutable;
class Cheep class Cheep
{ {

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\DomainModel\Cheep; namespace Cheeper\AllChapters\DomainModel\Cheep;
use Cheeper\AllChapters\DomainModel\Common\ValueObject; use Cheeper\AllChapters\DomainModel\Common\ValueObject;
use InvalidArgumentException;
use DateTimeImmutable; use DateTimeImmutable;
use InvalidArgumentException;
final class CheepDate extends ValueObject final class CheepDate extends ValueObject
{ {

View File

@@ -4,8 +4,6 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\DomainModel\Cheep; namespace Cheeper\AllChapters\DomainModel\Cheep;
use Cheeper\AllChapters\DomainModel\Author\Author;
//snippet cheeps //snippet cheeps
interface Cheeps interface Cheeps
{ {

View File

@@ -43,8 +43,7 @@ class Follow
FollowId $followId, FollowId $followId,
AuthorId $fromAuthorId, AuthorId $fromAuthorId,
AuthorId $toAuthorId, AuthorId $toAuthorId,
): static ): static {
{
return new static( return new static(
followId: $followId, followId: $followId,
fromAuthorId: $fromAuthorId, fromAuthorId: $fromAuthorId,

View File

@@ -26,4 +26,4 @@ trait TriggerEventsTrait
$this->domainEvents = []; $this->domainEvents = [];
} }
} }
// end-snippet // end-snippet

View File

@@ -9,7 +9,6 @@ use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\Authors; use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Ramsey\Uuid\Uuid;
//snippet doctrine-orm-authors //snippet doctrine-orm-authors
final class DoctrineOrmAuthors implements Authors final class DoctrineOrmAuthors implements Authors

View File

@@ -4,8 +4,6 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\Infrastructure\Persistence; namespace Cheeper\AllChapters\Infrastructure\Persistence;
use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Cheep\Cheep; use Cheeper\AllChapters\DomainModel\Cheep\Cheep;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId; use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\AllChapters\DomainModel\Cheep\Cheeps; use Cheeper\AllChapters\DomainModel\Cheep\Cheeps;

View File

@@ -8,8 +8,6 @@ use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Follow\Follow; use Cheeper\AllChapters\DomainModel\Follow\Follow;
use Cheeper\AllChapters\DomainModel\Follow\Follows; use Cheeper\AllChapters\DomainModel\Follow\Follows;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository;
//snippet doctrine-orm-follows //snippet doctrine-orm-follows
final class DoctrineOrmFollows implements Follows final class DoctrineOrmFollows implements Follows

View File

@@ -4,13 +4,9 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\Infrastructure\Persistence; namespace Cheeper\AllChapters\Infrastructure\Persistence;
use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Cheep\Cheep; use Cheeper\AllChapters\DomainModel\Cheep\Cheep;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId; use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\AllChapters\DomainModel\Cheep\Cheeps; use Cheeper\AllChapters\DomainModel\Cheep\Cheeps;
use function Functional\filter;
use function Functional\select;
//snippet inmemory-cheeps //snippet inmemory-cheeps
final class InMemoryCheeps implements Cheeps final class InMemoryCheeps implements Cheeps

View File

@@ -45,9 +45,7 @@ final class InMemoryFollows implements Follows
{ {
return reduce_left( return reduce_left(
$this->collection, $this->collection,
function(Follow $f, string $key, array $collection, int $initial) use($authorId): int { fn (Follow $f, string $key, array $collection, int $initial): int => $initial + ($f->fromAuthorId()->equals($authorId) ? 1 : 0),
return $initial + ($f->fromAuthorId()->equals($authorId) ? 1 : 0);
},
0 0
); );
} }

View File

@@ -8,4 +8,4 @@ use RuntimeException;
final class AuthorNotFound extends RuntimeException final class AuthorNotFound extends RuntimeException
{ {
} }

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace Cheeper\Chapter2\Layered; namespace Cheeper\Chapter2\Layered;
use Cheeper\Chapter2\Author; use Cheeper\Chapter2\Author;
use PDO;
use function mimic\hydrate; use function mimic\hydrate;
use PDO;
//snippet authors //snippet authors
class Authors class Authors

View File

@@ -1,4 +1,5 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace Cheeper\Chapter2\Layered; namespace Cheeper\Chapter2\Layered;

View File

@@ -1,10 +1,11 @@
<?php declare(strict_types=1); <?php
declare(strict_types=1);
namespace Cheeper\Chapter2\Layered; namespace Cheeper\Chapter2\Layered;
use Cheeper\Chapter2\Cheep; use Cheeper\Chapter2\Cheep;
use PDO;
use function mimic\hydrate; use function mimic\hydrate;
use PDO;
//snippet cheeps //snippet cheeps
class Cheeps class Cheeps

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Cheeper\Chapter5\Application\Query\CountFollowersHandlerWithDbAccess; namespace Cheeper\Chapter5\Application\Query\CountFollowersHandlerWithDbAccess;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter5\Application\Query\CountFollowers; use Cheeper\Chapter5\Application\Query\CountFollowers;
use Cheeper\Chapter5\Application\Query\CountFollowersResponse; use Cheeper\Chapter5\Application\Query\CountFollowersResponse;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
//snippet count-followers-handler //snippet count-followers-handler

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Cheeper\Chapter5\Application\Query\CountFollowersHandlerWithRedisAccess; namespace Cheeper\Chapter5\Application\Query\CountFollowersHandlerWithRedisAccess;
use Cheeper\Chapter5\Application\Query\CountFollowers;
use Cheeper\Chapter5\Application\Query\CountFollowersResponse;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter5\Application\Query\CountFollowers;
use Cheeper\Chapter5\Application\Query\CountFollowersResponse;
use Redis; use Redis;
//snippet count-followers-handler //snippet count-followers-handler

View File

@@ -4,12 +4,12 @@ declare(strict_types=1);
namespace Cheeper\Chapter5\Application\Query\CountFollowersHandlerWithRepositoriesAccess; namespace Cheeper\Chapter5\Application\Query\CountFollowersHandlerWithRepositoriesAccess;
use Cheeper\Chapter5\Application\Query\CountFollowers;
use Cheeper\Chapter5\Application\Query\CountFollowersResponse;
use Cheeper\Chapter5\DomainModel\Follow\Followers;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\Authors; use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\Chapter5\Application\Query\CountFollowers;
use Cheeper\Chapter5\Application\Query\CountFollowersResponse;
use Cheeper\Chapter5\DomainModel\Follow\Followers;
//snippet count-followers-handler //snippet count-followers-handler
final class CountFollowersHandler final class CountFollowersHandler
@@ -17,8 +17,7 @@ final class CountFollowersHandler
public function __construct( public function __construct(
private Followers $followers, private Followers $followers,
private Authors $authors private Authors $authors
) ) {
{
} }
public function __invoke(CountFollowers $query): CountFollowersResponse public function __invoke(CountFollowers $query): CountFollowersResponse

View File

@@ -7,7 +7,6 @@ namespace Cheeper\Chapter5\Application\Query;
//snippet count-followers-response //snippet count-followers-response
final class CountFollowersResponse final class CountFollowersResponse
{ {
public function __construct( public function __construct(
private string $authorId, private string $authorId,
private string $authorUsername, private string $authorUsername,

View File

@@ -15,7 +15,6 @@ class NumberOfFollowers
#[ORM\GeneratedValue(strategy: "NONE")] #[ORM\GeneratedValue(strategy: "NONE")]
#[ORM\Id] #[ORM\Id]
private UuidInterface $userId, private UuidInterface $userId,
#[ORM\Column(type: "integer")] #[ORM\Column(type: "integer")]
private int $followers private int $followers
) { ) {

View File

@@ -6,10 +6,10 @@ namespace Cheeper\Chapter5\Infrastructure\Application\Query;
use Cheeper\Chapter5\Application\Query\Query; use Cheeper\Chapter5\Application\Query\Query;
use Cheeper\Chapter5\Application\Query\QueryBus; use Cheeper\Chapter5\Application\Query\QueryBus;
use function Functional\first;
use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\HandleTrait; use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\MessageBusInterface;
use function Functional\first;
//snippet symfony-query-bus //snippet symfony-query-bus
final class SymfonyQueryBus implements QueryBus final class SymfonyQueryBus implements QueryBus

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Cheeper\Chapter5\Infrastructure\Persistence; namespace Cheeper\Chapter5\Infrastructure\Persistence;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter5\DomainModel\Follow\Followers; use Cheeper\Chapter5\DomainModel\Follow\Followers;
use Cheeper\Chapter5\DomainModel\Follow\NumberOfFollowers; use Cheeper\Chapter5\DomainModel\Follow\NumberOfFollowers;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
final class DoctrineOrmFollowers implements Followers final class DoctrineOrmFollowers implements Followers
@@ -20,4 +20,4 @@ final class DoctrineOrmFollowers implements Followers
{ {
return null; return null;
} }
} }

View File

@@ -4,13 +4,13 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Application\Command\Author\WithDomainEvents; namespace Cheeper\Chapter6\Application\Command\Author\WithDomainEvents;
use Cheeper\Chapter6\Application\Command\Author\Follow;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\Author\Author; use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\Authors; use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Follow\Follows; use Cheeper\AllChapters\DomainModel\Follow\Follows;
use Cheeper\Chapter6\Application\Command\Author\Follow;
use Cheeper\Chapter6\Application\Event\EventBus;
//snippet follow-handler-with-event //snippet follow-handler-with-event
final class FollowHandler final class FollowHandler

View File

@@ -4,13 +4,13 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Application\Command\Author\WithIdempotency; namespace Cheeper\Chapter6\Application\Command\Author\WithIdempotency;
use Cheeper\Chapter6\Application\Command\Author\Follow;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\Author\Author; use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\Authors; use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Follow\Follows; use Cheeper\AllChapters\DomainModel\Follow\Follows;
use Cheeper\Chapter6\Application\Command\Author\Follow;
use Cheeper\Chapter6\Application\Event\EventBus;
final class FollowHandler final class FollowHandler
{ {

View File

@@ -4,12 +4,12 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Application\Command\Author\WithoutDomainEvents; namespace Cheeper\Chapter6\Application\Command\Author\WithoutDomainEvents;
use Cheeper\Chapter6\Application\Command\Author\Follow;
use Cheeper\AllChapters\DomainModel\Author\Author; use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist; use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\Authors; use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Follow\Follows; use Cheeper\AllChapters\DomainModel\Follow\Follows;
use Cheeper\Chapter6\Application\Command\Author\Follow;
//snippet follow-handler-without-event //snippet follow-handler-without-event
final class FollowHandler final class FollowHandler

View File

@@ -7,7 +7,6 @@ namespace Cheeper\Chapter6\Application\Projector\Author;
//snippet count-followers //snippet count-followers
final class CountFollowers final class CountFollowers
{ {
public static function ofAuthor(string $authorId): self public static function ofAuthor(string $authorId): self
{ {
return new self($authorId); return new self($authorId);

View File

@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Infrastructure\Application\Event; namespace Cheeper\Chapter6\Infrastructure\Application\Event;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\DomainEvent; use Cheeper\AllChapters\DomainModel\DomainEvent;
use Cheeper\Chapter6\Application\Event\EventBus;
//snippet in-memory-event-bus //snippet in-memory-event-bus
final class InMemoryEventBus implements EventBus final class InMemoryEventBus implements EventBus
@@ -13,8 +13,7 @@ final class InMemoryEventBus implements EventBus
public function __construct( public function __construct(
/** @param DomainEvent[] $events */ /** @param DomainEvent[] $events */
private array $events = [] private array $events = []
) ) {
{
} }
public function events(): array public function events(): array

View File

@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Infrastructure\Application\Event; namespace Cheeper\Chapter6\Infrastructure\Application\Event;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\DomainEvent; use Cheeper\AllChapters\DomainModel\DomainEvent;
use Cheeper\Chapter6\Application\Event\EventBus;
use Symfony\Component\Messenger\HandleTrait; use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\MessageBusInterface;

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author\SagaStyle; namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author\SagaStyle;
use App\Messenger\CommandBus; use App\Messenger\CommandBus;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Cheeper\AllChapters\DomainModel\Follow\AuthorFollowed; use Cheeper\AllChapters\DomainModel\Follow\AuthorFollowed;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-author-followed-handler-in-saga-style //snippet symfony-author-followed-handler-in-saga-style

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author; namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author;
use Cheeper\AllChapters\DomainModel\Follow\AuthorFollowed;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector; use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers; use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Cheeper\AllChapters\DomainModel\Follow\AuthorFollowed;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-author-followed-handler //snippet symfony-author-followed-handler
@@ -32,4 +32,4 @@ final class SymfonyAuthorFollowedHandler implements MessageSubscriberInterface
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author; namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author;
use App\Messenger\CommandBus; use App\Messenger\CommandBus;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Cheeper\AllChapters\DomainModel\Follow\AuthorUnfollowed; use Cheeper\AllChapters\DomainModel\Follow\AuthorUnfollowed;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-author-unfollowed-handler //snippet symfony-author-unfollowed-handler

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author; namespace Cheeper\Chapter6\Infrastructure\Application\Projector\Author;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Cheeper\AllChapters\DomainModel\Follow\AuthorFollowed; use Cheeper\AllChapters\DomainModel\Follow\AuthorFollowed;
use Cheeper\AllChapters\DomainModel\Follow\AuthorUnfollowed; use Cheeper\AllChapters\DomainModel\Follow\AuthorUnfollowed;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-projector-count-followers //snippet symfony-projector-count-followers
@@ -22,7 +22,7 @@ final class SymfonyCountFollowerProjector implements MessageSubscriberInterface
{ {
yield AuthorUnfollowed::class => [ yield AuthorUnfollowed::class => [
'bus' => 'event.bus', 'bus' => 'event.bus',
'method' => 'handleAuthorUnfollowed' 'method' => 'handleAuthorUnfollowed',
]; ];
yield AuthorFollowed::class => [ yield AuthorFollowed::class => [
@@ -56,6 +56,5 @@ final class SymfonyCountFollowerProjector implements MessageSubscriberInterface
CountFollowers::ofAuthor($event->toAuthorId()) CountFollowers::ofAuthor($event->toAuthorId())
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Command\Author; namespace Cheeper\Chapter7\Application\Command\Author;
use Cheeper\Chapter7\Application\MessageTrait;
use Cheeper\AllChapters\DomainModel\Follow\FollowId; use Cheeper\AllChapters\DomainModel\Follow\FollowId;
use Cheeper\Chapter7\Application\MessageTrait;
final class Follow final class Follow
{ {
@@ -47,4 +47,4 @@ final class Follow
$array['to_author_id'] ?? '', $array['to_author_id'] ?? '',
); );
} }
} }

View File

@@ -4,12 +4,12 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Command\Author; namespace Cheeper\Chapter7\Application\Command\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter7\Application\Event\EventBus; use Cheeper\Chapter7\Application\Event\EventBus;
use Cheeper\Chapter7\DomainModel\Author\Author; use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors; use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\Chapter7\DomainModel\Follow\Follows; use Cheeper\Chapter7\DomainModel\Follow\Follows;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
final class FollowHandler final class FollowHandler
{ {
@@ -51,4 +51,4 @@ final class FollowHandler
return $author; return $author;
} }
} }

View File

@@ -4,15 +4,15 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Command\Author; namespace Cheeper\Chapter7\Application\Command\Author;
use Cheeper\Chapter7\Application\Event\EventBus;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Author\AuthorAlreadyExists; use Cheeper\AllChapters\DomainModel\Author\AuthorAlreadyExists;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\BirthDate; use Cheeper\AllChapters\DomainModel\Author\BirthDate;
use Cheeper\AllChapters\DomainModel\Author\EmailAddress; use Cheeper\AllChapters\DomainModel\Author\EmailAddress;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\AllChapters\DomainModel\Author\Website; use Cheeper\AllChapters\DomainModel\Author\Website;
use Cheeper\Chapter7\Application\Event\EventBus;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
//snippet sign-up-handler-with-events //snippet sign-up-handler-with-events
final class SignUpHandler final class SignUpHandler

View File

@@ -4,15 +4,15 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Command\Cheep; namespace Cheeper\Chapter7\Application\Command\Cheep;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\AllChapters\DomainModel\Cheep\CheepMessage;
use Cheeper\Chapter7\Application\Event\EventBus; use Cheeper\Chapter7\Application\Event\EventBus;
use Cheeper\Chapter7\DomainModel\Author\Author; use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors; use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\Chapter7\DomainModel\Cheep\Cheep; use Cheeper\Chapter7\DomainModel\Cheep\Cheep;
use Cheeper\Chapter7\DomainModel\Cheep\Cheeps; use Cheeper\Chapter7\DomainModel\Cheep\Cheeps;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\AllChapters\DomainModel\Cheep\CheepMessage;
//snippet post-cheep-handler //snippet post-cheep-handler
final class PostCheepHandler final class PostCheepHandler

View File

@@ -2,29 +2,20 @@
declare(strict_types=1); declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\EventHandler; namespace Cheeper\Chapter7\Application\Event\Author;
use Cheeper\Chapter7\Application\Projector\Author\CountFollowerProjector; use Cheeper\Chapter7\Application\Projector\Author\CountFollowerProjector;
use Cheeper\Chapter7\Application\Projector\Author\CountFollowersProjection; use Cheeper\Chapter7\Application\Projector\Author\CountFollowersProjection;
use Cheeper\Chapter7\DomainModel\Follow\AuthorFollowed; use Cheeper\Chapter7\DomainModel\Follow\AuthorFollowed;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-author-followed-handler //snippet author-followed-event-handler
final class SymfonyAuthorFollowedHandler implements MessageSubscriberInterface final class AuthorFollowedEventHandler
{ {
public function __construct( public function __construct(
private CountFollowerProjector $projector private CountFollowerProjector $projector
) { ) {
} }
public static function getHandledMessages(): iterable
{
yield AuthorFollowed::class => [
'method' => 'handle',
'from_transport' => 'chapter7_events'
];
}
public function handle(AuthorFollowed $event): void public function handle(AuthorFollowed $event): void
{ {
$this->projector->__invoke( $this->projector->__invoke(
@@ -32,4 +23,4 @@ final class SymfonyAuthorFollowedHandler implements MessageSubscriberInterface
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -2,30 +2,21 @@
declare(strict_types=1); declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\EventHandler; namespace Cheeper\Chapter7\Application\Event\Author;
use Cheeper\Chapter7\Application\Projector\Author\CreateFollowersCounterProjection; use Cheeper\Chapter7\Application\Projector\Author\CreateFollowersCounterProjection;
use Cheeper\Chapter7\Application\Projector\Author\CreateFollowersCounterProjectionProjector; use Cheeper\Chapter7\Application\Projector\Author\CreateFollowersCounterProjectionProjector;
use Cheeper\Chapter7\DomainModel\Author\NewAuthorSigned; use Cheeper\Chapter7\DomainModel\Author\NewAuthorSigned;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-new-author-signed-handler //snippet new-author-signed-event-handler
final class SymfonyNewAuthorSignedHandler implements MessageSubscriberInterface final class NewAuthorSignedEventHandler
{ {
public function __construct( public function __construct(
private CreateFollowersCounterProjectionProjector $projector private CreateFollowersCounterProjectionProjector $projector
) { ) {
} }
public static function getHandledMessages(): iterable public function handle(NewAuthorSigned $event): void
{
yield NewAuthorSigned::class => [
'method' => 'handlerNewAuthorSigned',
'from_transport' => 'chapter7_events'
];
}
public function handlerNewAuthorSigned(NewAuthorSigned $event): void
{ {
$this->projector->__invoke( $this->projector->__invoke(
CreateFollowersCounterProjection::ofAuthor( CreateFollowersCounterProjection::ofAuthor(
@@ -35,4 +26,4 @@ final class SymfonyNewAuthorSignedHandler implements MessageSubscriberInterface
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\EventHandler; namespace Cheeper\Chapter7\Application\Event\Cheep;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter7\Application\Projector\ProjectionBus; use Cheeper\Chapter7\Application\Projector\ProjectionBus;
@@ -11,10 +11,9 @@ use Cheeper\Chapter7\DomainModel\Cheep\CheepPosted;
use Cheeper\Chapter7\DomainModel\Follow\Follows; use Cheeper\Chapter7\DomainModel\Follow\Follows;
use DateTimeImmutable; use DateTimeImmutable;
use DateTimeInterface; use DateTimeInterface;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet cheep-projection-to-redis //snippet cheep-posted-event-handler
final class SymfonyCheepPostedHandler implements MessageSubscriberInterface final class CheepPostedEventHandler
{ {
public function __construct( public function __construct(
private Follows $follows, private Follows $follows,
@@ -22,7 +21,7 @@ final class SymfonyCheepPostedHandler implements MessageSubscriberInterface
) { ) {
} }
public function whenCheepPosted(CheepPosted $event): void public function handle(CheepPosted $event): void
{ {
$follows = $this->follows->toAuthorId( $follows = $this->follows->toAuthorId(
AuthorId::fromString($event->authorId()) AuthorId::fromString($event->authorId())
@@ -34,8 +33,7 @@ final class SymfonyCheepPostedHandler implements MessageSubscriberInterface
authorId: $follow->fromAuthorId()->toString(), authorId: $follow->fromAuthorId()->toString(),
cheepId: $event->cheepId(), cheepId: $event->cheepId(),
cheepMessage: $event->cheepMessage(), cheepMessage: $event->cheepMessage(),
cheepDate: DateTimeImmutable cheepDate: DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $event->cheepDate())
::createFromFormat('Y-m-d H:i:s', $event->cheepDate())
->setTimezone(new \DateTimeZone('UTC')) ->setTimezone(new \DateTimeZone('UTC'))
->format(DateTimeInterface::ATOM), ->format(DateTimeInterface::ATOM),
) )
@@ -55,13 +53,5 @@ final class SymfonyCheepPostedHandler implements MessageSubscriberInterface
// ); // );
} }
} }
public static function getHandledMessages(): iterable
{
yield CheepPosted::class => [
'method' => 'whenCheepPosted',
'from_transport' => 'chapter7_events'
];
}
} }
//end-snippet //end-snippet

View File

@@ -79,4 +79,4 @@ trait MessageTrait
return $this->correlationId; return $this->correlationId;
} }
} }
//end-snippet //end-snippet

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Projector\Author; namespace Cheeper\Chapter7\Application\Projector\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@@ -35,7 +34,7 @@ final class CountFollowerProjector
$projectionResult = [ $projectionResult = [
'id' => $authorId->toString(), 'id' => $authorId->toString(),
'username' => $result['username'], 'username' => $result['username'],
'followers' => 0 'followers' => 0,
]; ];
if (false !== $result) { if (false !== $result) {

View File

@@ -22,7 +22,7 @@ final class CreateFollowersCounterProjectionProjector
$result = [ $result = [
'id' => $projection->authorId(), 'id' => $projection->authorId(),
'username' => $projection->authorUsername(), 'username' => $projection->authorUsername(),
'followers' => 0 'followers' => 0,
]; ];
$this->redis->set( $this->redis->set(

View File

@@ -1,10 +1,11 @@
<?php <?php
declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Projector\Timeline; namespace Cheeper\Chapter7\Application\Projector\Timeline;
use Cheeper\Chapter7\Application\Projector\Projection; use Cheeper\Chapter7\Application\Projector\Projection;
//snippet put-cheep-on-redis-timeline //snippet add-cheep-to-timeline-projection
final class AddCheepToTimelineProjection implements Projection final class AddCheepToTimelineProjection implements Projection
{ {
public function __construct( public function __construct(
@@ -15,4 +16,4 @@ final class AddCheepToTimelineProjection implements Projection
) { ) {
} }
} }
//end-snippet //end-snippet

View File

@@ -1,4 +1,5 @@
<?php <?php
declare(strict_types=1);
namespace Cheeper\Chapter7\Application\Projector\Timeline; namespace Cheeper\Chapter7\Application\Projector\Timeline;

View File

@@ -22,10 +22,10 @@ final class TimelineHandler
return new TimelineResponse( return new TimelineResponse(
array_map( array_map(
static fn(string $cheep): array => json_decode($cheep, true, flags: JSON_THROW_ON_ERROR), static fn (string $cheep): array => json_decode($cheep, true, flags: JSON_THROW_ON_ERROR),
$serializedCheeps $serializedCheeps
) )
); );
} }
} }
//end-snippet //end-snippet

View File

@@ -4,13 +4,13 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\DomainModel\Author; namespace Cheeper\Chapter7\DomainModel\Author;
use Cheeper\Chapter7\DomainModel\Follow\Follow;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\BirthDate; use Cheeper\AllChapters\DomainModel\Author\BirthDate;
use Cheeper\AllChapters\DomainModel\Author\EmailAddress; use Cheeper\AllChapters\DomainModel\Author\EmailAddress;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\AllChapters\DomainModel\Author\Website; use Cheeper\AllChapters\DomainModel\Author\Website;
use Cheeper\AllChapters\DomainModel\Follow\FollowId; use Cheeper\AllChapters\DomainModel\Follow\FollowId;
use Cheeper\Chapter7\DomainModel\Follow\Follow;
use Cheeper\Chapter7\DomainModel\TriggerEventsTrait; use Cheeper\Chapter7\DomainModel\TriggerEventsTrait;
use DateTimeImmutable; use DateTimeImmutable;
use InvalidArgumentException; use InvalidArgumentException;
@@ -142,4 +142,4 @@ final class Author
return $value; return $value;
} }
} }

View File

@@ -44,8 +44,7 @@ final class Follow
FollowId $followId, FollowId $followId,
AuthorId $fromAuthorId, AuthorId $fromAuthorId,
AuthorId $toAuthorId, AuthorId $toAuthorId,
): static ): static {
{
return new static( return new static(
followId: $followId->toString(), followId: $followId->toString(),
fromAuthorId: $fromAuthorId->toString(), fromAuthorId: $fromAuthorId->toString(),
@@ -68,4 +67,4 @@ final class Follow
return FollowId::fromString($this->followId); return FollowId::fromString($this->followId);
} }
} }
// end-snippet // end-snippet

View File

@@ -26,4 +26,4 @@ trait TriggerEventsTrait
$this->domainEvents = []; $this->domainEvents = [];
} }
} }
// end-snippet // end-snippet

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Application\Event\Author;
use Cheeper\Chapter7\Application\Event\Author\AuthorFollowedEventHandler;
use Cheeper\Chapter7\DomainModel\Follow\AuthorFollowed;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-author-followed-event-handler
final class SymfonyAuthorFollowedHandler implements MessageSubscriberInterface
{
public function __construct(
private AuthorFollowedEventHandler $eventHandler
) {
}
public function handle(AuthorFollowed $event): void
{
$this->eventHandler->handle($event);
}
public static function getHandledMessages(): iterable
{
yield AuthorFollowed::class => [
'method' => 'handle',
'from_transport' => 'chapter7_events',
];
}
}
//end-snippet

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Application\Event\Author;
use Cheeper\Chapter7\Application\Event\Author\NewAuthorSignedEventHandler;
use Cheeper\Chapter7\DomainModel\Author\NewAuthorSigned;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-new-author-signed-event-handler
final class SymfonyNewAuthorSignedHandler implements MessageSubscriberInterface
{
public function __construct(
private NewAuthorSignedEventHandler $eventHandler
) {
}
public function handle(NewAuthorSigned $event): void
{
$this->eventHandler->handle($event);
}
public static function getHandledMessages(): iterable
{
yield NewAuthorSigned::class => [
'method' => 'handle',
'from_transport' => 'chapter7_events',
];
}
}
//end-snippet

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Application\Event\Cheep;
use Cheeper\Chapter7\Application\Event\Cheep\CheepPostedEventHandler;
use Cheeper\Chapter7\DomainModel\Cheep\CheepPosted;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-cheep-posted-event-handler
final class SymfonyCheepPostedHandler implements MessageSubscriberInterface
{
public function __construct(
private CheepPostedEventHandler $eventHandler
) {
}
public function handle(CheepPosted $event): void
{
$this->eventHandler->handle($event);
}
public static function getHandledMessages(): iterable
{
yield CheepPosted::class => [
'method' => 'handle',
'from_transport' => 'chapter7_events',
];
}
}
//end-snippet

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Application\Event; namespace Cheeper\Chapter7\Infrastructure\Application\Event;
//snippet in-memory-event-bus //snippet in-memory-event-bus
use Cheeper\Chapter7\Application\Event\EventBus; use Cheeper\Chapter7\Application\Event\EventBus;
use Cheeper\Chapter7\DomainModel\DomainEvent; use Cheeper\Chapter7\DomainModel\DomainEvent;
@@ -14,8 +13,7 @@ final class InMemoryEventBus implements EventBus
public function __construct( public function __construct(
/** @param DomainEvent[] $events */ /** @param DomainEvent[] $events */
private array $events = [] private array $events = []
) ) {
{
} }
public function events(): array public function events(): array

View File

@@ -6,10 +6,10 @@ namespace Cheeper\Chapter7\Infrastructure\Application\Projector;
use Cheeper\Chapter7\Application\Projector\Projection; use Cheeper\Chapter7\Application\Projector\Projection;
use Cheeper\Chapter7\Application\Projector\ProjectionBus; use Cheeper\Chapter7\Application\Projector\ProjectionBus;
use function Functional\first;
use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\HandleTrait; use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\MessageBusInterface;
use function Functional\first;
//snippet symfony-projection-bus //snippet symfony-projection-bus
final class SymfonyProjectionBus implements ProjectionBus final class SymfonyProjectionBus implements ProjectionBus

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Persistence; namespace Cheeper\Chapter7\Infrastructure\Persistence;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
//snippet doctrine-orm-authors //snippet doctrine-orm-authors

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Persistence; namespace Cheeper\Chapter7\Infrastructure\Persistence;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\Chapter7\DomainModel\Cheep\Cheep; use Cheeper\Chapter7\DomainModel\Cheep\Cheep;
use Cheeper\Chapter7\DomainModel\Cheep\Cheeps; use Cheeper\Chapter7\DomainModel\Cheep\Cheeps;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;

View File

@@ -4,12 +4,10 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Persistence; namespace Cheeper\Chapter7\Infrastructure\Persistence;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter7\DomainModel\Follow\Follow; use Cheeper\Chapter7\DomainModel\Follow\Follow;
use Cheeper\Chapter7\DomainModel\Follow\Follows; use Cheeper\Chapter7\DomainModel\Follow\Follows;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository;
//snippet doctrine-orm-follows //snippet doctrine-orm-follows
final class DoctrineOrmFollows implements Follows final class DoctrineOrmFollows implements Follows

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Persistence; namespace Cheeper\Chapter7\Infrastructure\Persistence;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\UserName; use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use function Functional\head; use function Functional\head;
use function Functional\select; use function Functional\select;

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Persistence; namespace Cheeper\Chapter7\Infrastructure\Persistence;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
use Cheeper\Chapter7\DomainModel\Cheep\Cheep; use Cheeper\Chapter7\DomainModel\Cheep\Cheep;
use Cheeper\Chapter7\DomainModel\Cheep\Cheeps; use Cheeper\Chapter7\DomainModel\Cheep\Cheeps;
use Cheeper\AllChapters\DomainModel\Cheep\CheepId;
//snippet inmemory-cheeps //snippet inmemory-cheeps
final class InMemoryCheeps implements Cheeps final class InMemoryCheeps implements Cheeps

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
namespace Cheeper\Chapter7\Infrastructure\Persistence; namespace Cheeper\Chapter7\Infrastructure\Persistence;
use Cheeper\Chapter7\DomainModel\Follow\Follow;
use Cheeper\Chapter7\DomainModel\Follow\Follows;
use Cheeper\AllChapters\DomainModel\Author\AuthorId; use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Follow\FollowId; use Cheeper\AllChapters\DomainModel\Follow\FollowId;
use Cheeper\Chapter7\DomainModel\Follow\Follow;
use Cheeper\Chapter7\DomainModel\Follow\Follows;
use function Functional\head; use function Functional\head;
use function Functional\reduce_left; use function Functional\reduce_left;
use function Functional\select; use function Functional\select;
@@ -45,9 +45,7 @@ final class InMemoryFollows implements Follows
{ {
return reduce_left( return reduce_left(
$this->collection, $this->collection,
function(Follow $f, string $key, array $collection, int $initial) use($authorId): int { fn (Follow $f, string $key, array $collection, int $initial): int => $initial + ($f->fromAuthorId()->equals($authorId) ? 1 : 0),
return $initial + ($f->fromAuthorId()->equals($authorId) ? 1 : 0);
},
0 0
); );
} }

View File

@@ -8,7 +8,7 @@ use Cheeper\Chapter7\Application\Projector\Timeline\AddCheepToTimelineProjection
use Cheeper\Chapter7\Application\Projector\Timeline\AddCheepToTimelineProjector; use Cheeper\Chapter7\Application\Projector\Timeline\AddCheepToTimelineProjector;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet cheep-projection-to-redis //snippet add-cheep-to-one-timeline
final class SymfonyAddCheepToTimelineProjectionHandler implements MessageSubscriberInterface final class SymfonyAddCheepToTimelineProjectionHandler implements MessageSubscriberInterface
{ {
public function __construct( public function __construct(
@@ -25,8 +25,8 @@ final class SymfonyAddCheepToTimelineProjectionHandler implements MessageSubscri
{ {
yield AddCheepToTimelineProjection::class => [ yield AddCheepToTimelineProjection::class => [
'method' => 'handle', 'method' => 'handle',
'from_transport' => 'chapter7_async_projections' 'from_transport' => 'chapter7_async_projections',
]; ];
} }
} }
//end-snippet //end-snippet