Fixes for CI & some code updates

This commit is contained in:
theUniC
2022-04-10 19:19:24 +02:00
parent 8521d0ee75
commit 8596fd1f40
10 changed files with 84 additions and 178 deletions

View File

@@ -28,7 +28,7 @@ services:
- ./:/var/www/html
async-commands-consumer:
build: .docker/php-cli
profiles: ["async-commands"]
profiles: [ "async-commands" ]
init: true
env_file: .env.docker.dist
working_dir: /var/www/html
@@ -37,7 +37,7 @@ services:
- ./:/var/www/html
async-events-consumer:
build: .docker/php-cli
profiles: ["async-events"]
profiles: [ "async-events" ]
init: true
env_file: .env.docker.dist
working_dir: /var/www/html
@@ -46,7 +46,7 @@ services:
- ./:/var/www/html
async-projections-consumer:
build: .docker/php-cli
profiles: ["async-projections"]
profiles: [ "async-projections" ]
init: true
env_file: .env.docker.dist
working_dir: /var/www/html

View File

@@ -10,8 +10,8 @@ use Cheeper\AllChapters\DomainModel\Author\UserName;
//snippet authors
interface AuthorRepository
{
public function ofId(AuthorId $authorId): ?Author;
public function ofUserName(UserName $userName): ?Author;
public function ofId(AuthorId $authorId): Author|null;
public function ofUserName(UserName $userName): Author|null;
public function add(Author $author): void;
}
//end-snippet

View File

