Skip to content

Commit c328657

Browse files
committed
Merge branch '3.4' into 4.2
* 3.4: [Workflow] Guard documentation
2 parents 5fabac8 + 6fbe8d4 commit c328657

File tree

1 file changed

+62
-20
lines changed

1 file changed

+62
-20
lines changed

workflow/usage.rst

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ A set of places and transitions creates a **definition**. A workflow needs
2727
a ``Definition`` and a way to write the states to the objects (i.e. an
2828
instance of a :class:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface`.)
2929

30-
Consider the following example for a blog post that can have these places:
31-
``draft``, ``review``, ``rejected``, ``published``. You can define the workflow
30+
Consider the following example for a blog post. A post can have these places:
31+
``draft``, ``reviewed``, ``rejected``, ``published``. You can define the workflow
3232
like this:
3333

3434
.. configuration-block::
@@ -51,18 +51,18 @@ like this:
5151
initial_place: draft
5252
places:
5353
- draft
54-
- review
54+
- reviewed
5555
- rejected
5656
- published
5757
transitions:
5858
to_review:
5959
from: draft
60-
to: review
60+
to: reviewed
6161
publish:
62-
from: review
62+
from: reviewed
6363
to: published
6464
reject:
65-
from: review
65+
from: reviewed
6666
to: rejected
6767
6868
.. code-block:: xml
@@ -87,24 +87,24 @@ like this:
8787
<framework:support>App\Entity\BlogPost</framework:support>
8888
8989
<framework:place>draft</framework:place>
90-
<framework:place>review</framework:place>
90+
<framework:place>reviewed</framework:place>
9191
<framework:place>rejected</framework:place>
9292
<framework:place>published</framework:place>
9393
9494
<framework:transition name="to_review">
9595
<framework:from>draft</framework:from>
9696
97-
<framework:to>review</framework:to>
97+
<framework:to>reviewed</framework:to>
9898
</framework:transition>
9999
100100
<framework:transition name="publish">
101-
<framework:from>review</framework:from>
101+
<framework:from>reviewed</framework:from>
102102
103103
<framework:to>published</framework:to>
104104
</framework:transition>
105105
106106
<framework:transition name="reject">
107-
<framework:from>review</framework:from>
107+
<framework:from>reviewed</framework:from>
108108
109109
<framework:to>rejected</framework:to>
110110
</framework:transition>
@@ -132,21 +132,21 @@ like this:
132132
'supports' => ['App\Entity\BlogPost'],
133133
'places' => [
134134
'draft',
135-
'review',
135+
'reviewed',
136136
'rejected',
137137
'published',
138138
],
139139
'transitions' => [
140140
'to_review' => [
141141
'from' => 'draft',
142-
'to' => 'review',
142+
'to' => 'reviewed',
143143
],
144144
'publish' => [
145-
'from' => 'review',
145+
'from' => 'reviewed',
146146
'to' => 'published',
147147
],
148148
'reject' => [
149-
'from' => 'review',
149+
'from' => 'reviewed',
150150
'to' => 'rejected',
151151
],
152152
],
@@ -244,7 +244,9 @@ When a state transition is initiated, the events are dispatched in the following
244244
order:
245245

246246
``workflow.guard``
247-
Validate whether the transition is allowed at all (:ref:`see below <workflow-usage-guard-events>`).
247+
Validate whether the transition is blocked or not (see
248+
:ref:`guard events <workflow-usage-guard-events>` and
249+
:ref:`blocking transitions <workflow-blocking-transitions>`).
248250

249251
The three events being dispatched are:
250252

@@ -356,14 +358,15 @@ Guard Events
356358
There are a special kind of events called "Guard events". Their event listeners
357359
are invoked every time a call to ``Workflow::can``, ``Workflow::apply`` or
358360
``Workflow::getEnabledTransitions`` is executed. With the guard events you may
359-
add custom logic to decide what transitions are valid or not. Here is a list
361+
add custom logic to decide which transitions should be blocked or not. Here is a list
360362
of the guard event names.
361363

362364
* ``workflow.guard``
363365
* ``workflow.[workflow name].guard``
364366
* ``workflow.[workflow name].guard.[transition name]``
365367

366-
See example to make sure no blog post without title is moved to "review"::
368+
This example stops any blog post being transitioned to "reviewed" if it is
369+
missing a title::
367370

368371
use Symfony\Component\Workflow\Event\GuardEvent;
369372
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -377,8 +380,7 @@ See example to make sure no blog post without title is moved to "review"::
377380
$title = $post->title;
378381

379382
if (empty($title)) {
380-
// Posts without title are not allowed
381-
// to perform the transition "to_review"
383+
// Block the transition "to_review" if the post has no title
382384
$event->setBlocked(true);
383385
}
384386
}
@@ -418,6 +420,46 @@ This class has two more methods:
418420
:method:`Symfony\\Component\\Workflow\\Event\\GuardEvent::setBlocked`
419421
Sets the blocked value.
420422

423+
.. _workflow-blocking-transitions:
424+
425+
Blocking Transitions
426+
--------------------
427+
428+
The execution of the workflow can be controlled by executing custom logic to
429+
decide if the current transition is blocked or allowed before applying it. This
430+
feature is provided by "guards", which can be used in two ways.
431+
432+
First, you can listen to :ref:`the guard events <workflow-usage-guard-events>`.
433+
Alternatively, you can define a ``guard`` configuration option for the
434+
transition. The value of this option is any valid expression created with the
435+
:doc:`ExpressionLanguage component </components/expression_language>`:
436+
437+
.. configuration-block::
438+
439+
.. code-block:: yaml
440+
441+
# config/packages/workflow.yaml
442+
framework:
443+
workflows:
444+
blog_publishing:
445+
# previous configuration
446+
transitions:
447+
to_review:
448+
# the transition is allowed only if the current user has the ROLE_REVIEWER role.
449+
guard: "is_granted('ROLE_REVIEWER')"
450+
from: draft
451+
to: reviewed
452+
publish:
453+
# or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted"
454+
guard: "is_authenticated"
455+
from: reviewed
456+
to: published
457+
reject:
458+
# or any valid expression language with "subject" referring to the post
459+
guard: "has_role("ROLE_ADMIN") and subject.isStatusReviewed()"
460+
from: reviewed
461+
to: rejected
462+
421463
Usage in Twig
422464
-------------
423465

@@ -459,7 +501,7 @@ The following example shows these functions in action:
459501
{% endfor %}
460502

461503
{# Check if the object is in some specific place #}
462-
{% if workflow_has_marked_place(post, 'review') %}
504+
{% if workflow_has_marked_place(post, 'reviewed') %}
463505
<p>This post is ready for review.</p>
464506
{% endif %}
465507

0 commit comments

Comments
 (0)