
— 4 reading minutes
There are many situations in the development of software projects in which you have to manage a workflow, a process, a series of states that a certain entity can go through. Entity, as we say, that something you are modeling can go through. An easy example would be an order in an online store, the order starts in a new state and, if certain conditions are met, it goes to pending payment, paid, shipped, etc. An order is something direct, easy to understand that follows a flow of states, but there are actually many other things that can only be in a series of states and that, naturally, may or may not move from one state to another. A task in a task management system, a course that someone wants to take, etc. In Symfony there is a specific component for process management called Workflow. You can add it to your project with:
composer require symfony/workflow

Diagram showing places as circles, transitions as squares, and arrows between them.
State machines and workflows
How to get started

framework:
workflows:
article_lifecycle:
type: 'state_machine'
marking_store:
type: 'single_state'
arguments:
- 'status'
supports:
- App\Entity\Article
places:
- draft
- review
- published
transitions:
to_review:
from: draft
to: review
publish:
from: review
to: published
unpublish:
from: published
to: review
guards:
to_review:
- "subject.isEditable() === true"
publish:
- "subject.isReviewed() === true"
Events
If you build your workflow with an EventDispatcher, events will be fired in a bunch of situations that the workflow goes through, specifically:
- workflow.guard To validate whether the transition is blocked or not.
- workflow.leave When the object is about to leave a state, or place.
- workflow.transition The object is going through this transition.
- workflow.enter The object is entering a state or place.
- workflow.entered The object has already entered this state or place.
- workflow.completed The object has already completed this transition.
- workflow.announce Fired for each transition currently available for the object.
Since announce can fire a bunch of events, it is common to disable it.
We can also decide which events to fire in the yaml (in case you only want to fire a subset of the events):
# you can pass one or more event names
events_to_dispatch: ['workflow.leave', 'workflow.completed']
Guards
There is a special type of event, and if it is not as an event it can be configured directly in the yaml, as in the example above or directly in each place, which are the guards:
completed:
guard: "subject.hasPaid()"
from: [in_progress]
to: completed