Skip to content

Commit 025c2bb

Browse files
committed
Merge branch '4.2'
* 4.2: Documented the workflow metadata
2 parents 8a6b025 + ad961c7 commit 025c2bb

File tree

1 file changed

+229
-0
lines changed

1 file changed

+229
-0
lines changed

workflow/usage.rst

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
665675
event 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

Comments
 (0)