8000 Merge remote-tracking branch 'origin/4.3' into feature-workflow-config · symfony/symfony-docs@0ef3235 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0ef3235

Browse files
Merge remote-tracking branch 'origin/4.3' into feature-workflow-config
2 parents 6b4f98a + 346cdf5 commit 0ef3235

File tree

5 files changed

+138
-92
lines changed

5 files changed

+138
-92
lines changed
181 Bytes
Loading

components/workflow.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,19 @@ are trying to use it with::
7676
Usage
7777
-----
7878

79-
When you have configured a ``Registry`` with your workflows, you may use it as follows::
79+
When you have configured a ``Registry`` with your workflows,
80+
you can retreive a workflow from it and use it as follows::
8081

8182
// ...
83+
// Consider that $post is in state "draft" by default
8284
$post = new BlogPost();
8385
$workflow = $registry->get($post);
8486

8587
$workflow->can($post, 'publish'); // False
8688
$workflow->can($post, 'to_review'); // True
8789

88-
$workflow->apply($post, 'to_review');
90+
$workflow->apply($post, 'to_review'); // $post is now in state "review"
91+
8992
$workflow->can($post, 'publish'); // True
9093
$workflow->getEnabledTransitions($post); // ['publish', 'reject']
9194

workflow.rst

Lines changed: 104 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,10 @@ As configured, the following property is used by the marking store::
185185
With this workflow named ``blog_publishing``, you can get help to decide
186186
what actions are allowed on a blog post::
187187

188-
$post = new App\Entity\BlogPost();
188+
use Symfony\Component\Workflow\Exception\LogicException;
189+
use App\Entity\BlogPost;
190+
191+
$post = BlogPost();
189192

190193
$workflow = $this->container->get('workflow.blog_publishing');
191194
$workflow->can($post, 'publish'); // False
@@ -389,6 +392,9 @@ This means that each event has access to the following information:
389392
:method:`Symfony\\Component\\Workflow\\Event\\Event::getWorkflowName`
390393
Returns a string with the name of the workflow that triggered the event.
391394

395+
:method:`Symfony\\Component\\Workflow\\Event\\Event::getMetadata`
396+
Returns a metadata.
397+
392398
For Guard Events, there is an extended class :class:`Symfony\\Component\\Workflow\\Event\\GuardEvent`.
393399
This class has two more methods:
394400

@@ -398,6 +404,13 @@ This class has two more methods:
398404
:method:`Symfony\\Component\\Workflow\\Event\\GuardEvent::setBlocked`
399405
Sets the blocked value.
400406

407+
:method:`Symfony\\Component\\Workflow\\Event\\GuardEvent::getTransitionBlockerList`
408+
Returns the event :class:`Symfony\\Component\\Workflow\\TransitionBlockerList`.
409+
See :ref:`blocking transitions <workflow-blocking-transitions>`.
410+
411+
:method:`Symfony\\Component\\Workflow\\Event\\GuardEvent::addTransitionBlocker`
412+
Add a :class:`Symfony\\Component\\Workflow\\TransitionBlocker` instance.
413+
401414
.. _workflow-blocking-transitions:
402415

403416
Blocking Transitions
@@ -426,16 +439,61 @@ transition. The value of this option is any valid expression created with the
426439
from: draft
427440
to: reviewed
428441
publish:
429-
# or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted"
442+
# or "is_anonymous", "is_remember_me", "is_fully_authenticated", "is_granted", "is_valid"
430443
guard: "is_authenticated"
431444
from: reviewed
432445
to: published
433446
reject:
434-
# or any valid expression language with "subject" referring to the post
435-
guard: "has_role('ROLE_ADMIN') and subject.isStatusReviewed()"
447+
# or any valid expression language with "subject" referring to the supported object
448+
guard: "has_role('ROLE_ADMIN') and subject.isRejectable()"
436449
from: reviewed
437450
to: rejected
438451
452+
You can also use transition blockers to block and return a user-friendly error
453+
message when you stop a transition from happening.
454+
In the example we get this message from the
455+
:class:`Symfony\\Component\\Workflow\\Event\\Event`'s metadata, giving you a
456+
central place to manage the text.
457+
458+
This example has been simplified; in production you may prefer to use the
459+
:doc:`Translation </components/translation>` component to manage messages in one
460+
place::
461+
462+
namespace App\Listener\Workflow\Task;
463+
464+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
465+
use Symfony\Component\Workflow\Event\GuardEvent;
466+
use Symfony\Component\Workflow\TransitionBlocker;
467+
468+
class BlogPostPublishListener implements EventSubscriberInterface
469+
{
470+
public function guardPublish(GuardEvent $event)
471+
{
472+
$eventTransition = $event->getTransition();
473+
$hourLimit = $event->getMetadata('hour_limit', $eventTransition);
474+
475+
if (date('H') <= $hourLimit) {
476+
return;
477+
}
478+
479+
// Block the transition "publish" if it is more than 8 PM
480+
// with the message for end user
481+
$explanation = $event->getMetadata('explanation', $eventTransition);
482+
$event->addTransitionBlocker(new TransitionBlocker($explanation , 0));
483+
}
484+
485+
public static function getSubscribedEvents()
486+
{
487+
return [
488+
'workflow.blog_publishing.guard.publish' => ['guardPublish'],
489+
];
490+
}
491+
}
492+
493+
.. versionadded:: 4.1
494+
495+
The transition blockers were introduced in Symfony 4.1.
496+
439497
Usage in Twig
440498
-------------
441499

