CQRS AND EVENT SOURCING BASICS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Alexander Miertsch
Founder and CEO of prooph software GmbH
Founder and core contributor prooph components
contact@prooph.de
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
prooph components
CQRS and Event Sourcing packages for PHP
Supported Web Frameworks
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3276444/ZendFramework-logo.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3276447/laravel-text-logo.png)
or any other framework/codebase supporting container-interop & interop-config
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Problem Space
Complex
Distributed
Chaotic
When to use CQRS & ES ?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Messages
Semantics of Messaging
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Types: Command, Query, Event
Immutable DTOs
Unique names according to Domain Language
Command
Imperative Messages
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Represent sender's intention
Instruct receiver to perform action
Never return data
Query
Interrogatory Messages
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Ask system about it's current state
Do NOT cause stage changes
Can be cached
Domain Events
Informational Message
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Named in past tense
Communicate facts that have happened
Relevant to the business
Event Storming
Deeper insights with events
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Event Flow
record, publish, react
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
OrderPlaced
OrderPaid
OrderShipped
Change State, Then Publish
ORM - Publisher
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
<?php
final class OrderService
{
private $entityManager;
private $orderRepositoy;
private $eventPublisher;
public function placeOrder(string $orderId, OrderItem ...$items): void
{
$order = $this->orderRepostoy->get($orderId);
$this->entityManager->beginTransaction();
try {
$order->place($items);
$this->entityManager->commit();
} catch(\Throwable $error) {
$this->entityManager->rollBack();
throw $error;
}
$event = OrderPlaced::fromOrder($order);
$this->eventPublisher->publish($event);
}
}
Record Event, Then Publish
Event Store - Publisher
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
<?php
final class PlaceOrderHandler
{
private $eventStore;
private $eventPublisher;
public function handle(PlaceOrder $command): void
{
//Note: Loading/saving is normally done by event sourcing repository
$orderStream = new StreamName('order-'.$command->orderId());
$history = $this->eventStore->load($orderStream);
$order = Order::reconstituteFromHistory($history);
$newEvents = $order->place($command->items());
//Atomic operation
$this->eventStore->appendTo($orderStream, $newEvents);
$this->eventPublisher->publish($newEvents);
}
}
Event Sourcing
State is a left fold of past events
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
# E1 at t1: UserRegistered
userId: 1
name: John Doe
email: doe@fake.com
# E2 at t2: UsernameChanged
userId: 1
oldName: John Doe
newName: Alex
# E3 at t3: EmailChanged
userId: 1
oldEmail: doe@fake.com
newEmail: contact@prooph.de
_______________________________________________
# current state (t:now) = ((E1 + E2) + E3):
userId: 1
name: Alex
email: contact@prooph.de
version: 3
Time Travel
Debug like a boss
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
UserRegistered
UsernameChanged
ChangeEmailFailed
{
E1 + E2
Change Email
Temporal Queries
Use time interval as query param
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
UserRegistered
UsernameChanged
5 min
7 min
Who has changed username within 5 min after registration?
UserRegistered
UsernameChanged
Event Sourcing in PHP
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
prooph components
CQRS
SRP on system level
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Gateway
Write Model
Read Model
CQRS and Event Sourcing
Double Team
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
Gateway
Write Model
Read Model
Event Store
Projection
Cache
Event Driven Microservices
React on Events
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
E1
E2
E3
E4
E5
Event Log
Document DB
Message Queue
Process Manager
Search Service
Services
subscribe
consume
CQRS in PHP
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
prooph components
Just Try It
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/4251874/prooph_do_sf.png)
Join prooph
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3932683/getprooph.png)
Event Sourcing Tutorial
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/3275592/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/619076/images/4263864/tutorial_lumen_theme.png)
Thanks for listening
Questions?
PHP UG Munich 2018 CQRS and ES Basics
By prooph
PHP UG Munich 2018 CQRS and ES Basics
- 1,352