@@ -197,7 +197,10 @@ As configured, the following property is used by the marking store::
197197With this workflow named ``blog_publishing ``, you can get help to decide
198198what actions are allowed on a blog post::
199199
200- $post = new App\Entity\BlogPost();
200+ use Symfony\Component\Workflow\Exception\LogicException;
201+ use App\Entity\BlogPost;
202+
203+ $post = BlogPost();
201204
202205 $workflow = $this->container->get('workflow.blog_publishing');
203206 $workflow->can($post, 'publish'); // False
@@ -401,6 +404,9 @@ This means that each event has access to the following information:
401404:method: `Symfony\\ Component\\ Workflow\\ Event\\ Event::getWorkflowName `
402405 Returns a string with the name of the workflow that triggered the event.
403406
407+ :method: `Symfony\\ Component\\ Workflow\\ Event\\ Event::getMetadata `
408+ Returns a metadata.
409+
404410For Guard Events, there is an extended class:class: `Symfony\\ Component\\ Workflow\\ Event\\ GuardEvent `.
405411This class has two more methods:
406412
@@ -410,6 +416,13 @@ This class has two more methods:
410416:method: `Symfony\\ Component\\ Workflow\\ Event\\ GuardEvent::setBlocked `
411417 Sets the blocked value.
412418
419+ :method: `Symfony\\ Component\\ Workflow\\ Event\\ GuardEvent::getTransitionBlockerList `
420+ Returns the event:class: `Symfony\\ Component\\ Workflow\\ TransitionBlockerList `.
421+ See:ref: `blocking transitions <workflow-blocking-transitions >`.
422+
423+ :method: `Symfony\\ Component\\ Workflow\\ Event\\ GuardEvent::addTransitionBlocker `
424+ Add a:class: `Symfony\\ Component\\ Workflow\\ TransitionBlocker ` instance.
425+
413426.. _workflow-blocking-transitions :
414427
415428Blocking Transitions
@@ -438,16 +451,61 @@ transition. The value of this option is any valid expression created with the
438451from :draft
439452to :reviewed
440453publish :
441- # or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted"
454+ # or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted", "is_valid"
442455guard :" is_authenticated"
443456from :reviewed
444457to :published
445458reject :
446- # or any valid expression language with "subject" referring to thepost
447- guard :" has_role('ROLE_ADMIN') and subject.isStatusReviewed ()"
459+ # or any valid expression language with "subject" referring to thesupported object
460+ guard :" has_role('ROLE_ADMIN') and subject.isRejectable ()"
448461from :reviewed
449462to :rejected
450463
464+ You can also use transition blockers to block and return a user-friendly error
465+ message when you stop a transition from happening.
466+ In the example we get this message from the
467+ :class: `Symfony\\ Component\\ Workflow\\ Event\\ Event `'s metadata, giving you a
468+ central place to manage the text.
469+
470+ This example has been simplified; in production you may prefer to use the
471+ :doc: `Translation </components/translation >` component to manage messages in one
472+ place::
473+
474+ namespace App\Listener\Workflow\Task;
475+
476+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
477+ use Symfony\Component\Workflow\Event\GuardEvent;
478+ use Symfony\Component\Workflow\TransitionBlocker;
479+
480+ class BlogPostPublishListener implements EventSubscriberInterface
481+ {
482+ public function guardPublish(GuardEvent $event)
483+ {
484+ $eventTransition = $event->getTransition();
485+ $hourLimit = $event->getMetadata('hour_limit', $eventTransition);
486+
487+ if (date('H') <= $hourLimit) {
488+ return;
489+ }
490+
491+ // Block the transition "publish" if it is more than 8 PM
492+ // with the message for end user
493+ $explanation = $event->getMetadata('explanation', $eventTransition);
494+ $event->addTransitionBlocker(new TransitionBlocker($explanation , 0));
495+ }
496+
497+ public static function getSubscribedEvents()
498+ {
499+ return [
500+ 'workflow.blog_publishing.guard.publish' => ['guardPublish'],
501+ ];
502+ }
503+ }
504+
505+ ..versionadded ::4.1
506+
507+ The transition blockers were introduced in Symfony 4.1.
508+
451509Usage in Twig
452510-------------
453511
@@ -470,15 +528,15 @@ The following example shows these functions in action:
470528
471529..code-block ::html+twig
472530
473- <h3>Actions</h3>
531+ <h3>Actions on Blog Post </h3>
474532 {% if workflow_can(post, 'publish') %}
475- <a href="...">Publish article </a>
533+ <a href="...">Publish</a>
476534 {% endif %}
477535 {% if workflow_can(post, 'to_review') %}
478536 <a href="...">Submit to review</a>
479537 {% endif %}
480538 {% if workflow_can(post, 'reject') %}
481- <a href="...">Reject article </a>
539+ <a href="...">Reject</a>
482540 {% endif %}
483541
484542 {# Or loop through the enabled transitions #}
@@ -494,8 +552,8 @@ The following example shows these functions in action:
494552 {% endif %}
495553
496554 {# Check if some place has been marked on the object #}
497- {% if 'waiting_some_approval ' in workflow_marked_places(post) %}
498- <span>PENDING </span>
555+ {% if 'reviewed ' in workflow_marked_places(post) %}
556+ <span>Reviewed </span>
499557 {% endif %}
500558
501559Storing Metadata
@@ -532,7 +590,12 @@ requires:
532590to :review
533591metadata :
534592priority :0.5
535- # ...
593+ publish :
594+ from :reviewed
595+ to :published
596+ metadata :
597+ hour_limit :20
598+ explanation :' You can not publish after 8 PM.'
536599
537600 ..code-block ::xml
538601
@@ -563,7 +626,14 @@ requires:
563626 <framework : priority >0.5</framework : priority >
564627 </framework : metadata >
565628 </framework : transition >
566- <!-- ...-->
629+ <framework : transition name =" publish" >
630+ <framework : from >reviewed</framework : from >
631+ <framework : to >published</framework : to >
632+ <framework : metadata >
633+ <framework : hour_limit >20</framework : priority >
634+ <framework : explanation >You can not publish after 8 PM.</framework : priority >
635+ </framework : metadata >
636+ </framework : transition >
567637 </framework : workflow >
568638 </framework : config >
569639 </container >
@@ -595,6 +665,14 @@ requires:
595665 'priority' => 0.5,
596666 ],
597667 ],
668+ 'publish' => [
669+ 'from' => 'reviewed',
670+ 'to' => 'published',
671+ 'metadata' => [
672+ 'hour_limit' => 20,
673+ 'explanation' => 'You can not publish after 8 PM.',
674+ ],
675+ ],
598676 ],
599677 ],
600678 ],
@@ -603,27 +681,29 @@ requires:
603681 Then you can access this metadata in your controller as follows::
604682
605683 use Symfony\Component\Workflow\Registry;
684+ use App\Entity\BlogPost;
606685
607- public function myController(Registry $registry,Article $article )
686+ public function myController(Registry $registry,BlogPost $post )
608687 {
609- $workflow = $registry->get($article );
688+ $workflow = $registry->get($post );
610689
611690 $title = $workflow
612691 ->getMetadataStore()
613- ->getWorkflowMetadata()['title'] ??false
692+ ->getWorkflowMetadata()['title'] ??'Default title'
614693 ;
615694
616695 // or
617696 $aTransition = $workflow->getDefinition()->getTransitions()[0];
618697 $transitionTitle = $workflow
619698 ->getMetadataStore()
620- ->getTransitionMetadata($aTransition)['title '] ??false
699+ ->getTransitionMetadata($aTransition)['priority '] ??0
621700 ;
622701 }
623702
624- There is a shortcut that works witheverything ::
703+ There is a shortcut that works withevery metadata level ::
625704
626705 $title = $workflow->getMetadataStore()->getMetadata('title');
706+ $priority = $workflow->getMetadataStore()->getMetadata('priority');
627707
628708In a:ref: `flash message <flash-messages >` in your controller::
629709
@@ -633,76 +713,35 @@ In a :ref:`flash message <flash-messages>` in your controller::
633713 $title = $workflow->getMetadataStore()->getMetadata('title', $transition);
634714 $this->addFlash('info', "You have successfully applied the transition with title: '$title'");
635715
636- Metadata can also be accessed in a Listener, from the Event object.
637-
638- Using transition blockers you can return a user-friendly error message when you
639- stop a transition from happening. In the example we get this message from the
640- :class: `Symfony\\ Component\\ Workflow\\ Event\\ Event `'s metadata, giving you a
641- central place to manage the text.
642-
643- This example has been simplified; in production you may prefer to use the
644- :doc: `Translation </components/translation >` component to manage messages in one
645- place::
646-
647- namespace App\Listener\Workflow\Task;
648-
649- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
650- use Symfony\Component\Workflow\Event\GuardEvent;
651- use Symfony\Component\Workflow\TransitionBlocker;
652-
653- class OverdueGuard implements EventSubscriberInterface
654- {
655- public function guardPublish(GuardEvent $event)
656- {
657- $timeLimit = $event->getMetadata('time_limit', $event->getTransition());
658-
659- if (date('Hi') <= $timeLimit) {
660- return;
661- }
662-
663- $explanation = $event->getMetadata('explanation', $event->getTransition());
664- $event->addTransitionBlocker(new TransitionBlocker($explanation , 0));
665- }
666-
667- public static function getSubscribedEvents()
668- {
669- return [
670- 'workflow.task.guard.done' => 'guardPublish',
671- ];
672- }
673- }
674-
675- ..versionadded ::4.1
676-
677- The transition blockers were introduced in Symfony 4.1.
716+ Metadata can also be accessed in a Listener, from the:class: `Symfony\\ Component\\ Workflow\\ Event\\ Event ` object.
678717
679718In Twig templates, metadata is available via the ``workflow_metadata() `` function:
680719
681720..code-block ::html+twig
682721
683- <h2>Metadata</h2>
722+ <h2>Metadata of Blog Post </h2>
684723 <p>
685- <strong>Workflow</strong>:<br >
686- <code>{{ workflow_metadata(article , 'title') }}</code>
724+ <strong>Workflow</strong>:<br>
725+ <code>{{ workflow_metadata(blog_post , 'title') }}</code>
687726 </p>
688727 <p>
689728 <strong>Current place(s)</strong>
690729 <ul>
691- {% for place in workflow_marked_places(article ) %}
730+ {% for place in workflow_marked_places(blog_post ) %}
692731 <li>
693732 {{ place }}:
694- <code>{{ workflow_metadata(article , 'max_num_of_words', place) ?: 'Unlimited'}}</code>
733+ <code>{{ workflow_metadata(blog_post , 'max_num_of_words', place) ?: 'Unlimited'}}</code>
695734 </li>
696735 {% endfor %}
697736 </ul>
698737 </p>
699738 <p>
700739 <strong>Enabled transition(s)</strong>
701740 <ul>
702- {% for transition in workflow_transitions(article ) %}
741+ {% for transition in workflow_transitions(blog_post ) %}
703742 <li>
704743 {{ transition.name }}:
705- <code>{{ workflow_metadata(article , 'priority', transition) ?: '0' }}</code>
744+ <code>{{ workflow_metadata(blog_post , 'priority', transition) ?: '0' }}</code>
706745 </li>
707746 {% endfor %}
708747 </ul>