@@ -14,6 +14,16 @@ install the workflow feature before using it:
14
14
15
15
$ composer require symfony/workflow
16
16
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
+
17
27
Creating a Workflow
18
28
-------------------
19
29
@@ -665,3 +675,222 @@ Don't need a human-readable message? You can also block a transition via a guard
665
675
event using::
666
676
667
677
$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