@@ -14,6 +14,16 @@ install the workflow feature before using it:
1414
1515 $ composer require symfony/workflow
1616
17+ Configuration
18+ -------------
19+
20+ To see all configuration options, if you are using the component inside a
21+ Symfony project run this command:
22+
23+ .. code-block :: terminal
24+
25+ $ php bin/console config:dump-reference framework workflows
26+
1727 Creating a Workflow
1828-------------------
1929
@@ -665,3 +675,222 @@ Don't need a human-readable message? You can also block a transition via a guard
665675event using::
666676
667677 $event->setBlocked('true');
678+
679+ Storing Metadata
680+ ----------------
681+
682+ .. versionadded :: 4.1
683+
684+ The feature to store metadata in workflows was introduced in Symfony 4.1.
685+
686+ In case you need it, you can store arbitrary metadata in workflows, their
687+ places, and their transitions using the ``metadata `` option. This metadata can
688+ be as simple as the title of the workflow or as complex as your own application
689+ requires:
690+
691+ .. configuration-block ::
692+
693+ .. code-block :: yaml
694+
695+ # config/packages/workflow.yaml
696+ framework :
697+ workflows :
698+ blog_publishing :
699+ metadata :
700+ title : ' Blog Publishing Workflow'
701+ # ...
702+ places :
703+ draft :
704+ metadata :
705+ max_num_of_words : 500
706+ # ...
707+ transitions :
708+ to_review :
709+ from : draft
710+ to : review
711+ metadata :
712+ priority : 0.5
713+ # ...
714+
715+ .. code-block :: xml
716+
717+ <!-- config/packages/workflow.xml -->
718+ <?xml version =" 1.0" encoding =" UTF-8" ?>
719+ <container xmlns =" http://symfony.com/schema/dic/services"
720+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
721+ xmlns : framework =" http://symfony.com/schema/dic/symfony"
722+ xsi : schemaLocation =" http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
723+ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
724+ >
725+
726+ <framework : config >
727+ <framework : workflow name =" blog_publishing" >
728+ <framework : metadata >
729+ <framework : title >Blog Publishing Workflow</framework : title >
730+ </framework : metadata >
731+ <!-- ... -->
732+
733+ <framework : place name =" draft" >
734+ <framework : metadata >
735+ <framework : max-num-of-words >500</framework : max-num-of-words >
736+ </framework : metadata >
737+ </framework : place >
738+ <!-- ... -->
739+
740+ <framework : transition name =" to_review" >
741+ <framework : from >draft</framework : from >
742+ <framework : to >review</framework : to >
743+ <framework : metadata >
744+ <framework : priority >0.5</framework : priority >
745+ </framework : metadata >
746+ </framework : transition >
747+ <!-- ... -->
748+ </framework : workflow >
749+ </framework : config >
750+ </container >
751+
752+ .. code-block :: php
753+
754+ // config/packages/workflow.php
755+
756+ $container->loadFromExtension('framework', [
757+ // ...
758+ 'workflows' => [
759+ 'blog_publishing' => [
760+ 'metadata' => [
761+ 'title' => 'Blog Publishing Workflow',
762+ ],
763+ // ...
764+ 'places' => [
765+ 'draft' => [
766+ 'metadata' => [
767+ 'max_num_of_words' => 500,
768+ ],
769+ ],
770+ // ...
771+ ],
772+ 'transitions' => [
773+ 'to_review' => [
774+ 'from' => 'draft',
775+ 'to' => 'review',
776+ 'metadata' => [
777+ 'priority' => 0.5,
778+ ],
779+ ],
780+ ],
781+ ],
782+ ],
783+ ]);
784+
785+ Then you can access this metadata in your controller as follows::
786+
787+ public function myController(Registry $registry, Article $article)
788+ {
789+ $workflow = $registry->get($article);
790+
791+ $title = $workflow
792+ ->getMetadataStore()
793+ ->getWorkflowMetadata()['title'] ?? false
794+ ;
795+
796+ // or
797+ $title = $workflow->getMetadataStore()
798+ ->getWorkflowMetadata()['title'] ?? false
799+ ;
800+
801+ // or
802+ $aTransition = $workflow->getDefinition()->getTransitions()[0];
803+ $transitionTitle = $workflow
804+ ->getMetadataStore()
805+ ->getTransitionMetadata($aTransition)['title'] ?? false
806+ ;
807+ }
808+
809+ There is a shortcut that works with everything::
810+
811+ $title = $workflow->getMetadataStore()->getMetadata('title');
812+
813+ In a :ref: `flash message <flash-messages >` in your controller::
814+
815+ // $transition = ...; (an instance of Transition)
816+
817+ // $workflow is a Workflow instance retrieved from the Registry (see above)
818+ $title = $workflow->getMetadataStore()->getMetadata('title', $transition);
819+ $this->addFlash('info', "You have successfully applied the transition with title: '$title'");
820+
821+ Metadata can also be accessed in a Listener, from the Event object.
822+
823+ Using transition blockers you can return a user-friendly error message when you
824+ stop a transition from happening. The example gets this message from the
825+ :class: `Symfony\\ Component\\ Workflow\\ Event\\ Event `'s metadata, giving you a
826+ central place to manage the text.
827+
828+ .. tip ::
829+
830+ This example has been simplified; in production you may prefer to use the
831+ :doc: `Translation </components/translation >` component to manage messages in
832+ one place::
833+
834+ namespace App\Listener\Workflow\Task;
835+
836+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
837+ use Symfony\Component\Workflow\Event\GuardEvent;
838+ use Symfony\Component\Workflow\TransitionBlocker;
839+
840+ class OverdueGuard implements EventSubscriberInterface
841+ {
842+ public function guardPublish(GuardEvent $event)
843+ {
844+ $timeLimit = $event->getMetadata('time_limit', $event->getTransition());
845+
846+ if (date('Hi') <= $timeLimit) {
847+ return;
848+ }
849+
850+ $explanation = $event->getMetadata('explanation', $event->getTransition());
851+ $event->addTransitionBlocker(new TransitionBlocker($explanation , 0));
852+ }
853+
854+ public static function getSubscribedEvents()
855+ {
856+ return [
857+ 'workflow.task.guard.done' => 'guardPublish',
858+ ];
859+ }
860+ }
861+
862+ .. versionadded :: 4.1
863+
864+ The transition blockers were introduced in Symfony 4.1.
865+
866+ In Twig templates, metadata is available via the ``workflow_metadata() `` function:
867+
868+ .. code-block :: html+twig
869+
870+ <h2>Metadata</h2>
871+ <p>
872+ <strong>Workflow</strong>:<br >
873+ <code>{{ workflow_metadata(article, 'title') }}</code>
874+ </p>
875+ <p>
876+ <strong>Current place(s)</strong>
877+ <ul>
878+ {% for place in workflow_marked_places(article) %}
879+ <li>
880+ {{ place }}:
881+ <code>{{ workflow_metadata(article, 'max_num_of_words', place) ?: 'Unlimited'}}</code>
882+ </li>
883+ {% endfor %}
884+ </ul>
885+ </p>
886+ <p>
887+ <strong>Enabled transition(s)</strong>
888+ <ul>
889+ {% for transition in workflow_transitions(article) %}
890+ <li>
891+ {{ transition.name }}:
892+ <code>{{ workflow_metadata(article, 'priority', transition) ?: '0' }}</code>
893+ </li>
894+ {% endfor %}
895+ </ul>
896+ </p>
0 commit comments