@@ -458,15 +516,15 @@ The following example shows these functions in action:
458516

459517
.. code-block:: html+twig
460518

461-
<h3>Actions</h3>
519+
<h3>Actions on Blog Post</h3>
462520
{% if workflow_can(post, 'publish') %}
463-
<a href="...">Publish article</a>
521+
<a href="...">Publish</a>
464522
{% endif %}
465523
{% if workflow_can(post, 'to_review') %}
466524
<a href="...">Submit to review</a>
467525
{% endif %}
468526
{% if workflow_can(post, 'reject') %}
469-
<a href="...">Reject article</a>
527+
<a href="...">Reject</a>
470528
{% endif %}
471529

472530
{# Or loop through the enabled transitions #}
@@ -482,8 +540,8 @@ The following example shows these functions in action:
482540
{% endif %}
483541

484542
{# Check if some place has been marked on the object #}
485-
{% if 'waiting_some_approval' in workflow_marked_places(post) %}
486-
<span class="label">PENDING</span>
543+
{% if 'reviewed' in workflow_marked_places(post) %}
544+
<span class="label">Reviewed</span>
487545
{% endif %}
488546

489547
Storing Metadata
@@ -520,7 +578,12 @@ requires:
520578
to: review
521579
metadata:
522580
priority: 0.5
523-
# ...
581+
publish:
582+
from: reviewed
583+
to: published
584+
metadata:
585+
hour_limit: 20
586+
explanation: 'You can not publish after 8 PM.'
524587
525588
.. code-block:: xml
526589
@@ -551,7 +614,14 @@ requires:
551614
<framework:priority>0.5</framework:priority>
552615
</framework:metadata>
553616
</framework:transition>
554-
<!-- ... -->
617+
<framework:transition name="publish">
618+
<framework:from>reviewed</framework:from>
619+
<framework:to>published</framework:to>
620+
<framework:metadata>
621+
<framework:hour_limit>20</framework:priority>
622+
<framework:explanation>You can not publish after 8 PM.</framework:priority>
623+
</framework:metadata>
624+
</framework:transition>
555625
</framework:workflow>
556626
</framework:config>
557627
</container>
@@ -583,6 +653,14 @@ requires:
583653
'priority' => 0.5,
584654
],
585655
],
656+
'publish' => [
657+
'from' => 'reviewed',
658+
'to' => 'published',
659+
'metadata' => [
660+
'hour_limit' => 20,
661+
'explanation' => 'You can not publish after 8 PM.',
662+
],
663+
],
586664
],
587665
],
588666
],
@@ -591,27 +669,29 @@ requires:
591669
Then you can access this metadata in your controller as follows::
592670

593671
use Symfony\Component\Workflow\Registry;
672+
use App\Entity\BlogPost;
594673

595-
public function myController(Registry $registry, Article $article)
674+
public function myController(Registry $registry, BlogPost $post)
596675
{
597-
$workflow = $registry->get($article);
676+
$workflow = $registry->get($post);
598677

599678
$title = $workflow
600679
->getMetadataStore()
601-
->getWorkflowMetadata()['title'] ?? false
680+
->getWorkflowMetadata()['title'] ?? 'Default title'
602681
;
603682

604683
// or
605684
$aTransition = $workflow->getDefinition()->getTransitions()[0];
606685
$transitionTitle = $workflow
607686
->getMetadataStore()
608-
->getTransitionMetadata($aTransition)['title'] ?? false
687+
->getTransitionMetadata($aTransition)['priority'] ?? 0
609688
;
610689
}
611690

612-
There is a shortcut that works with everything::
691+
There is a shortcut that works with every metadata level::
613692

614693
$title = $workflow->getMetadataStore()->getMetadata('title');
694+
$priority = $workflow->getMetadataStore()->getMetadata('priority');
615695

616696
In a :ref:`flash message <flash-messages>` in your controller::
617697

@@ -621,76 +701,35 @@ In a :ref:`flash message <flash-messages>` in your controller::
621701
$title = $workflow->getMetadataStore()->getMetadata('title', $transition);
622702
$this->addFlash('info', "You have successfully applied the transition with title: '$title'");
623703

