@@ -27,8 +27,8 @@ A set of places and transitions creates a **definition**. A workflow needs
2727a ``Definition `` and a way to write the states to the objects (i.e. an
2828instance 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
3232like 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
244244order:
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
356358There are a special kind of events called "Guard events". Their event listeners
357359are 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
360362of 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