Hello folks! I would like to write a little about one of the essential concepts in Sylius. If you know what it is, you’re probably aware of why it’s so cool. If you don’t, there is no better time to learn it!
The concept itself is neither new nor especially complicated. The state machine (in mathematics usually called finite state machine), is a model that describes the sequential logic of some process. It can be implemented both in software and hardware and represented as a simple graph
https://brilliant.org/wiki/finite-state-machines/
Of course, there are multiple variations of this concept, but the main idea is always the same – a bunch of states between which we can move with strictly specified transitions.
In Sylius, a state machine is a widely used concept. If you’ve ever read some Sylius’ code, you have probably seen it, even if you were not aware of it. Many business processes are modeled with such an approach, starting from the checkout process, ending with the order’s shipment management.
To reach this goal, we use a fabulous WinzouStateMachineBundle, which is an integration layer between Symfony and state machine library, from the same vendor. It’s, of course, not the only library that provides state machine mechanisms for the PHP application (you can check out Symfony/Workflow or Finite).
WinzouStateMachineBundle allows us to use simple YAML configurations, to define even the most complicated processes:
winzou_state_machine:
sylius_order_checkout:
class: "%sylius.model.order.class%"
property_path: checkoutState
graph: sylius_order_checkout
state_machine_class: "%sylius.state_machine.class%"
states:
cart: ~
addressed: ~
shipping_selected: ~
shipping_skipped: ~
payment_skipped: ~
payment_selected: ~
completed: ~
transitions:
address:
from: [cart, addressed, shipping_selected, shipping_skipped, payment_selected, payment_skipped]
to: addressed
skip_shipping:
from: [addressed]
to: shipping_skipped
select_shipping:
from: [addressed, shipping_selected, payment_selected, payment_skipped]
to: shipping_selected
skip_payment:
from: [shipping_selected, shipping_skipped]
to: payment_skipped
select_payment:
from: [payment_selected, shipping_skipped, shipping_selected]
to: payment_selected
complete:
from: [payment_selected, payment_skipped]
to: completed
What is more, it’s also possible to react to the state’s changes, with so-called callbacks. These are Symfony services, which can operate on a transitioned entity and reflect its change in other parts of the application (like sending an email after shipping the shipment).
In fact, we like this concept so much that there is even a unique applyStateMachineTransition action in our basic controller for resources.
What are the benefits of implementing the State Machine concept in an eCommerce application? Here are some of the key arguments in favor of state machine:
Of course, there are some disadvantages as well. Even though YAML configuration is quite easy to read, it’s also hard to maintain (which is the reason why so many developers are not fond of this format). Most of the libraries also require a public setState method, which does not prevent us from unneeded states changes (when the state machine is used, states should always be changed with transitions instead of setters!).
As always, it’s just a pick of an iceberg. Like in any other case, the best way to learn a thing is by writing down a few lines of code 🙂 Also, if you find this topic interesting, you can study Sylius’ source a little bit, to become more familiar with the concept.
Enjoyed this post? If you need more information and guidance, we have launched a pre-sale of our first official online video course. For sure, the state machine usage will be an important part of it. Hope to see you soon!