Event Sourcing
Event Sourcing PHP
Ecotone comes with Prooph Event Store integration. This is well known and stable solution providing event storage over databases like Postgres, MySQL or MariaDB. Ecotone provides Event Sourced Aggregates, which are stored as series of events. Thanks to that we will be able to have the whole history of what happened with specific Aggregate. And build up projections, that targets specific view, in order to keep our code simple, even with really complicated queries. This divide Commands from Queries (CQRS).
Do you want to find out, how to apply Event Sourcing in your business? Try out InspectIO!

Installation

1
composer require ecotone/pdo-event-sourcing
Copied!
And go to DBAL Support in order to configure the connection.
Ecotone Event Sourcing is based on well known and stable Prooph's Event Store. It does provide support for three databases: - PostgreSQL - MySQL - MariaDB

Storing Events in streams using Aggregates

There are two ways, we can make use of Event Sourced Aggregates.

Pure Event Sourced Aggregate

This way of handling events does allow for pure functions. Writes are clearly separated from writes.
1
#[EventSourcingAggregate] // 1
2
class Ticket
3
{
4
use WithAggregateVersioning; // 2
5
6
#[AggregateIdentifier] // 1
7
private string $ticketId;
8
private string $ticketType;
9
10
#[CommandHandler] // 2
11
public static function register(RegisterTicket $command) : array
12
{
13
return [new TicketWasRegistered($command->getTicketId(), $command->getTicketType())];
14
}
15
16
#[CommandHandler] // 2
17
public function close(CloseTicket $command) : array
18
{
19
return [new TicketWasClosed($this->ticketId)];
20
}
21
22
#[EventSourcingHandler] // 4
23
public function applyTicketWasRegistered(TicketWasRegistered $event) : void
24
{
25
$this->ticketId = $event->getTicketId();
26
$this->ticketType = $event->getTicketType();
27
}
28
}
Copied!
  1. 1.
    EventSourcingAggregate and AggregateIdentifier works exactly the same as State-Stored Aggregate.
  2. 2.
    Event Sourced Aggregate must provide version. You may leave it to Ecotone using WithAggregateVersioning or you can implement it yourself.
  3. 3.
    CommandHandlerfor event sourcing returns events generated by specific method. This will be passed to the Repository to be stored.
  4. 4.
    EventSourcingHandler is method responsible for reconstructing Aggregate from previously created events. At least one event need to be handled in order to provide AggregateIdentifier.

Internal Recorder Aggregate

This way of handling events allow for similarity with State Stored Aggregates.
1
#[EventSourcingAggregate(true)] // 1
2
class Basket
3
{
4
use WithAggregateEvents;
5
use WithAggregateVersioning;
6
7
#[AggregateIdentifier]
8
private string $id;
9
10
#[CommandHandler] // 2
11
public static function create(CreateBasket $command) : static
12
{
13
$basket = new static();
14
$basket->recordThat(new BasketWasCreated($command->getId()));
15
16
return $basket;
17
}
18
19
#[CommandHandler] // 2
20
public function addProduct(AddProduct $command) : void
21
{
22
$this->recordThat(new ProductWasAddedToBasket($this->id, $command->getProductName()));
23
}
24
25
#[EventSourcingHandler]
26
public function applyBasketWasCreated(BasketWasCreated $basketWasCreated)
27
{
28
$this->id = $basketWasCreated->getId();
29
}
30
}
Copied!
  1. 1.
    In order to make use of alternative way of handling events, we need to set attribute to trueEventSourcingAggregate(true)
  2. 2.
    Command Handlers instead of returning events are acting the same as State Stored Aggregates. All events which will be published using recordThatwill be passed to the Repository to be stored.