Symfony Workflow component (1/3)

--

With the release of Symfony 3.2 a new workflow component was added that implemented a workflow net or a state machine. This component helps to separate the business workflow logic from other application logic and can help to visualize the workflow and mark the current state it is in.

This blog post is part 1 of a small series on the workflow component:

Creditcard application workflow
  1. Introduction to the workflow component (this blog post)
  2. Scheduled transitions using a job scheduler, for example to send reminders.
  3. Improve the configuration, testability and visualize the workflow

For this introduction we’ll use a creditcard application usecase as example. The applicant will need to confirm the applications emailaddress, the application needs to be verified and a new creditcard needs to be created.

For the workflow component to work we need to configure a workflow definition, a marking store and a subject. A workflow definition consists of places (states), transitions between the places and guards that conditionally block transitions.

The marking store

The marking store keeps track of the place where the subject (in this case the creditcard application) is inside the workflow. By default the marking store will manipulate the ‘marking’ property on your subject. If we have a creditcard application $application in the place start and apply the transition confirm_email the marking store would set the $application->marking property to email_confirmed.

By default the marking store will manipulate the ‘marking’ property on your subject, but you can change this by supplying an arguments property to the marking_store configuration. In the following example we change the property name to ‘state’.

The marking store will only manipulate the property, but will not take care of any persistence. If we implemented a service persisting_marking_store with our own implementation of the MarkingStoreInterface we could configure it using the service configuration property.

For an example of a persisting marking store see the OrmPersistentMarkingStore in the GTT workflow-extension-bundle.

Multiple-state workflow

When the workflow supports parallel processes the subject can be in multiple places at once and we’ll need to configure the MultipleStateMarkingStore.

Multiple-state workflow

But in our example we’ll use a state machine which always has a single place/state.

The type names for marking stores were changed:
- property_accessor -> multiple_state
- scalar -> single_state
You might still see examples with the old configuration names.

When your workflow type is state_machine a multiple_state marking store is valid but doesn’t add any extra functionality as a state machine has only a single state.

Initiate workflow

To get a hold of a specific workflow you can use the following service name syntax: $container->get('workflow.' . $workflowName), or when you use a state machine: $container->get('state_machine' . $workflowName). Keep in mind that while the service name differs between a normal workflow and a statemachine the prefix workflow for event names in both cases.

Apply workflow transition

You can apply a transition using $workflow->apply('confirm_email', $subject). For our example application we implement a controller that would confirm the emailaddress using a link containing a unique hash

Transition events

Applying a transition will dispatch the following sequence of events:

  1. Guard the transition
    workflow[.<workflow_name>].guard[.<transition_name>]
    The guard event is used the apply conditions to a transition and can block the transition.
  2. Leave the from place
    workflow[.<workflow_name>].leave[.<from_place_name>]
  3. Transition
    workflow[.<workflow_name>].transition[.<transition_name>]
    This event can be used to apply an action on this transition such as sending an email.
  4. Enter the to place
    workflow[.<workflow_name>].enter[.<to_place_name>]
  5. Entered the to place (Only ≥ Symfony 3.3)
    workflow[.<workflow_name>].entered[.<to_place_name>]
    This is the same as the enter event but now the marking store is updated.
  6. Announce new applicable transitions
    workflow[.<workflow_name>].transition[.<transition_name>]
    Listener to this event if you want to automatically apply a transition.

Listen for a transition

Using the generated workflow events we could listen for the confirm_email transition event and send an email when the user confirms his creditcard application.

Guard a workflow transition

To conditionally guard a workflow transition the application can listen for guard events. If any of the guard listeners set $guardEvent->setBlocked(true) the transition will not be available.

In the creditcard example we can require an additional approved credit limit when the user requests a creditcard with a limit above $ 200. We implement a Guard listener that listens for the workflow.creditcard_application_flow.guard.create_card event:

In Symfony 3.3+ you will also be able to define the guards using an expression in the workflow definition:

What’s next?

In part 2 of this serie we’ll have a look at how you can schedule transitions and hook transitions to application events. We’ll build a reminder transtion that ‘ll be applied if the user hasn’t confirmed its creditcard application in 3 days.

References

--

--

Jool Software Professionals
Jool Software Professionals

We are explorers in the world of web technology. We ♥ to share our discoveries with the community. https://jool.nl