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\:
resource: '../src/Cheeper/Chapter7/Infrastructure/**/*.php'
Cheeper\Chapter7\Application\Event\:
resource: '../src/Cheeper/Chapter7/Application/Event/**/*Handler.php'
Cheeper\Chapter7\Application\Projector\:
resource: '../src/Cheeper/Chapter7/Application/Projector/**/*.php'
@@ -128,15 +131,15 @@ services:
tags:
- { name: messenger.message_handler, bus: command.bus }
Cheeper\Chapter7\Infrastructure\EventHandler\SymfonyNewAuthorSignedHandler:
Cheeper\Chapter7\Infrastructure\Application\Event\Author\SymfonyNewAuthorSignedHandler:
tags:
- { 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:
- { 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:
tags:

Binary file not shown.

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
<?php declare(strict_types=1);
<?php
declare(strict_types=1);
namespace App\Command;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowerProjector;
use Cheeper\Chapter6\Application\Projector\Author\CountFollowers;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Redis;
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;

View File

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

View File

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

View File

@@ -23,7 +23,7 @@ final class CountFollowersController extends AbstractController
$httpCode = Response::HTTP_ACCEPTED;
$httpContent = [
'_meta' => [],
'data' => []
'data' => [],
];
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);
$httpContent = [
'message_id' => $command->messageId()?->toString()
'message_id' => $command->messageId()?->toString(),
];
} catch (
AuthorDoesNotExist $exception

View File

@@ -28,7 +28,7 @@ final class GetTimelineController extends AbstractController
Timeline::fromArray([
'author_id' => $authorId,
'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;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace App\Repository;
@@ -28,7 +29,7 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
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);

View File

@@ -7,9 +7,9 @@ namespace Cheeper\AllChapters\Application\Command\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\Authors;
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\Follows;
use Cheeper\AllChapters\DomainModel\Follow\Follow as FollowAggregate;
final class FollowHandler
{

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\Application\Command\Author\SignUpWithEvents;
use Cheeper\AllChapters\Application\Command\Author\SignUp;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorAlreadyExists;
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\UserName;
use Cheeper\AllChapters\DomainModel\Author\Website;
use Cheeper\Chapter6\Application\Event\EventBus;
//snippet sign-up-handler-with-events
final class SignUpHandler

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Cheeper\AllChapters\Application\Command\Cheep;
use Cheeper\Chapter6\Application\Event\EventBus;
use Cheeper\AllChapters\DomainModel\Author\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
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\CheepMessage;
use Cheeper\AllChapters\DomainModel\Cheep\Cheeps;
use Cheeper\Chapter6\Application\Event\EventBus;
//snippet post-cheep-handler
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\TriggerEventsTrait;
use DateTimeImmutable;
class Cheep
{

View File

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

View File

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

View File

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

View File

@@ -26,4 +26,4 @@ trait TriggerEventsTrait
$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\UserName;
use Doctrine\ORM\EntityManagerInterface;
use Ramsey\Uuid\Uuid;
//snippet doctrine-orm-authors
final class DoctrineOrmAuthors implements Authors

View File

@@ -4,8 +4,6 @@ declare(strict_types=1);
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\CheepId;
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\Follows;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository;
//snippet doctrine-orm-follows
final class DoctrineOrmFollows implements Follows

View File

@@ -4,13 +4,9 @@ declare(strict_types=1);
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\CheepId;
use Cheeper\AllChapters\DomainModel\Cheep\Cheeps;
use function Functional\filter;
use function Functional\select;
//snippet inmemory-cheeps
final class InMemoryCheeps implements Cheeps

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
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\AuthorId;
use Cheeper\Chapter5\Application\Query\CountFollowers;
use Cheeper\Chapter5\Application\Query\CountFollowersResponse;
use Redis;
//snippet count-followers-handler

View File

@@ -4,12 +4,12 @@ declare(strict_types=1);
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\AuthorId;
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
final class CountFollowersHandler
@@ -17,8 +17,7 @@ final class CountFollowersHandler
public function __construct(
private Followers $followers,
private Authors $authors
)
{
) {
}
public function __invoke(CountFollowers $query): CountFollowersResponse

View File

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

View File

@@ -15,7 +15,6 @@ class NumberOfFollowers
#[ORM\GeneratedValue(strategy: "NONE")]
#[ORM\Id]
private UuidInterface $userId,
#[ORM\Column(type: "integer")]
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\QueryBus;
use function Functional\first;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface;
use function Functional\first;
//snippet symfony-query-bus
final class SymfonyQueryBus implements QueryBus

View File

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

View File

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

View File

@@ -4,13 +4,13 @@ declare(strict_types=1);
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\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\Authors;
use Cheeper\AllChapters\DomainModel\Follow\Follows;
use Cheeper\Chapter6\Application\Command\Author\Follow;
use Cheeper\Chapter6\Application\Event\EventBus;
final class FollowHandler
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,12 +4,12 @@ declare(strict_types=1);
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\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\Chapter7\DomainModel\Follow\Follows;
use Cheeper\AllChapters\DomainModel\Author\AuthorDoesNotExist;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
final class FollowHandler
{
@@ -51,4 +51,4 @@ final class FollowHandler
return $author;
}
}
}

View File

@@ -4,15 +4,15 @@ declare(strict_types=1);
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\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\BirthDate;
use Cheeper\AllChapters\DomainModel\Author\EmailAddress;
use Cheeper\AllChapters\DomainModel\Author\UserName;
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
final class SignUpHandler

View File

@@ -4,15 +4,15 @@ declare(strict_types=1);
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\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Cheeper\Chapter7\DomainModel\Cheep\Cheep;
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
final class PostCheepHandler

View File

@@ -2,29 +2,20 @@
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\CountFollowersProjection;
use Cheeper\Chapter7\DomainModel\Follow\AuthorFollowed;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-author-followed-handler
final class SymfonyAuthorFollowedHandler implements MessageSubscriberInterface
//snippet author-followed-event-handler
final class AuthorFollowedEventHandler
{
public function __construct(
private CountFollowerProjector $projector
) {
}
public static function getHandledMessages(): iterable
{
yield AuthorFollowed::class => [
'method' => 'handle',
'from_transport' => 'chapter7_events'
];
}
public function handle(AuthorFollowed $event): void
{
$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);
namespace Cheeper\Chapter7\Infrastructure\EventHandler;
namespace Cheeper\Chapter7\Application\Event\Author;
use Cheeper\Chapter7\Application\Projector\Author\CreateFollowersCounterProjection;
use Cheeper\Chapter7\Application\Projector\Author\CreateFollowersCounterProjectionProjector;
use Cheeper\Chapter7\DomainModel\Author\NewAuthorSigned;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet symfony-new-author-signed-handler
final class SymfonyNewAuthorSignedHandler implements MessageSubscriberInterface
//snippet new-author-signed-event-handler
final class NewAuthorSignedEventHandler
{
public function __construct(
private CreateFollowersCounterProjectionProjector $projector
) {
}
public static function getHandledMessages(): iterable
{
yield NewAuthorSigned::class => [
'method' => 'handlerNewAuthorSigned',
'from_transport' => 'chapter7_events'
];
}
public function handlerNewAuthorSigned(NewAuthorSigned $event): void
public function handle(NewAuthorSigned $event): void
{
$this->projector->__invoke(
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);
namespace Cheeper\Chapter7\Infrastructure\EventHandler;
namespace Cheeper\Chapter7\Application\Event\Cheep;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\Chapter7\Application\Projector\ProjectionBus;
@@ -11,10 +11,9 @@ use Cheeper\Chapter7\DomainModel\Cheep\CheepPosted;
use Cheeper\Chapter7\DomainModel\Follow\Follows;
use DateTimeImmutable;
use DateTimeInterface;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
//snippet cheep-projection-to-redis
final class SymfonyCheepPostedHandler implements MessageSubscriberInterface
//snippet cheep-posted-event-handler
final class CheepPostedEventHandler
{
public function __construct(
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(
AuthorId::fromString($event->authorId())
@@ -34,8 +33,7 @@ final class SymfonyCheepPostedHandler implements MessageSubscriberInterface
authorId: $follow->fromAuthorId()->toString(),
cheepId: $event->cheepId(),
cheepMessage: $event->cheepMessage(),
cheepDate: DateTimeImmutable
::createFromFormat('Y-m-d H:i:s', $event->cheepDate())
cheepDate: DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $event->cheepDate())
->setTimezone(new \DateTimeZone('UTC'))
->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;
}
}
//end-snippet
//end-snippet

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,10 +22,10 @@ final class TimelineHandler
return new TimelineResponse(
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
)
);
}
}
//end-snippet
//end-snippet

View File

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

View File

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

View File

@@ -26,4 +26,4 @@ trait TriggerEventsTrait
$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;
//snippet in-memory-event-bus
use Cheeper\Chapter7\Application\Event\EventBus;
use Cheeper\Chapter7\DomainModel\DomainEvent;
@@ -14,8 +13,7 @@ final class InMemoryEventBus implements EventBus
public function __construct(
/** @param DomainEvent[] $events */
private array $events = []
)
{
) {
}
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\ProjectionBus;
use function Functional\first;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\HandleTrait;
use Symfony\Component\Messenger\MessageBusInterface;
use function Functional\first;
//snippet symfony-projection-bus
final class SymfonyProjectionBus implements ProjectionBus

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
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\UserName;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use Doctrine\ORM\EntityManagerInterface;
//snippet doctrine-orm-authors

View File

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

View File

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

View File

@@ -4,10 +4,10 @@ declare(strict_types=1);
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\UserName;
use Cheeper\Chapter7\DomainModel\Author\Author;
use Cheeper\Chapter7\DomainModel\Author\Authors;
use function Functional\head;
use function Functional\select;

View File

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

View File

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

View File

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