New in Symfony 4.3: Workflow improvements

Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.

In Symfony 4.3 we improved the Workflow component with lots of major and minor features. This blog post summarizes the most important ones.

Added a context to Workflow::apply()

Contributed by
Grégoire Pineau
in #29146.

When applying a transition, now it's possible to pass a custom $context (e.g. the user who performed the transition or the current date):

1
2
3
$workflow->apply($article, $request->request->get('transition'), [
    'time' => date('y-m-d H:i:s'),
]);

Before using this feature, update your entity or any other object supported by the workflow as follows:

1
2
3
4
 class Article
 {
-    public function setMarking($marking)
+    public function setMarking($marking, $context = [])

Then, update the configuration of the workflow to use the MethodMarkingStore:

1
2
3
4
5
6
7
 framework:
     workflows:
         article:
             type: workflow
             marking_store:
-                 type: multiple_state
+                 type: method

Allow to modify the context in a listener

Contributed by
Grégoire Pineau
in #30902.

Passing the context on every call to ->apply() could be annoying and will lead to duplicated code.

Now you can create a listener that does that for you:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class TransitionEventSubscriber implements EventSubscriberInterface
{
    private $tokenStorage;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    public function onWorkflowArticleTransition(TransitionEvent $event)
    {
        $context = $event->getContext();

        $token = $this->tokenStorage->getToken();
        if ($token instanceof TokenInterface) {
            $user = $token->getUser();
            if ($user instanceof UserInterface) {
                $context['user'] = $user->getUsername();
            }
        }

        $event->setContext($context);
    }

    public static function getSubscribedEvents()
    {
        return [
           TransitionEvent::class => 'onWorkflowArticleTransition',
        ];
    }
}

Added color to dumped workflow

Contributed by
Alexis Lefebvre
in #29538.

It's now possible to configure how a workflow will be rendered thanks to the dump_style metadata config option:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
transitions:
    submit:
        from: start
        to: travis
        metadata:
            title: transition submit title
            dump_style:
                label: 'My custom label'
                arrow_color: '#0088FF'
                label_color: 'Red'

And this is how the custom style would look like:

Allow to configure many initial places

Contributed by
Grégoire Pineau
in #30468 and #30890.

Unlike state machines, when using a workflow it's possible to have a subject in many places. That's why the component now allows to configure multiple initial places:

1
2
3
4
5
workflows:
    article:
        type: workflow
        initial_marking: [foo, bar]
        places: [foo, bar, a, b, c, d]

Simpler configuration

Contributed by
Grégoire Pineau
in #30551 and #30890.

As mentioned above, subjects can only be in one place in state machines but they can be in one or more states when using a workflow. However, the initial design of the Workflow component allowed to use a workflow with a Single State Marking Store. This wasn't the best decision and it added some unnecessary complexity.

Starting from Symfony 4.3, if your subject can be only in one state, use a state machine. In that case, the property (called marking by default) will be a string. If the subject can be in many places, use a workflow. In that case, the property will be an array.

Thanks to this simplification, we've improved the DX (developer experience):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
framework:
    workflows:
        article:
            type: workflow
            marking_store:
                type: method # This will be the default value in Symfony 5.0
                property: marking # This is the default value, it could be omitted
        task:
            type: state_machine
            marking_store:
                type: method # This will be the default value in Symfony 5.0
                property: state

Added workflow_transition_blockers() Twig function

Contributed by
Grégoire Pineau
in #30908.

In Symfony 4.1 we added a feature to know why a transition is blocked.

In Symfony 4.3 we're adding a Twig function to build the blocker list:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<h2>Publication was blocked because:</h2>
<ul>
    {% for blocker in workflow_transition_blockers(article, 'publish') %}
        <li>
            {{ blocker.message }}
            {# Display the guard expression #}
            {% if blocker.parameters.expression is defined %}
                <code>{{ blocker.parameters.expression }}</code>
            {% endif %}
        </li>
    {% endfor %}
<ul>
Help the Symfony project!

As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.

Comments

Wow! So many improvements! 👍
Very appreciated :)
woww terrible !
GG !
Can't wait to use these improvments :)
I love workflow so much! This is a nice improvement! :)
Thanks for workflow improvements! I'll use these in my project.

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.