The document describes state machines and their use in modeling application workflows and business processes. State machines define a set of states, transitions between states, and rules governing the transitions. They allow enforcing business logic by validating transitions and triggering actions on transitions. The document discusses several PHP libraries for implementing state machines, including WinzouStateMachine, Symfony Workflow, and Finite. It provides examples of using callbacks and guards to add validation and trigger external services during state transitions. In summary, state machines help define and enforce business rules by modeling the valid states and transitions of an entity.
15. @lukaszchrusciel
(Q, Σ, δ, q0, F)
Q = a finite set of states
Σ = a finite, nonempty input alphabet
δ = a series of transition functions
q0 = the starting state
F = the set of accepting states
18. @lukaszchrusciel
What can we do with it?
Define possible states and relation between them
Protect business rules (with guards)
Trigger other services on transitions
20. @lukaszchrusciel
Callback’s execution in config file
Used heavily in Sylius
Configurable arguments of service
Services have to be public in order to make it work
Lack of documentation
Not stable
32. @lukaszchrusciel
Oldest and most popular implementation (in terms of stars)
Extendability with events & callbacks definition
It is said to be little bit heavier implementation compared to
Winzou
33. final class Payment
{
public const NEW = 'new';
/** @var string */
private $state = self::NEW;
public function getState(): string
{
return $this->state;
}
public function setState(string $state): void
{
$this->state = $state
}
}
35. final class SomeService
{
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
public function doStuff(): void
{
$stateMachine = $this->factory->get($payment, 'payment');
$stateMachine->apply('process');
$stateMachine->apply(‘fail');
}
}
37. final class SomeService
{
public function __construct(Registry $workflows)
{
$this->workflows = $workflows;
}
public function doStuff(): void
{
$stateMachine = $this->workflows->get($payment, 'payment');
$stateMachine->apply($payment, 'process');
$stateMachine->apply($payment, ‘fail');
}
}
43. AppOperatorInventoryOperator:
public: true
final class InventoryOperator
{
public function __invoke(Payment $payment): void
{
// Reduce inventory of bought products
}
}
winzou_state_machine:
payment:
…
callbacks:
before:
reduce_amount:
on: ["pay"]
do: [“@AppOperatorInventoryOperator”, "__invoke"]
args: [“object"] # <- Expression language can be used
44. AppOperatorInventoryOperator:
public: true
final class InventoryOperator
{
public function __invoke(Payment $payment): void
{
// Reduce inventory of bought products
}
}
winzou_state_machine:
payment:
…
callbacks:
before:
reduce_amount:
on: ["pay"]
do: [“@AppOperatorInventoryOperator”, "__invoke"]
args: [“object"] # <- Expression language can be used
46. AppOperatorInventoryOperator:
public: true
final class InventoryOperator
{
public function __invoke(Payment $payment): void
{
// Reduce inventory of bought products
}
}
winzou_state_machine:
payment:
…
callbacks:
before:
reduce_amount:
on: ["pay"]
do: [“@AppOperatorInventoryOperator”, "__invoke"]
args: [“object"] # <- Expression language can be used
72. final class InformAboutPaidPayment
{...}
final class InformAboutPaidPaymentHandler implements MessageHandlerInterface
{
public function __invoke(InformAboutPaidPayment $payment)
{
// Check if it should be dispatched
file_get_contents(
‘https://workflow.free.beeceptor.com?state='. $payment->getSubject()
);
}
}
MESSENGER_TRANSPORT_DSN=doctrine://default
75. @lukaszchrusciel
Define possible states and relation between them
Protect business rules (with guards)
Trigger other services on transitions
Ease to add new possible transitions
Trigger other state changes as a reaction