624-
Metadata can also be accessed in a Listener, from the Event object.
625-
626-
Using transition blockers you can return a user-friendly error message when you
627-
stop a transition from happening. In the example we get this message from the
628-
:class:`Symfony\\Component\\Workflow\\Event\\Event`'s metadata, giving you a
629-
central place to manage the text.
630-
631-
This example has been simplified; in production you may prefer to use the
632-
:doc:`Translation </components/translation>` component to manage messages in one
633-
place::
634-
635-
namespace App\Listener\Workflow\Task;
636-
637-
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
638-
use Symfony\Component\Workflow\Event\GuardEvent;
639-
use Symfony\Component\Workflow\TransitionBlocker;
640-
641-
class OverdueGuard implements EventSubscriberInterface
642-
{
643-
public function guardPublish(GuardEvent $event)
644-
{
645-
$timeLimit = $event->getMetadata('time_limit', $event->getTransition());
646-
647-
if (date('Hi') <= $timeLimit) {
648-
return;
649-
}
650-
651-
$explanation = $event->getMetadata('explanation', $event->getTransition());
652-
$event->addTransitionBlocker(new TransitionBlocker($explanation , 0));
653-
}
654-
655-
public static function getSubscribedEvents()
656-
{
657-
return [
658-
'workflow.task.guard.done' => 'guardPublish',
659-
];
660-
}
661-
}
662-
663-
.. versionadded:: 4.1
664-
665-
The transition blockers were introduced in Symfony 4.1.
704+
Metadata can also be accessed in a Listener, from the :class:`Symfony\\Component\\Workflow\\Event\\Event` object.
666705

667706
In Twig templates, metadata is available via the ``workflow_metadata()`` function:
668707

669708
.. code-block:: html+twig
670709

671-
<h2>Metadata</h2>
710+
<h2>Metadata of Blog Post</h2>
672711
<p>
673-
<strong>Workflow</strong>:<br >
674-
<code>{{ workflow_metadata(article, 'title') }}</code>
712+
<strong>Workflow</strong>:<br>
713+
<code>{{ workflow_metadata(blog_post, 'title') }}</code>
675714
</p>
676715
<p>
677716
<strong>Current place(s)</strong>
678717
<ul>
679-
{% for place in workflow_marked_places(article) %}
718+
{% for place in workflow_marked_places(blog_post) %}
680719
<li>
681720
{{ place }}:
682-
<code>{{ workflow_metadata(article, 'max_num_of_words', place) ?: 'Unlimited'}}</code>
721+
<code>{{ workflow_metadata(blog_post, 'max_num_of_words', place) ?: 'Unlimited'}}</code>
683722
</li>
684723
{% endfor %}
685724
</ul>
686725
</p>
687726
<p>
688727
<strong>Enabled transition(s)</strong>
689728
<ul>
690-
{% for transition in workflow_transitions(article) %}
729+
{% for transition in workflow_transitions(blog_post) %}
691730
<li>
692731
{{ transition.name }}:
693-
<code>{{ workflow_metadata(article, 'priority', transition) ?: '0' }}</code>
732+
<code>{{ workflow_metadata(blog_post, 'priority', transition) ?: '0' }}</code>
694733
</li>
695734
{% endfor %}
696735
</ul>

workflow/dumping-workflows.rst

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ How to Dump Workflows
55
=====================
66

77
To help you debug your workflows, you can dump a representation of your workflow
8-
or state machine with the use of a ``DumperInterface``. Symfony provides 2
9-
different dumpers both based on Dot.
8+
or state machine with the use of a ``DumperInterface``. Symfony provides two
9+
different dumpers, both based on Dot (see below).
1010

1111
Use the ``GraphvizDumper`` or ``StateMachineGraphvizDumper`` to create DOT
1212
files, or use ``PlantUmlDumper`` for PlantUML files. Both types can be converted
@@ -24,17 +24,20 @@ Images of the workflow defined above::
2424

2525
.. code-block:: terminal
2626
27+
# dump DOT file in PNG image:
2728
$ php dump-graph-dot.php | dot -Tpng -o dot_graph.png
28-
$ php dump-graph-puml.php | java -jar plantuml.jar -p > puml_graph.png
2929
30-
# run this command if you prefer SVG images:
30+
# dump DOT file in SVG image:
3131
# $ php dump-graph-dot.php | dot -Tsvg -o dot_graph.svg
3232
33+
# dump PlantUML in PNG image:
34+
$ php dump-graph-puml.php | java -jar plantuml.jar -p > puml_graph.png
35+
3336
The DOT result will look like this:
3437

3538
.. image:: /_images/components/workflow/blogpost.png
3639

37-
The PUML result:
40+
The PlantUML result:
3841

3942
.. image:: /_images/components/workflow/blogpost_puml.png
4043

@@ -43,8 +46,9 @@ Inside a Symfony application, you can dump the files with those commands using
4346

4447
.. code-block:: terminal
4548
46-
$ php bin/console workflow:dump name | dot -Tsvg -o graph.svg
47-
$ php bin/console workflow:dump name --dump-format=puml | java -jar plantuml.jar -p > workflow.png
49+
$ php bin/console workflow:dump workflow_name | dot -Tpng -o workflow_name.png
50+
$ php bin/console workflow:dump workflow_name | dot -Tsvg -o workflow_name.svg
51+
$ php bin/console workflow:dump workflow_name --dump-format=puml | java -jar plantuml.jar -p > workflow_name.png
4852
4953
.. note::
5054

0 commit comments

Comments
 (0)
0