Skip to content

Instantly share code, notes, and snippets.

@pwm
Created March 14, 2019 09:52
Show Gist options
  • Save pwm/58e96d080e1482141bb0b550165efd14 to your computer and use it in GitHub Desktop.
Save pwm/58e96d080e1482141bb0b550165efd14 to your computer and use it in GitHub Desktop.
S-Flow - Event sourcing example
<?php
declare(strict_types=1);
final class Order
{
/** @var Event */
private $events;
/** @var State */
private $state;
public function __construct(Events $events)
{
$this->events = $events;
$this->state = $this->buildState($events);
}
public function getEvents(): Events
{
return $this->events;
}
public function getState(): State
{
return $this->state;
}
private function buildState(Events $events): State
{
$transitionOp = $this->fsm()->run(new S\NoItems, $events);
if ($transitionOp->isSuccess() === false) {
throw new RuntimeException(
sprintf(
'Invalid transition: from %s via %s',
$transitionOp->getState()::name()->unWrap(),
$transitionOp->getLastEvent()::name()->unWrap()
)
);
}
return $transitionOp->getState();
}
private function fsm(): FSM
{
$labels = [
S\NoItems::name(),
S\HasItems::name(),
S\NoCard::name(),
S\CardSelected::name(),
S\CardConfirmed::name(),
S\OrderPlaced::name(),
];
$arrows = [
(new Arrow(E\Select::name()))->from(S\NoItems::name())->via(new T\AddFirstItem),
(new Arrow(E\Select::name()))->from(S\HasItems::name())->via(new T\AddItem),
(new Arrow(E\Checkout::name()))->from(S\HasItems::name())->via(new T\DoCheckout),
(new Arrow(E\SelectCard::name()))->from(S\NoCard::name())->via(new T\DoSelectCard),
(new Arrow(E\Confirm::name()))->from(S\CardSelected::name())->via(new T\ConfirmCard),
(new Arrow(E\PlaceOrder::name()))->from(S\CardConfirmed::name())->via(new T\DoPlaceOrder),
(new Arrow(E\Cancel::name()))->from(S\NoCard::name())->via(new T\DoCancel),
(new Arrow(E\Cancel::name()))->from(S\CardSelected::name())->via(new T\DoCancel),
(new Arrow(E\Cancel::name()))->from(S\CardConfirmed::name())->via(new T\DoCancel),
];
return new FSM((new Graph(...$labels))->drawArrows(...$arrows));
}
}
<?php
declare(strict_types=1);
// Get the events (eg. from the DB)
$events = new Events(
new E\Select(new Item('foo')),
new E\Select(new Item('bar')),
new E\Select(new Item('baz')),
new E\Checkout,
new E\SelectCard(new Card('Visa', '1234567812345678')),
new E\Confirm,
new E\PlaceOrder
);
// Build the entity
$order = new Order($events);
\assert($order->getState() instanceof S\OrderPlaced); // true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment