Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
A SHORT TALE
ABOUT
STATE MACHINE
Albert
Once upon a time…
final class Payment
{
/** @var bool */
private $pending = false;
}
A few days later
final class Payment
{
/** @var bool */
private $pending = false;
/** @var bool */
private $failed = false;
}
final class Payment
{
/** @var bool */
private $pending = false;
/** @var bool */
private $failed = false;
}
final class Payment
{
public const NEW = 1;
public const PENDING = 1;
public const FAILED = 2;
/** @var int */
private $st...
State Machine
(Q, Σ, δ, q0, F)
Q = a finite set of states
Σ = a finite, nonempty input alphabet
δ = a series of transition functions
q0 = ...
NEW
PENDING
FAILED PAID
Create
PayFail
Libraries
What can we do with it?
Define possible states and relation between them
Protect business rules (with guards)
Trigger other...
WinzouStateMachine
Callback’s execution in config file
Used heavily in Sylius
Configurable arguments of service
Services have to be public in or...
winzou_state_machine:
payment:
class: AppModelPayment
property_path: state
graph: payment
states:
new: ~
pending: ~
failed...
winzou_state_machine:
payment:
class: AppModelPayment
property_path: state
graph: payment
states:
new: ~
pending: ~
failed...
winzou_state_machine:
payment:
class: AppModelPayment
property_path: state
graph: payment
states:
new: ~
pending: ~
failed...
winzou_state_machine:
payment:
class: AppModelPayment
property_path: state
graph: payment
states:
new: ~
pending: ~
failed...
Symfony Workflow
Maintained by Symfony
Flex support
Workflow & state machine support
Execution of external services with events
XML / YAML /...
framework:
workflows:
payment:
type: 'state_machine'
supports:
- AppModelPayment
initial_marking: new
marking_store:
type:...
framework:
workflows:
payment:
type: 'state_machine'
supports:
- AppModelPayment
initial_marking: new
marking_store:
type:...
framework:
workflows:
payment:
type: 'state_machine'
supports:
- AppModelPayment
initial_marking: new
marking_store:
type:...
framework:
workflows:
payment:
type: 'state_machine'
supports:
- AppModelPayment
initial_marking: new
marking_store:
type:...
Finite
Oldest and most popular implementation (in terms of stars)
Extendability with events & callbacks definition
It is said to b...
New adventures
Symfony Workflow
final class PaymentPaidListener
{
public function __invoke(EnterEvent $event): void
{
$payment = $event->getSubject();
// ...
Actions
workflow.[type]
workflow.[workflow name].[type]
workflow.[workflow name].[type].[transition name]
Types for transitions
guard
transition
completed
announce
Actions
workflow.[type]
workflow.[workflow name].[type]
workflow.[workflow name].[type].[place name]
Types for places
leave
enter
entered
WinzouStateMachine
AppOperatorInventoryOperator:
public: true
final class InventoryOperator
{
public function __invoke(Payment $payment): voi...
Callbacks types
Before
After
Guard
Callbacks types
On -> transition
From -> state
To -> state
Symfony Workflow
#1
final class BlockedGuardListener
{
public function __invoke(GuardEvent $event): void
{
$event->setBlocked(true);
}
}
AppEv...
#2
framework:
workflows:
payment:
...
transitions:
...
block:
guard: "is_granted('ROLE_ADMIN')"
from: pending
to: blocked
symfony/security-core
WinzouStateMachine
AppAuthorizerBlockedAuthorizer:
public: true
final class BlockAuthorizer
{
public function __invoke(): bool
{
return false...
😭
Final boss
final class AfterPaymentPaidListener
{
public function __invoke(EnteredEvent $event): void
{
/** @var Payment $payment */
...
But when do you flush?
final class InformAboutPaidPayment
{...}
final class InformAboutPaidPaymentHandler implements MessageHandlerInterface
{
pu...
Summary
Define possible states and relation between them
Protect business rules (with guards)
Trigger other services on transitions...
Common issues
Business logic wired up in configuration files
Describe problem with state machine
but implement directly in code
Possibility to destroy state of entities
if state machine is omitted
setState(…)
Informing external system on transition callback
Sending emails or dispatching messages
on transition callbacks is not the best idea.
Defer external calls and ensure prope...
https://github.com/lchrusciel/StateMachine
@lukaszchrusciel
Thank you!
https://github.com/lchrusciel/StateMachine
@lukaszchrusciel
Q & A
https://github.com/lchrusciel/StateMachine
@lukaszchrusciel
Thank you!
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
A short tale about state machine
Upcoming SlideShare
Loading in …5
×

A short tale about state machine

136 views

Published on

State machine is a powerful concept. How can it be used in php? What is the difference between libraries?

Published in: Software
  • Be the first to comment

  • Be the first to like this

A short tale about state machine

  1. 1. A SHORT TALE ABOUT STATE MACHINE
  2. 2. Albert
  3. 3. Once upon a time…
  4. 4. final class Payment { /** @var bool */ private $pending = false; }
  5. 5. A few days later
  6. 6. final class Payment { /** @var bool */ private $pending = false; /** @var bool */ private $failed = false; }
  7. 7. final class Payment { /** @var bool */ private $pending = false; /** @var bool */ private $failed = false; }
  8. 8. final class Payment { public const NEW = 1; public const PENDING = 1; public const FAILED = 2; /** @var int */ private $state = self::NEW; } ?
  9. 9. State Machine
  10. 10. (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
  11. 11. NEW PENDING FAILED PAID Create PayFail
  12. 12. Libraries
  13. 13. What can we do with it? Define possible states and relation between them Protect business rules (with guards) Trigger other services on transitions
  14. 14. WinzouStateMachine
  15. 15. 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
  16. 16. winzou_state_machine: payment: class: AppModelPayment property_path: state graph: payment states: new: ~ pending: ~ failed: ~ paid: ~ transitions: process: from: [new] to: pending fail: from: [pending] to: failed pay: from: [pending] to: paid
  17. 17. winzou_state_machine: payment: class: AppModelPayment property_path: state graph: payment states: new: ~ pending: ~ failed: ~ paid: ~ transitions: process: from: [new] to: pending fail: from: [pending] to: failed pay: from: [pending] to: paid
  18. 18. winzou_state_machine: payment: class: AppModelPayment property_path: state graph: payment states: new: ~ pending: ~ failed: ~ paid: ~ transitions: process: from: [new] to: pending fail: from: [pending] to: failed pay: from: [pending] to: paid
  19. 19. winzou_state_machine: payment: class: AppModelPayment property_path: state graph: payment states: new: ~ pending: ~ failed: ~ paid: ~ transitions: process: from: [new] to: pending fail: from: [pending] to: failed pay: from: [pending] to: paid
  20. 20. Symfony Workflow
  21. 21. Maintained by Symfony Flex support Workflow & state machine support Execution of external services with events XML / YAML / PHP support out-of-the-box
  22. 22. framework: workflows: payment: type: 'state_machine' supports: - AppModelPayment initial_marking: new marking_store: type: method property: state places: - new - pending - failed - paid transitions: process: from: new to: pending fail: from: pending to: failed paying: from: pending to: paid
  23. 23. framework: workflows: payment: type: 'state_machine' supports: - AppModelPayment initial_marking: new marking_store: type: method property: state places: - new - pending - failed - paid transitions: process: from: new to: pending fail: from: pending to: failed paying: from: pending to: paid
  24. 24. framework: workflows: payment: type: 'state_machine' supports: - AppModelPayment initial_marking: new marking_store: type: method property: state places: - new - pending - failed - paid transitions: process: from: new to: pending fail: from: pending to: failed paying: from: pending to: paid
  25. 25. framework: workflows: payment: type: 'state_machine' supports: - AppModelPayment initial_marking: new marking_store: type: method property: state places: - new - pending - failed - paid transitions: process: from: new to: pending fail: from: pending to: failed paying: from: pending to: paid
  26. 26. Finite
  27. 27. 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
  28. 28. New adventures
  29. 29. Symfony Workflow
  30. 30. final class PaymentPaidListener { public function __invoke(EnterEvent $event): void { $payment = $event->getSubject(); // Reduce inventory of bought products } } AppEventListenerPaymentPaidListener: tags: - name: kernel.event_listener event: workflow.payment.enter.paid method: __invoke
  31. 31. Actions workflow.[type] workflow.[workflow name].[type] workflow.[workflow name].[type].[transition name]
  32. 32. Types for transitions guard transition completed announce
  33. 33. Actions workflow.[type] workflow.[workflow name].[type] workflow.[workflow name].[type].[place name]
  34. 34. Types for places leave enter entered
  35. 35. WinzouStateMachine
  36. 36. 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
  37. 37. Callbacks types Before After Guard
  38. 38. Callbacks types On -> transition From -> state To -> state
  39. 39. Symfony Workflow
  40. 40. #1
  41. 41. final class BlockedGuardListener { public function __invoke(GuardEvent $event): void { $event->setBlocked(true); } } AppEventListenerBlockedGuardListener: tags: - name: kernel.event_listener event: workflow.payment.guard.block method: __invoke
  42. 42. #2
  43. 43. framework: workflows: payment: ... transitions: ... block: guard: "is_granted('ROLE_ADMIN')" from: pending to: blocked
  44. 44. symfony/security-core
  45. 45. WinzouStateMachine
  46. 46. AppAuthorizerBlockedAuthorizer: public: true final class BlockAuthorizer { public function __invoke(): bool { return false; } } winzou_state_machine: payment: ... callbacks: guard: guard-blocked: to: ["blocked"] do: ["@AppAuthorizerBlockedAuthorizer", "__invoke"]
  47. 47. 😭
  48. 48. Final boss
  49. 49. final class AfterPaymentPaidListener { public function __invoke(EnteredEvent $event): void { /** @var Payment $payment */ $payment = $event->getSubject(); file_get_contents( 'https://workflow.free.beeceptor.com?state=' . $payment->getState() ); } } AppEventListenerAfterPaymentPaidListener: tags: - name: kernel.event_listener event: workflow.payment.entered.paid method: __invoke
  50. 50. But when do you flush?
  51. 51. 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
  52. 52. Summary
  53. 53. Define possible states and relation between them Protect business rules (with guards) Trigger other services on transitions Trigger other state changes as a reaction
  54. 54. Common issues
  55. 55. Business logic wired up in configuration files
  56. 56. Describe problem with state machine but implement directly in code
  57. 57. Possibility to destroy state of entities if state machine is omitted
  58. 58. setState(…)
  59. 59. Informing external system on transition callback
  60. 60. Sending emails or dispatching messages on transition callbacks is not the best idea. Defer external calls and ensure proper state.
  61. 61. https://github.com/lchrusciel/StateMachine @lukaszchrusciel Thank you!
  62. 62. https://github.com/lchrusciel/StateMachine @lukaszchrusciel Q & A
  63. 63. https://github.com/lchrusciel/StateMachine @lukaszchrusciel Thank you!

×