@@ -14,6 +14,15 @@ 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 Symfony project run this command:
21
+
22
+ .. code-block :: terminal
23
+
24
+ $ bin/console config:dump-reference framework workflows
25
+
17
26
Creating a Workflow
18
27
-------------------
19
28
@@ -552,3 +561,224 @@ Don't need a human-readable message? You can also block a transition via a guard
552
561
event using::
553
562
554
563
$event->setBlocked('true');
564
+
565
+ Storing Metadata
566
+ ----------------
567
+
568
+ .. versionadded :: 4.1
569
+
570
+ The feature to store metadata in workflows was introduced in Symfony 4.1.
571
+
572
+ In case you need it, you can store arbitrary metadata in workflows, their
573
+ places, and their transitions using the ``metadata `` option. This metadata can
574
+ be as simple as the title of the workflow or as complex as your own application
575
+ requires:
576
+
577
+ .. configuration-block ::
578
+
579
+ .. code-block :: yaml
580
+
581
+ # config/packages/workflow.yaml
582
+ framework :
583
+ workflows :
584
+ blog_publishing :
585
+ metadata :
586
+ title : ' Blog Publishing Workflow'
587
+ # ...
588
+ places :
589
+ draft :
590
+ metadata :
591
+ max_num_of_words : 500
592
+ # ...
593
+ transitions :
594
+ to_review :
595
+ from : draft
596
+ to : review
597
+ metadata :
598
+ priority : 0.5
599
+ # ...
600
+
601
+ .. code-block :: xml
602
+
603
+ <!-- config/packages/workflow.xml -->
604
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
605
+ <container xmlns =" http://symfony.com/schema/dic/services"
606
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
607
+ xmlns : framework =" http://symfony.com/schema/dic/symfony"
608
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
609
+ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
610
+ >
611
+
612
+ <framework : config >
613
+ <framework : workflow name =" blog_publishing" >
614
+ <framework : metadata >
615
+ <framework : title >Blog Publishing Workflow</framework : title >
616
+ </framework : metadata >
617
+ <!-- ... -->
618
+
619
+ <framework : place name =" draft" >
620
+ <framework : metadata >
621
+ <framework : max-num-of-words >500</framework : max-num-of-words >
622
+ </framework : metadata >
623
+ </framework : place >
624
+ <!-- ... -->
625
+
626
+ <framework : transition name =" to_review" >
627
+ <framework : from >draft</framework : from >
628
+ <framework : to >review</framework : to >
629
+ <framework : metadata >
630
+ <framework : priority >0.5</framework : priority >
631
+ </framework : metadata >
632
+ </framework : transition >
633
+ <!-- ... -->
634
+ </framework : workflow >
635
+ </framework : config >
636
+ </container >
637
+
638
+ .. code-block :: php
639
+
640
+ // config/packages/workflow.php
641
+
642
+ $container->loadFromExtension('framework', [
643
+ // ...
644
+ 'workflows' => [
645
+ 'blog_publishing' => [
646
+ 'metadata' => [
647
+ 'title' => 'Blog Publishing Workflow',
648
+ ],
649
+ // ...
650
+ 'places' => [
651
+ 'draft' => [
652
+ 'metadata' => [
653
+ 'max_num_of_words' => 500,
654
+ ],
655
+ ],
656
+ // ...
657
+ ],
658
+ 'transitions' => [
659
+ 'to_review' => [
660
+ 'from' => 'draft',
661
+ 'to' => 'review',
662
+ 'metadata' => [
663
+ 'priority' => 0.5,
664
+ ],
665
+ ],
666
+ ],
667
+ ],
668
+ ],
669
+ ]);
670
+
671
+ Then you can access this metadata in your controller as follows::
672
+
673
+ public function myControllerAction(Registry $registry, Article $article)
674
+ {
675
+ $workflow = $registry->get($article);
676
+
677
+ $workflow
678
+ ->getMetadataStore()
679
+ ->getWorkflowMetadata()['title'] ?? false
680
+ ;
681
+
682
+ // or
683
+ $workflow->getMetadataStore()
684
+ ->getWorkflowMetadata()['title'] ?? false
685
+ ;
686
+
687
+ // or
688
+ $aTransition = $workflow->getDefinition()->getTransitions()[0];
689
+ $workflow
690
+ ->getMetadataStore()
691
+ ->getTransitionMetadata($aTransition)['title'] ?? false
692
+ ;
693
+ }
694
+
695
+ There is a shortcut that works with everything::
696
+
697
+ $workflow
698
+ ->getMetadataStore()
699
+ ->getMetadata('title')
700
+ ;
701
+
702
+ In a Flash message in your Controller::
703
+
704
+ // $transition = ...; (an instance of Transition)
705
+
706
+ // $workflow is a Workflow instance retrieved from the Registry (see above)
707
+ $title = $workflow->getMetadataStore()->getMetadata('title', $transition);
708
+ $this->addFlash('info', "You have successfully applied the transition with title: '$title'");
709
+
710
+ Metadata can also be accessed in a Listener, from the Event object.
711
+
712
+ Using transition blockers you can
713
+ return a user-friendly error message when you stop a transition from happening. In the example we
714
+ get this message from the :class: `Symfony\\ Component\\ Workflow\\ Event\\ Event `'s metadata, giving
715
+ you a central place to manage the text.
716
+
717
+ .. tip ::
718
+
719
+ This example has been simplified; in production you may prefer to use the :doc: `Translation </components/translation >`
720
+ component to manage messages in one place::
721
+
722
+ namespace App\Listener\Workflow\Task;
723
+
724
+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
725
+ use Symfony\Component\Workflow\Event\GuardEvent;
726
+ use Symfony\Component\Workflow\TransitionBlocker;
727
+
728
+ class OverdueGuard implements EventSubscriberInterface
729
+ {
730
+ public function guardPublish(GuardEvent $event)
731
+ {
732
+ $timeLimit = $event->getMetadata('time_limit', $event->getTransition());
733
+
734
+ if (date('Hi') <= $timeLimit) {
735
+ return;
736
+ }
737
+
738
+ $explanation = $event->getMetadata('explanation', $event->getTransition());
739
+ $event->addTransitionBlocker(new TransitionBlocker($explanation , 0));
740
+ }
741
+
742
+ public static function getSubscribedEvents()
743
+ {
744
+ return [
745
+ 'workflow.task.guard.done' => 'guardPublish',
746
+ ];
747
+ }
748
+ }
749
+
750
+ .. versionadded :: 4.1
751
+
752
+ The transition blockers were introduced in Symfony 4.1.
753
+
754
+ In Twig templates, metadata is available via the ``workflow_metadata() `` function:
755
+
756
+ .. code-block :: html+twig
757
+
758
+ <h2>Metadata</h2>
759
+ <p>
760
+ <strong>Workflow</strong>:<br >
761
+ <code>{{ workflow_metadata(article, 'title') }}</code>
762
+ </p>
763
+ <p>
764
+ <strong>Current place(s)</strong>
765
+ <ul>
766
+ {% for place in workflow_marked_places(article) %}
767
+ <li>
768
+ {{ place }}:
769
+ <code>{{ workflow_metadata(article, 'max_num_of_words', place) ?: 'Unlimited'}}</code>
770
+ </li>
771
+ {% endfor %}
772
+ </ul>
773
+ </p>
774
+ <p>
775
+ <strong>Enabled transition(s)</strong>
776
+ <ul>
777
+ {% for transition in workflow_transitions(article) %}
778
+ <li>
779
+ {{ transition.name }}:
780
+ <code>{{ workflow_metadata(article, 'priority', transition) ?: '0' }}</code>
781
+ </li>
782
+ {% endfor %}
783
+ </ul>
784
+ </p>
0 commit comments