Skip to content

Commit f3962d4

Browse files
committed
feature #37815 [Workflow] Choose which Workflow events should be dispatched (stewartmalik, lyrixx)
This PR was merged into the 5.2-dev branch. Discussion ---------- [Workflow] Choose which Workflow events should be dispatched | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #36633 ; Fix #36617 | License | MIT | Doc PR | Commits ------- cfc53ad [Workflow] Choose which Workflow events should be dispatched (fix previous commit) d700747 [Workflow] Choose which Workflow events should be dispatched
2 parents da60fbe + cfc53ad commit f3962d4

14 files changed

+399
-10
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

+41
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use Symfony\Component\Translation\Translator;
3535
use Symfony\Component\Validator\Validation;
3636
use Symfony\Component\WebLink\HttpHeaderSerializer;
37+
use Symfony\Component\Workflow\WorkflowEvents;
3738

3839
/**
3940
* FrameworkExtension configuration structure.
@@ -339,6 +340,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
339340
->fixXmlConfig('support')
340341
->fixXmlConfig('place')
341342
->fixXmlConfig('transition')
343+
->fixXmlConfig('event_to_dispatch', 'events_to_dispatch')
342344
->children()
343345
->arrayNode('audit_trail')
344346
->canBeEnabled()
@@ -381,6 +383,33 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
381383
->defaultValue([])
382384
->prototype('scalar')->end()
383385
->end()
386+
->variableNode('events_to_dispatch')
387+
->defaultValue(null)
388+
->validate()
389+
->ifTrue(function ($v) {
390+
if (null === $v) {
391+
return false;
392+
}
393+
if (!\is_array($v)) {
394+
return true;
395+
}
396+
397+
foreach ($v as $value) {
398+
if (!\is_string($value)) {
399+
return true;
400+
}
401+
if (class_exists(WorkflowEvents::class) && !\in_array($value, WorkflowEvents::ALIASES)) {
402+
return true;
403+
}
404+
}
405+
406+
return false;
407+
})
408+
->thenInvalid('The value must be "null" or an array of workflow events (like ["workflow.enter"]).')
409+
->end()
410+
->info('Select which Transition events should be dispatched for this Workflow')
411+
->example(['workflow.enter', 'workflow.transition'])
412+
->end()
384413
->arrayNode('places')
385414
->beforeNormalization()
386415
->always()
@@ -509,6 +538,18 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
509538
})
510539
->thenInvalid('"supports" or "support_strategy" should be configured.')
511540
->end()
541+
->beforeNormalization()
542+
->always()
543+
->then(function ($values) {
544+
// Special case to deal with XML when the user wants an empty array
545+
if (\array_key_exists('event_to_dispatch', $values) && null === $values['event_to_dispatch']) {
546+
$values['events_to_dispatch'] = [];
547+
unset($values['event_to_dispatch']);
548+
}
549+
550+
return $values;
551+
})
552+
->end()
512553
->end()
513554
->end()
514555
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

+1
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
772772
$workflowDefinition->replaceArgument(1, $markingStoreDefinition);
773773
}
774774
$workflowDefinition->replaceArgument(3, $name);
775+
$workflowDefinition->replaceArgument(4, $workflow['events_to_dispatch']);
775776

776777
// Store to container
777778
$container->setDefinition($workflowId, $workflowDefinition);

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

+14
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@
288288
<xsd:element name="initial-marking" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
289289
<xsd:element name="marking-store" type="marking_store" minOccurs="0" maxOccurs="1" />
290290
<xsd:element name="support" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
291+
<xsd:element name="event-to-dispatch" type="event_to_dispatch" minOccurs="0" maxOccurs="unbounded" />
291292
<xsd:element name="place" type="place" minOccurs="0" maxOccurs="unbounded" />
292293
<xsd:element name="transition" type="transition" minOccurs="0" maxOccurs="unbounded" />
293294
<xsd:element name="metadata" type="metadata" minOccurs="0" maxOccurs="unbounded" />
@@ -345,6 +346,19 @@
345346
</xsd:sequence>
346347
</xsd:complexType>
347348

349+
<xsd:simpleType name="event_to_dispatch">
350+
<xsd:restriction base="xsd:string">
351+
<xsd:enumeration value="" />
352+
<xsd:enumeration value="workflow.leave" />
353+
<xsd:enumeration value="workflow.leave" />
354+
<xsd:enumeration value="workflow.transition" />
355+
<xsd:enumeration value="workflow.enter" />
356+
<xsd:enumeration value="workflow.entered" />
357+
<xsd:enumeration value="workflow.completed" />
358+
<xsd:enumeration value="workflow.announce" />
359+
</xsd:restriction>
360+
</xsd:simpleType>
361+
348362
<xsd:simpleType name="default_middleware">
349363
<xsd:restriction base="xsd:string">
350364
<xsd:enumeration value="true" />

src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
abstract_arg('marking store'),
2626
service('event_dispatcher')->ignoreOnInvalid(),
2727
abstract_arg('workflow name'),
28+
abstract_arg('events to dispatch'),
2829
])
2930
->abstract()
3031
->public()
@@ -34,6 +35,7 @@
3435
abstract_arg('marking store'),
3536
service('event_dispatcher')->ignoreOnInvalid(),
3637
abstract_arg('workflow name'),
38+
abstract_arg('events to dispatch'),
3739
])
3840
->abstract()
3941
->public()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest;
4+
5+
$container->loadFromExtension('framework', [
6+
'workflows' => [
7+
'my_workflow' => [
8+
'type' => 'state_machine',
9+
'marking_store' => [
10+
'type' => 'method',
11+
'property' => 'state'
12+
],
13+
'supports' => [
14+
FrameworkExtensionTest::class,
15+
],
16+
'events_to_dispatch' => [],
17+
'places' => [
18+
'one',
19+
'two',
20+
'three',
21+
],
22+
'transitions' => [
23+
'count_to_two' => [
24+
'from' => [
25+
'one',
26+
],
27+
'to' => [
28+
'two',
29+
],
30+
],
31+
'count_to_three' => [
32+
'from' => [
33+
'two',
34+
],
35+
'to' => [
36+
'three'
37+
]
38+
]
39+
],
40+
],
41+
],
42+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest;
4+
5+
$container->loadFromExtension('framework', [
6+
'workflows' => [
7+
'my_workflow' => [
8+
'type' => 'state_machine',
9+
'marking_store' => [
10+
'type' => 'method',
11+
'property' => 'state'
12+
],
13+
'supports' => [
14+
FrameworkExtensionTest::class,
15+
],
16+
'events_to_dispatch' => [
17+
'workflow.leave',
18+
'workflow.completed',
19+
],
20+
'places' => [
21+
'one',
22+
'two',
23+
'three',
24+
],
25+
'transitions' => [
26+
'count_to_two' => [
27+
'from' => [
28+
'one',
29+
],
30+
'to' => [
31+
'two',
32+
],
33+
],
34+
'count_to_three' => [
35+
'from' => [
36+
'two',
37+
],
38+
'to' => [
39+
'three'
40+
]
41+
]
42+
],
43+
],
44+
],
45+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:framework="http://symfony.com/schema/dic/symfony"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
7+
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
8+
9+
<framework:config>
10+
<framework:workflow name="my_workflow" type="state_machine">
11+
<framework:initial-marking>one</framework:initial-marking>
12+
<framework:marking-store type="method" property="state" />
13+
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
14+
<framework:event-to-dispatch></framework:event-to-dispatch>
15+
<framework:place name="one" />
16+
<framework:place name="two" />
17+
<framework:place name="three" />
18+
<framework:transition name="count_to_two">
19+
<framework:from>one</framework:from>
20+
<framework:to>two</framework:to>
21+
</framework:transition>
22+
<framework:transition name="count_to_three">
23+
<framework:from>two</framework:from>
24+
<framework:to>three</framework:to>
25+
</framework:transition>
26+
</framework:workflow>
27+
</framework:config>
28+
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:framework="http://symfony.com/schema/dic/symfony"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
7+
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
8+
9+
<framework:config>
10+
<framework:workflow name="my_workflow" type="state_machine">
11+
<framework:initial-marking>one</framework:initial-marking>
12+
<framework:marking-store type="method" property="state" />
13+
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
14+
<framework:event-to-dispatch>workflow.leave</framework:event-to-dispatch>
15+
<framework:event-to-dispatch>workflow.completed</framework:event-to-dispatch>
16+
<framework:place name="one" />
17+
<framework:place name="two" />
18+
<framework:place name="three" />
19+
<framework:transition name="count_to_two">
20+
<framework:from>one</framework:from>
21+
<framework:to>two</framework:to>
22+
</framework:transition>
23+
<framework:transition name="count_to_three">
24+
<framework:from>two</framework:from>
25+
<framework:to>three</framework:to>
26+
</framework:transition>
27+
</framework:workflow>
28+
</framework:config>
29+
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
framework:
2+
workflows:
3+
my_workflow:
4+
type: state_machine
5+
initial_marking: one
6+
events_to_dispatch: []
7+
marking_store:
8+
type: method
9+
property: state
10+
supports:
11+
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
12+
places:
13+
- one
14+
- two
15+
- three
16+
transitions:
17+
count_to_two:
18+
from: one
19+
to: two
20+
count_to_three:
21+
from: two
22+
to: three
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
framework:
2+
workflows:
3+
my_workflow:
4+
type: state_machine
5+
initial_marking: one
6+
events_to_dispatch: ['workflow.leave', 'workflow.completed']
7+
marking_store:
8+
type: method
9+
property: state
10+
supports:
11+
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
12+
places:
13+
- one
14+
- two
15+
- three
16+
transitions:
17+
count_to_two:
18+
from: one
19+
to: two
20+
count_to_three:
21+
from: two
22+
to: three

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

+21
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
5656
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
5757
use Symfony\Component\Workflow;
58+
use Symfony\Component\Workflow\WorkflowEvents;
5859

5960
abstract class FrameworkExtensionTest extends TestCase
6061
{
@@ -216,6 +217,8 @@ public function testWorkflows()
216217

217218
$this->assertTrue($container->hasDefinition('workflow.article'), 'Workflow is registered as a service');
218219
$this->assertSame('workflow.abstract', $container->getDefinition('workflow.article')->getParent());
220+
$this->assertNull($container->getDefinition('workflow.article')->getArgument('index_4'), 'Workflows has eventsToDispatch=null');
221+
219222
$this->assertTrue($container->hasDefinition('workflow.article.definition'), 'Workflow definition is registered as a service');
220223

221224
$workflowDefinition = $container->getDefinition('workflow.article.definition');
@@ -423,6 +426,24 @@ public function testWorkflowsNamedExplicitlyEnabled()
423426
$this->assertTrue($container->hasDefinition('workflow.workflows.definition'));
424427
}
425428

429+
public function testWorkflowsWithNoDispatchedEvents()
430+
{
431+
$container = $this->createContainerFromFile('workflow_with_no_events_to_dispatch');
432+
433+
$eventsToDispatch = $container->getDefinition('state_machine.my_workflow')->getArgument('index_4');
434+
435+
$this->assertSame([], $eventsToDispatch);
436+
}
437+
438+
public function testWorkflowsWithSpecifiedDispatchedEvents()
439+
{
440+
$container = $this->createContainerFromFile('workflow_with_specified_events_to_dispatch');
441+
442+
$eventsToDispatch = $container->getDefinition('state_machine.my_workflow')->getArgument('index_4');
443+
444+
$this->assertSame([WorkflowEvents::LEAVE, WorkflowEvents::COMPLETED], $eventsToDispatch);
445+
}
446+
426447
public function testEnabledPhpErrorsConfig()
427448
{
428449
$container = $this->createContainerFromFile('php_errors_enabled');

src/Symfony/Component/Workflow/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Added context to the event dispatched
99
* Dispatch an event when the subject enters in the workflow for the very first time
1010
* Added a default context to the previous event
11+
* Added support for specifying which events should be dispatched when calling `workflow->apply()`
1112

1213
5.1.0
1314
-----

0 commit comments

Comments
 (0)