Skip to content

Commit e1c0e04

Browse files
committed
Document 4.3 marking_store changes. Have reservations from a DX perspective, see https://github.com/symfony/symfony/pull/30551/files#r268391471
1 parent f04ac90 commit e1c0e04

File tree

1 file changed

+17
-161
lines changed

1 file changed

+17
-161
lines changed

workflow/usage.rst

Lines changed: 17 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ like this:
4343
audit_trail:
4444
enabled: true
4545
marking_store:
46-
type: 'multiple_state' # one of 'single_state', 'multiple_state', 'method'
46+
type: 'method'
4747
arguments:
48+
- false
4849
- 'currentPlace'
4950
supports:
5051
- App\Entity\BlogPost
@@ -68,7 +69,7 @@ like this:
6869
.. code-block:: xml
6970
7071
<!-- config/packages/workflow.xml -->
71-
<?xml version="1.0" encoding="UTF-8" ?>
72+
<?xml version="1.0" encoding="utf-8" ?>
7273
<container xmlns="http://symfony.com/schema/dic/services"
7374
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
7475
xmlns:framework="http://symfony.com/schema/dic/symfony"
@@ -80,7 +81,8 @@ like this:
8081
<framework:workflow name="blog_publishing" type="workflow">
8182
<framework:audit-trail enabled="true"/>
8283
83-
<framework:marking-store type="single_state">
84+
<framework:marking-store type="method">
85+
<framework:argument>false</framework:argument>
8486
<framework:argument>currentPlace</framework:argument>
8587
</framework:marking-store>
8688
@@ -117,6 +119,7 @@ like this:
117119
.. code-block:: php
118120
119121
// config/packages/workflow.php
122+
120123
$container->loadFromExtension('framework', [
121124
// ...
122125
'workflows' => [
@@ -126,8 +129,11 @@ like this:
126129
'enabled' => true
127130
],
128131
'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+
],
131137
],
132138
'supports' => ['App\Entity\BlogPost'],
133139
'places' => [
@@ -166,18 +172,14 @@ As configured, the following property is used by the marking store::
166172

167173
.. note::
168174

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``.
176178

177179
.. tip::
178180

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.
181183
If omitted, their default values will be used.
182184

183185
.. tip::
@@ -224,90 +226,11 @@ you can get the workflow by injecting the Workflow registry service::
224226
// ... if the transition is not allowed
225227
}
226228

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-
237229
// See all the available transitions for the post in the current state
238230
$transitions = $workflow->getEnabledTransitions($post);
239231
}
240232
}
241233

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-
311234
Using Events
312235
------------
313236

@@ -455,7 +378,7 @@ See example to make sure no blog post without title is moved to "review"::
455378
{
456379
public function guardReview(GuardEvent $event)
457380
{
458-
/** @var App\Entity\BlogPost $post */
381+
/** @var \App\Entity\BlogPost $post */
459382
$post = $event->getSubject();
460383
$title = $post->title;
461384

@@ -549,70 +472,3 @@ The following example shows these functions in action:
549472
{% if 'waiting_some_approval' in workflow_marked_places(post) %}
550473
<span class="label">PENDING</span>
551474
{% 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

Comments
 (0)