@@ -18,7 +18,7 @@ final class DoctrineOrmAuthorRepository implements AuthorRepository
) {
}
public function ofId(AuthorId $authorId): ?Author
public function ofId(AuthorId $authorId): Author|null
{
return $this->em
->getRepository(Author::class)
@@ -27,7 +27,7 @@ final class DoctrineOrmAuthorRepository implements AuthorRepository
]);
}
public function ofUserName(UserName $userName): ?Author
public function ofUserName(UserName $userName): Author|null
{
return $this->em
->getRepository(Author::class)

View File

@@ -20,20 +20,20 @@ final class InMemoryAuthorRepository implements AuthorRepository
$this->authors = [];
}
public function ofId(AuthorId $authorId): ?Author
public function ofId(AuthorId $authorId): Author|null
{
$candidate = head(
select($this->authors, fn (Author $u): bool => $u->authorId()->equals($authorId))
);
if (null === $candidate) {
return $candidate;
return null;
}
return $candidate;
}
public function ofUserName(UserName $userName): ?Author
public function ofUserName(UserName $userName): Author|null
{
$candidate = head(
select($this->authors, fn (Author $u): bool => $u->userName()->equalsTo($userName))

View File

@@ -45,10 +45,10 @@ final class Author
?string $location = null,
?Website $website = null,
?BirthDate $birthDate = null
): static {
): self {
// Regular semantic constructors
// still apply as a proper design
$obj = new static();
$obj = new self();
$obj->authorId = $authorId->toString();
$obj->userName = $userName->userName();
@@ -67,6 +67,11 @@ final class Author
return $obj;
}
public function authorId(): string
{
return $this->authorId;
}
public function changeEmail(EmailAddress $newEmail)
{
$this->recordApplyAndPublishThat(

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Cheeper\Chapter9\DomainModel\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\UserName;
interface AuthorRepository
{
public function ofId(AuthorId $authorId): Author|null;
public function ofUserName(UserName $userName): Author|null;
public function add(Author $author): void;
}

View File

@@ -8,18 +8,13 @@ use Cheeper\Chapter7\DomainModel\DomainEvent;
class EventStream implements \Iterator
{
private string $aggregateId;
/** @var DomainEvent[] */
private array $events;
/**
* @param string $aggregateId
* @param DomainEvent[] $events
*/
public function __construct(string $aggregateId, array $events)
{
$this->aggregateId = $aggregateId;
$this->events = $events;
public function __construct(
private string $aggregateId,
private array $events
) {
}
public function getAggregateId(): string
@@ -51,4 +46,9 @@ class EventStream implements \Iterator
{
return key($this->events) !== null;
}
public function isEmpty(): bool
{
return count($this->events) === 0;
}
}

View File

@@ -1,116 +0,0 @@
<?php
declare(strict_types=1);
namespace Cheeper\Chapter9\DomainModel;
//snippet post
class Post extends AggregateRoot
{
//ignore
private PostId $id;
private ?string $title = null;
private ?string $content = null;
private bool $published = false;
private array $categories = [];
protected function __construct(PostId $id)
{
$this->id = $id;
}
public function id(): PostId
{
return $this->id;
}
public function title(): ?string
{
return $this->title;
}
public function content(): ?string
{
return $this->content;
}
public function categories(): array
{
return array_values($this->categories);
}
public function isPublished(): bool
{
return $this->published === true;
}
//end-ignore
public static function writeNewFrom(string $title, string $content): self
{
$postId = PostId::create();
$post = new static($postId);
$post->recordApplyAndPublishThat(
new PostWasCreated($postId, $title, $content)
);
return $post;
}
public function publish(): void
{
$this->recordApplyAndPublishThat(
new PostWasPublished($this->id)
);
}
public function categorizeIn(CategoryId $categoryId): void
{
$this->recordApplyAndPublishThat(
new PostWasCategorized($this->id, $categoryId)
);
}
public function changeContentFor(string $newContent): void
{
$this->recordApplyAndPublishThat(
new PostContentWasChanged($this->id, $newContent)
);
}
public function changeTitleFor(string $newTitle): void
{
$this->recordApplyAndPublishThat(
new PostTitleWasChanged($this->id, $newTitle)
);
}
protected function applyPostWasCreated(PostWasCreated $event): void
{
$this->id = $event->postId();
$this->title = $event->title();
$this->content = $event->content();
}
protected function applyPostWasPublished(PostWasPublished $event): void
{
$this->published = true;
}
protected function applyPostWasCategorized(PostWasCategorized $event): void
{
$this->categories[$event->categoryId()->id()] = $event->categoryId();
}
protected function applyPostContentWasChanged(PostContentWasChanged $event): void
{
$this->content = $event->content();
}
protected function applyPostTitleWasChanged(PostTitleWasChanged $event): void
{
$this->title = $event->title();
}
}
//end-snippet

View File

@@ -6,26 +6,28 @@ namespace Cheeper\Chapter9\Infrastructure\DomainModel\Author;
use Cheeper\AllChapters\DomainModel\Author\AuthorId;
use Cheeper\AllChapters\DomainModel\Author\UserName;
use Cheeper\Chapter7\DomainModel\Author\AuthorRepository;
use Cheeper\Chapter9\DomainModel\Author\AuthorRepository;
use Cheeper\Chapter9\DomainModel\Author\Author;
use Cheeper\Chapter9\DomainModel\EventStore;
use Cheeper\Chapter9\DomainModel\EventStream;
//snippet code
class EventSourcedAuthorRepository implements AuthorRepository
final class EventSourcedAuthorRepository implements AuthorRepository
{
private EventStore $eventStore;
public function __construct(EventStore $eventStore)
{
$this->eventStore = $eventStore;
public function __construct(
private EventStore $eventStore
) {
}
public function ofId(AuthorId $authorId): Author
public function ofId(AuthorId $authorId): Author|null
{
return Author::reconstitute(
$this->eventStore->getEventsFor($authorId->id())
);
$eventStream = $this->eventStore->getEventsFor($authorId->id());
if ($eventStream->isEmpty()) {
return null;
}
return Author::reconstitute($eventStream);
}
public function ofUserName(UserName $userName): ?Author
@@ -37,9 +39,9 @@ class EventSourcedAuthorRepository implements AuthorRepository
public function add(Author $author): void
{
$this->eventStore->append(
newEventStream:: $author->domainEvents()
);
$eventStream = new EventStream($author->authorId(), $author->domainEvents());
$this->eventStore->append($eventStream);
}
}
//end-snippet

View File

@@ -11,37 +11,23 @@ use Redis;
use Symfony\Component\Serializer\Serializer;
//snippet code
class RedisEventStore implements EventStore
final class RedisEventStore implements EventStore
{
private Redis $redis;
private Serializer $serializer;
public function __construct(
Redis $redis,
Serializer $serializer
)
{
$this->redis = $redis;
$this->serializer = $serializer;
private Redis $redis,
private Serializer $serializer,
) {
}
public function append(EventStream $eventStream): void
{
/** @var DomainEvent */
foreach ($eventStream as $event) {
$data = $this->serializer->serialize($event, 'json');
$date = (new \DateTimeImmutable())->format('YmdHis');
$serializedEvent = $this->serialize($event);
$this->redis->rpush(
'events:' . $eventStream->getAggregateId(),
$this->serializer->serialize([
'type' => get_class($event),
'created_on' => $date,
'data' => $data
],
'json'
)
$this->serializer->serialize($serializedEvent, 'json')
);
}
}
@@ -59,20 +45,34 @@ class RedisEventStore implements EventStore
-1
);
/** @var DomainEvent[] */
$events = [];
/** @var string */
foreach ($serializedEvents as $serializedEvent) {
$event = (array) $this->serializer->deserialize($serializedEvent);
$eventData = (string) $event['data'];
/** @var DomainEvent */
$events[] = $this->serializer->deserialize($eventData);
$events[] = $this->deserialize($serializedEvent);
}
return new EventStream($id, $events);
}
//ignore
private function deserialize(array $event): DomainEvent
{
return $this->serializer->deserialize(
$event['data'],
$event['type'],
'json'
);
}
private function serialize(mixed $event): array
{
return [
'type' => get_class($event),
'created_on' => (new \DateTimeImmutable())->format('YmdHis'),
'data' => $this->serializer->serialize($event, 'json')
];
}
//end-ignore
}
//end-snippet