@@ -43,8 +43,9 @@ like this:
43
43
audit_trail :
44
44
enabled : true
45
45
marking_store :
46
- type : ' multiple_state ' # one of 'single_state', 'multiple_state', ' method'
46
+ type : ' method'
47
47
arguments :
48
+ - false
48
49
- ' currentPlace'
49
50
supports :
50
51
- App\Entity\BlogPost
@@ -68,7 +69,7 @@ like this:
68
69
.. code-block :: xml
69
70
70
71
<!-- config/packages/workflow.xml -->
71
- <?xml version =" 1.0" encoding =" UTF -8" ?>
72
+ <?xml version =" 1.0" encoding =" utf -8" ?>
72
73
<container xmlns =" http://symfony.com/schema/dic/services"
73
74
xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
74
75
xmlns : framework =" http://symfony.com/schema/dic/symfony"
@@ -80,7 +81,8 @@ like this:
80
81
<framework : workflow name =" blog_publishing" type =" workflow" >
81
82
<framework : audit-trail enabled =" true" />
82
83
83
- <framework : marking-store type =" single_state" >
84
+ <framework : marking-store type =" method" >
85
+ <framework : argument >false</framework : argument >
84
86
<framework : argument >currentPlace</framework : argument >
85
87
</framework : marking-store >
86
88
@@ -117,6 +119,7 @@ like this:
117
119
.. code-block :: php
118
120
119
121
// config/packages/workflow.php
122
+
120
123
$container->loadFromExtension('framework', [
121
124
// ...
122
125
'workflows' => [
@@ -126,8 +129,11 @@ like this:
126
129
'enabled' => true
127
130
],
128
131
'marking_store' => [
129
- 'type' => 'multiple_state', // one of 'single_state', 'multiple_state', 'method'
130
- 'arguments' => ['currentPlace'],
132
+ 'type' => 'method',
133
+ 'arguments' => [
134
+ false,
135
+ 'currentPlace',
136
+ ],
131
137
],
132
138
'supports' => ['App\Entity\BlogPost'],
133
139
'places' => [
@@ -166,18 +172,14 @@ As configured, the following property is used by the marking store::
166
172
167
173
.. note ::
168
174
169
- The marking store type could be "multiple_state", "single_state" or "method".
170
- A single state marking store does not support a model being on multiple places
171
- at the same time.
172
-
173
- versionadded:: 4.3
174
-
175
- The ``method `` marking store type was introduced in Symfony 4.3.
175
+ The Workflow Component supports workflows that can be in one or multiple places
176
+ (states) at the same time. To restrict a workflow to a single state, set the first
177
+ argument to ``true `` when defining the ``marking_store ``.
176
178
177
179
.. tip ::
178
180
179
- The ``type `` (default value ``single_state ``) and ``arguments `` (default
180
- value ``marking ``) attributes of the ``marking_store `` option are optional.
181
+ The ``type `` (default value ``method ``) and ``arguments `` (default
182
+ values `` false `` and ``marking ``) attributes of the ``marking_store `` option are optional.
181
183
If omitted, their default values will be used.
182
184
183
185
.. tip ::
@@ -224,90 +226,11 @@ you can get the workflow by injecting the Workflow registry service::
224
226
// ... if the transition is not allowed
225
227
}
226
228
227
- // Update the currentState on the post passing some contextual data
228
- // to the whole workflow process
229
- try {
230
- $workflow->apply($post, 'publish', [
231
- 'log_comment' => 'My logging comment for the publish transition.',
232
- ]);
233
- } catch (TransitionException $exception) {
234
- // ... if the transition is not allowed
235
- }
236
-
237
229
// See all the available transitions for the post in the current state
238
230
$transitions = $workflow->getEnabledTransitions($post);
239
231
}
240
232
}
241
233
242
- .. versionadded :: 4.1
243
-
244
- The :class: `Symfony\\ Component\\ Workflow\\ Exception\\ TransitionException `
245
- class was introduced in Symfony 4.1.
246
-
247
- .. versionadded :: 4.1
248
-
249
- The :method: `Symfony\\ Component\\ Workflow\\ Registry::all ` method was
250
- introduced in Symfony 4.1.
251
-
252
- You can pass some context as the second argument of the ``apply() `` method.
253
- This can be useful when the subject not only needs to apply a transition,
254
- but for example you also want to log the context in which the switch happened.
255
-
256
- This context is forwarded to the :method: `Symfony\\ Component\\ Workflow\\ MarkingStore\\ MarkingStoreInterface::setMarking `
257
- method of the marking store.
258
-
259
- .. versionadded :: 4.3
260
-
261
- The ``$context `` argument of the :method: `Symfony\\ Component\\ Workflow\\ Workflow::apply `
262
- method was introduced in Symfony 4.3.
263
-
264
- .. tip ::
265
-
266
- Configure the ``type `` as ``method `` of the ``marking_store `` option to use this feature
267
- without implementing your own marking store.
268
-
269
- You can also use this ``$context `` in your own marking store implementation.
270
- A simple implementation example is when you want to store the place as integer instead of string in your object.
271
-
272
- Lets say your object has a status property, stored as an integer in your storage, and you want to log an optional
273
- comment any time the status changes::
274
-
275
- // your own implementation class, to define in the configuration "marking_store"
276
-
277
- class ObjectMarkingStore implements MarkingStoreInterface
278
- {
279
- public function getMarking($subject)
280
- {
281
- $subject->getStatus();
282
- // ...
283
- // return a marking
284
- }
285
-
286
- public function setMarking($subject, Marking $marking, array $context);
287
- {
288
- // ...
289
- $subject->setStatus($newStatus, $context['log_comment'] ?? null);
290
- }
291
- }
292
-
293
- // and in your Object class
294
-
295
- public function getStatus()
296
- {
297
- return $this->status;
298
- }
299
-
300
- public function setStatus(int $status, ?string $comment = null)
301
- {
302
- $this->status = $status;
303
- $this->addStatusLogRecord(new StatusLog($this, $comment));
304
-
305
- return $this;
306
- }
307
-
308
- // the StatusLog class can have a createdAt, a username,
309
- // the new status, and finally your optional comment retrieved from the workflow context.
310
-
311
234
Using Events
312
235
------------
313
236
@@ -455,7 +378,7 @@ See example to make sure no blog post without title is moved to "review"::
455
378
{
456
379
public function guardReview(GuardEvent $event)
457
380
{
458
- /** @var App\Entity\BlogPost $post */
381
+ /** @var \ App\Entity\BlogPost $post */
459
382
$post = $event->getSubject();
460
383
$title = $post->title;
461
384
@@ -549,70 +472,3 @@ The following example shows these functions in action:
549
472
{% if 'waiting_some_approval' in workflow_marked_places(post) %}
550
473
<span class="label">PENDING</span>
551
474
{% endif %}
552
-
553
- Transition Blockers
554
- -------------------
555
-
556
- .. versionadded :: 4.1
557
-
558
- Transition Blockers were introduced in Symfony 4.1.
559
-
560
- Transition Blockers provide a way to return a human-readable message for why a
561
- transition was blocked::
562
-
563
- use Symfony\Component\Workflow\Event\GuardEvent;
564
- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
565
-
566
- class BlogPostPublishListener implements EventSubscriberInterface
567
- {
568
- public function guardPublish(GuardEvent $event)
569
- {
570
- /** @var \App\Entity\BlogPost $post */
571
- $post = $event->getSubject();
572
-
573
- // If it's after 9pm, prevent publication
574
- if (date('H') > 21) {
575
- $event->addTransitionBlocker(
576
- new TransitionBlocker(
577
- "You can not publish this blog post because it's too late. Try again tomorrow morning."
578
- )
579
- );
580
- }
581
- }
582
-
583
- public static function getSubscribedEvents()
584
- {
585
- return [
586
- 'workflow.blogpost.guard.publish' => ['guardPublish'],
587
- ];
588
- }
589
- }
590
-
591
- You can access the message from a Twig template as follows:
592
-
593
- .. code-block :: html+twig
594
-
595
- <h2>Publication was blocked because:</h2>
596
- <ul>
597
- {% for transition in workflow_all_transitions(article) %}
598
- {% if not workflow_can(article, transition.name) %}
599
- <li>
600
- <strong>{{ transition.name }}</strong>:
601
- <ul>
602
- {% for blocker in workflow_build_transition_blocker_list(article, transition.name) %}
603
- <li>
604
- {{ blocker.message }}
605
- {% if blocker.parameters.expression is defined %}
606
- <code>{{ blocker.parameters.expression }}</code>
607
- {% endif %}
608
- </li>
609
- {% endfor %}
610
- </ul>
611
- </li>
612
- {% endif %}
613
- {% endfor %}
614
- </ul>
615
-
616
- Don't need a human-readable message? You can still use::
617
-
618
- $event->setBlocked('true');
0 commit comments