diff --git a/workflow/usage.rst b/workflow/usage.rst index e1a106e6e82..7b5fc28b90b 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -28,7 +28,7 @@ a ``Definition`` and a way to write the states to the objects (i.e. an instance of a :class:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface`.) Consider the following example for a blog post that can have these places: -``draft``, ``review``, ``rejected``, ``published``. You can define the workflow +``draft``, ``reviewed``, ``rejected``, ``published``. You can define the workflow like this: .. configuration-block:: @@ -51,18 +51,18 @@ like this: initial_place: draft places: - draft - - review + - reviewed - rejected - published transitions: to_review: from: draft - to: review + to: reviewed publish: - from: review + from: reviewed to: published reject: - from: review + from: reviewed to: rejected .. code-block:: xml @@ -87,24 +87,24 @@ like this: App\Entity\BlogPost draft - review + reviewed rejected published draft - review + reviewed - review + reviewed published - review + reviewed rejected @@ -132,21 +132,21 @@ like this: 'supports' => ['App\Entity\BlogPost'], 'places' => [ 'draft', - 'review', + 'reviewed', 'rejected', 'published', ], 'transitions' => [ 'to_review' => [ 'from' => 'draft', - 'to' => 'review', + 'to' => 'reviewed', ], 'publish' => [ - 'from' => 'review', + 'from' => 'reviewed', 'to' => 'published', ], 'reject' => [ - 'from' => 'review', + 'from' => 'reviewed', 'to' => 'rejected', ], ], @@ -327,7 +327,7 @@ When a state transition is initiated, the events are dispatched in the following order: ``workflow.guard`` - Validate whether the transition is allowed at all (:ref:`see below `). + Validate whether the transition is blocked or not (:ref:`see below ` and :ref:`using guards `). The three events being dispatched are: @@ -439,14 +439,14 @@ Guard Events There are a special kind of events called "Guard events". Their event listeners are invoked every time a call to ``Workflow::can``, ``Workflow::apply`` or ``Workflow::getEnabledTransitions`` is executed. With the guard events you may -add custom logic to decide what transitions are valid or not. Here is a list +add custom logic to decide which transitions should be blocked or not. Here is a list of the guard event names. * ``workflow.guard`` * ``workflow.[workflow name].guard`` * ``workflow.[workflow name].guard.[transition name]`` -See example to make sure no blog post without title is moved to "review":: +This example stops any blog post being transitioned to "reviewed" if it is missing a title:: use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -460,8 +460,8 @@ See example to make sure no blog post without title is moved to "review":: $title = $post->title; if (empty($title)) { - // Posts without title are not allowed - // to perform the transition "to_review" + // Block the transition "to_review" + // if the post has no title $event->setBlocked(true); } } @@ -501,6 +501,51 @@ This class has two more methods: :method:`Symfony\\Component\\Workflow\\Event\\GuardEvent::setBlocked` Sets the blocked value. +.. _workflow-usage-using-guards: + +Using Guards +------------ + +The component has a guard logic to control the execution of your workflow on top of your configuration. + +It allows you to execute your custom logic to decide if the transition is blocked or not, before actually +applying this transition. + +You have multiple optional ways to use guards in your workflow. + +The first way is :ref:`with the guard event `, which allows you to implement +any desired feature. + +Another one is via the configuration and its specific entry ``guard`` on a transition. + +This ``guard`` entry allows any expression that is valid for the Expression Language component: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/workflow.yaml + framework: + workflows: + blog_publishing: + # previous configuration + transitions: + to_review: + # the transition is allowed only if the current user has the ROLE_REVIEWER role. + guard: "is_granted('ROLE_REVIEWER')" + from: draft + to: reviewed + publish: + # or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted" + guard: "is_authenticated" + from: reviewed + to: published + reject: + # or any valid expression language with "subject" refering to the post + guard: "has_role("ROLE_ADMIN") and subject.isStatusReviewed()" + from: reviewed + to: rejected + Usage in Twig ------------- @@ -542,7 +587,7 @@ The following example shows these functions in action: {% endfor %} {# Check if the object is in some specific place #} - {% if workflow_has_marked_place(post, 'review') %} + {% if workflow_has_marked_place(post, 'reviewed') %}

This post is ready for review.

{% endif %}