@@ -185,7 +185,10 @@ As configured, the following property is used by the marking store::
185
185
With this workflow named ``blog_publishing ``, you can get help to decide
186
186
what actions are allowed on a blog post::
187
187
188
- $post = new App\Entity\BlogPost();
188
+ use Symfony\Component\Workflow\Exception\LogicException;
189
+ use App\Entity\BlogPost;
190
+
191
+ $post = BlogPost();
189
192
190
193
$workflow = $this->container->get('workflow.blog_publishing');
191
194
$workflow->can($post, 'publish'); // False
@@ -389,6 +392,9 @@ This means that each event has access to the following information:
389
392
:method: `Symfony\\ Component\\ Workflow\\ Event\\ Event::getWorkflowName `
390
393
Returns a string with the name of the workflow that triggered the event.
391
394
395
+ :method: `Symfony\\ Component\\ Workflow\\ Event\\ Event::getMetadata `
396
+ Returns a metadata.
397
+
392
398
For Guard Events, there is an extended class :class: `Symfony\\ Component\\ Workflow\\ Event\\ GuardEvent `.
393
399
This class has two more methods:
394
400
@@ -398,6 +404,13 @@ This class has two more methods:
398
404
:method: `Symfony\\ Component\\ Workflow\\ Event\\ GuardEvent::setBlocked `
399
405
Sets the blocked value.
400
406
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
+
401
414
.. _workflow-blocking-transitions :
402
415
403
416
Blocking Transitions
@@ -426,16 +439,61 @@ transition. The value of this option is any valid expression created with the
426
439
from : draft
427
440
to : reviewed
428
441
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"
430
443
guard : " is_authenticated"
431
444
from : reviewed
432
445
to : published
433
446
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 ()"
436
449
from : reviewed
437
450
to : rejected
438
451
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
+
439
497
Usage in Twig
440
498
-------------
441
499
@@ -458,15 +516,15 @@ The following example shows these functions in action:
458
516
459
517
.. code-block :: html+twig
460
518
461
- <h3>Actions</h3>
519
+ <h3>Actions on Blog Post </h3>
462
520
{% if workflow_can(post, 'publish') %}
463
- <a href="...">Publish article </a>
521
+ <a href="...">Publish</a>
464
522
{% endif %}
465
523
{% if workflow_can(post, 'to_review') %}
466
524
<a href="...">Submit to review</a>
467
525
{% endif %}
468
526
{% if workflow_can(post, 'reject') %}
469
- <a href="...">Reject article </a>
527
+ <a href="...">Reject</a>
470
528
{% endif %}
471
529
472
530
{# Or loop through the enabled transitions #}
@@ -482,8 +540,8 @@ The following example shows these functions in action:
482
540
{% endif %}
483
541
484
542
{# 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>
487
545
{% endif %}
488
546
489
547
Storing Metadata
@@ -520,7 +578,12 @@ requires:
520
578
to : review
521
579
metadata :
522
580
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.'
524
587
525
588
.. code-block :: xml
526
589
@@ -551,7 +614,14 @@ requires:
551
614
<framework : priority >0.5</framework : priority >
552
615
</framework : metadata >
553
616
</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 >
555
625
</framework : workflow >
556
626
</framework : config >
557
627
</container >
@@ -583,6 +653,14 @@ requires:
583
653
'priority' => 0.5,
584
654
],
585
655
],
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
+ ],
586
664
],
587
665
],
588
666
],
@@ -591,27 +669,29 @@ requires:
591
669
Then you can access this metadata in your controller as follows::
592
670
593
671
use Symfony\Component\Workflow\Registry;
672
+ use App\Entity\BlogPost;
594
673
595
- public function myController(Registry $registry, Article $article )
674
+ public function myController(Registry $registry, BlogPost $post )
596
675
{
597
- $workflow = $registry->get($article );
676
+ $workflow = $registry->get($post );
598
677
599
678
$title = $workflow
600
679
->getMetadataStore()
601
- ->getWorkflowMetadata()['title'] ?? false
680
+ ->getWorkflowMetadata()['title'] ?? 'Default title'
602
681
;
603
682
604
683
// or
605
684
$aTransition = $workflow->getDefinition()->getTransitions()[0];
606
685
$transitionTitle = $workflow
607
686
->getMetadataStore()
608
- ->getTransitionMetadata($aTransition)['title '] ?? false
687
+ ->getTransitionMetadata($aTransition)['priority '] ?? 0
609
688
;
610
689
}
611
690
612
- There is a shortcut that works with everything ::
691
+ There is a shortcut that works with every metadata level ::
613
692
614
693
$title = $workflow->getMetadataStore()->getMetadata('title');
694
+ $priority = $workflow->getMetadataStore()->getMetadata('priority');
615
695
616
696
In a :ref: `flash message <flash-messages >` in your controller::
617
697
@@ -621,76 +701,35 @@ In a :ref:`flash message <flash-messages>` in your controller::
621
701
$title = $workflow->getMetadataStore()->getMetadata('title', $transition);
622
702
$this->addFlash('info', "You have successfully applied the transition with title: '$title'");
623
703
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.
666
705
667
706
In Twig templates, metadata is available via the ``workflow_metadata() `` function:
668
707
669
708
.. code-block :: html+twig
670
709
671
- <h2>Metadata</h2>
710
+ <h2>Metadata of Blog Post </h2>
672
711
<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>
675
714
</p>
676
715
<p>
677
716
<strong>Current place(s)</strong>
678
717
<ul>
679
- {% for place in workflow_marked_places(article ) %}
718
+ {% for place in workflow_marked_places(blog_post ) %}
680
719
<li>
681
720
{{ 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>
683
722
</li>
684
723
{% endfor %}
685
724
</ul>
686
725
</p>
687
726
<p>
688
727
<strong>Enabled transition(s)</strong>
689
728
<ul>
690
- {% for transition in workflow_transitions(article ) %}
729
+ {% for transition in workflow_transitions(blog_post ) %}
691
730
<li>
692
731
{{ transition.name }}:
693
- <code>{{ workflow_metadata(article , 'priority', transition) ?: '0' }}</code>
732
+ <code>{{ workflow_metadata(blog_post , 'priority', transition) ?: '0' }}</code>
694
733
</li>
695
734
{% endfor %}
696
735
</ul>
0 commit comments