From d70074753cd9c13c33d85f2e6c1a6b30d4eed904 Mon Sep 17 00:00:00 2001 From: Stewart Malik Date: Wed, 12 Aug 2020 16:21:28 +0200 Subject: [PATCH 1/2] [Workflow] Choose which Workflow events should be dispatched --- .../DependencyInjection/Configuration.php | 17 +++++ .../FrameworkExtension.php | 12 +++ .../Resources/config/schema/symfony-1.0.xsd | 14 ++++ .../workflow_with_all_dispatched_events.php | 41 ++++++++++ .../workflow_with_no_dispatched_events.php | 42 ++++++++++ ...kflow_with_specified_dispatched_events.php | 45 +++++++++++ .../workflow_with_all_dispatched_events.xml | 27 +++++++ .../workflow_with_no_dispatched_events.xml | 28 +++++++ ...kflow_with_specified_dispatched_events.xml | 29 +++++++ .../workflow_with_all_dispatched_events.yml | 21 +++++ .../workflow_with_no_dispatched_events.yml | 22 ++++++ ...kflow_with_specified_dispatched_events.yml | 22 ++++++ .../FrameworkExtensionTest.php | 31 ++++++++ src/Symfony/Component/Workflow/CHANGELOG.md | 2 +- src/Symfony/Component/Workflow/Definition.php | 19 ++++- .../Component/Workflow/DefinitionBuilder.php | 14 +++- .../Workflow/Tests/DefinitionBuilderTest.php | 29 +++++++ .../Workflow/Tests/DefinitionTest.php | 27 +++++++ .../Component/Workflow/Tests/WorkflowTest.php | 50 ++++++++---- src/Symfony/Component/Workflow/Workflow.php | 76 ++++++++++++------- .../Component/Workflow/WorkflowEvents.php | 5 ++ 21 files changed, 529 insertions(+), 44 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0ba78c5345a0..8f43295ab7a9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -339,6 +339,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->fixXmlConfig('support') ->fixXmlConfig('place') ->fixXmlConfig('transition') + ->fixXmlConfig('dispatched_event') ->children() ->arrayNode('audit_trail') ->canBeEnabled() @@ -381,6 +382,22 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->defaultValue([]) ->prototype('scalar')->end() ->end() + ->arrayNode('dispatched_events') + ->beforeNormalization() + ->ifString() + ->then(function ($v) { + return [$v]; + }) + ->end() + // We have to specify a default here as when this config option + // isn't set the default behaviour of `arrayNode()` is to return an empty + // array which conflicts with our Definition, and we cannot set a default + // of `null` for arrayNode()'s + ->defaultValue(['all']) + ->prototype('scalar')->end() + ->info('Select which Transition events should be dispatched for this Workflow') + ->example(['leave', 'completed']) + ->end() ->arrayNode('places') ->beforeNormalization() ->always() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 40f5e96e133a..4ffbfc1b2cff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -742,6 +742,17 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $places = array_column($workflow['places'], 'name'); $initialMarking = $workflow['initial_marking'] ?? []; + // Record which events should be dispatched + if ($workflow['dispatched_events'] === ['all']) { + $dispatchedEvents = null; + } elseif ($workflow['dispatched_events'] === ['none']) { + $dispatchedEvents = []; + } else { + $dispatchedEvents = array_map(function (string $event) { + return 'workflow.'.$event; + }, $workflow['dispatched_events']); + } + // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); @@ -749,6 +760,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $definitionDefinition->addArgument($transitions); $definitionDefinition->addArgument($initialMarking); $definitionDefinition->addArgument($metadataStoreDefinition); + $definitionDefinition->addArgument($dispatchedEvents); $definitionDefinition->addTag('workflow.definition', [ 'name' => $name, 'type' => $type, diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 526cf1970e08..5c6f052e2938 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -288,6 +288,7 @@ + @@ -345,6 +346,19 @@ + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php new file mode 100644 index 000000000000..0016479f95c3 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php @@ -0,0 +1,41 @@ +loadFromExtension('framework', [ + 'workflows' => [ + 'my_workflow' => [ + 'type' => 'state_machine', + 'marking_store' => [ + 'type' => 'method', + 'property' => 'state' + ], + 'supports' => [ + FrameworkExtensionTest::class, + ], + 'places' => [ + 'one', + 'two', + 'three', + ], + 'transitions' => [ + 'count_to_two' => [ + 'from' => [ + 'one', + ], + 'to' => [ + 'two', + ], + ], + 'count_to_three' => [ + 'from' => [ + 'two', + ], + 'to' => [ + 'three' + ] + ] + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php new file mode 100644 index 000000000000..eb8c6fd81c5f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php @@ -0,0 +1,42 @@ +loadFromExtension('framework', [ + 'workflows' => [ + 'my_workflow' => [ + 'type' => 'state_machine', + 'marking_store' => [ + 'type' => 'method', + 'property' => 'state' + ], + 'supports' => [ + FrameworkExtensionTest::class, + ], + 'dispatched_events' => [], + 'places' => [ + 'one', + 'two', + 'three', + ], + 'transitions' => [ + 'count_to_two' => [ + 'from' => [ + 'one', + ], + 'to' => [ + 'two', + ], + ], + 'count_to_three' => [ + 'from' => [ + 'two', + ], + 'to' => [ + 'three' + ] + ] + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php new file mode 100644 index 000000000000..8211bcc99710 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php @@ -0,0 +1,45 @@ +loadFromExtension('framework', [ + 'workflows' => [ + 'my_workflow' => [ + 'type' => 'state_machine', + 'marking_store' => [ + 'type' => 'method', + 'property' => 'state' + ], + 'supports' => [ + FrameworkExtensionTest::class, + ], + 'dispatched_events' => [ + 'leave', + 'completed' + ], + 'places' => [ + 'one', + 'two', + 'three', + ], + 'transitions' => [ + 'count_to_two' => [ + 'from' => [ + 'one', + ], + 'to' => [ + 'two', + ], + ], + 'count_to_three' => [ + 'from' => [ + 'two', + ], + 'to' => [ + 'three' + ] + ] + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml new file mode 100644 index 000000000000..f95d2a4e8adc --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml @@ -0,0 +1,27 @@ + + + + + + + one + + Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + + + + + one + two + + + two + three + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml new file mode 100644 index 000000000000..39b6fa5bf875 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml @@ -0,0 +1,28 @@ + + + + + + + one + + Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + none + + + + + one + two + + + two + three + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml new file mode 100644 index 000000000000..454d3cd8dba2 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml @@ -0,0 +1,29 @@ + + + + + + + one + + Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + leave + completed + + + + + one + two + + + two + three + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml new file mode 100644 index 000000000000..8c509cff587f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml @@ -0,0 +1,21 @@ +framework: + workflows: + my_workflow: + type: state_machine + initial_marking: one + marking_store: + type: method + property: state + supports: + - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + places: + - one + - two + - three + transitions: + count_to_two: + from: one + to: two + count_to_three: + from: two + to: three diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml new file mode 100644 index 000000000000..c14a0c6c7f91 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml @@ -0,0 +1,22 @@ +framework: + workflows: + my_workflow: + type: state_machine + initial_marking: one + dispatched_events: [] + marking_store: + type: method + property: state + supports: + - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + places: + - one + - two + - three + transitions: + count_to_two: + from: one + to: two + count_to_three: + from: two + to: three diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml new file mode 100644 index 000000000000..80218c11a167 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml @@ -0,0 +1,22 @@ +framework: + workflows: + my_workflow: + type: state_machine + initial_marking: one + dispatched_events: ['leave', 'completed'] + marking_store: + type: method + property: state + supports: + - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + places: + - one + - two + - three + transitions: + count_to_two: + from: one + to: two + count_to_three: + from: two + to: three diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index cfe9f555e77b..7d33cbfedf4d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -55,6 +55,7 @@ use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass; use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader; use Symfony\Component\Workflow; +use Symfony\Component\Workflow\WorkflowEvents; abstract class FrameworkExtensionTest extends TestCase { @@ -423,6 +424,36 @@ public function testWorkflowsNamedExplicitlyEnabled() $this->assertTrue($container->hasDefinition('workflow.workflows.definition')); } + public function testWorkflowsWithAllDispatchedEvents() + { + $container = $this->createContainerFromFile('workflow_with_all_dispatched_events'); + + $workflowDefinition = $container->getDefinition('state_machine.my_workflow.definition'); + $dispatchedEvents = $workflowDefinition->getArgument(4); + + $this->assertNull($dispatchedEvents); + } + + public function testWorkflowsWithNoDispatchedEvents() + { + $container = $this->createContainerFromFile('workflow_with_no_dispatched_events'); + + $workflowDefinition = $container->getDefinition('state_machine.my_workflow.definition'); + $dispatchedEvents = $workflowDefinition->getArgument(4); + + $this->assertSame([], $dispatchedEvents); + } + + public function testWorkflowsWithSpecifiedDispatchedEvents() + { + $container = $this->createContainerFromFile('workflow_with_specified_dispatched_events'); + + $workflowDefinition = $container->getDefinition('state_machine.my_workflow.definition'); + $dispatchedEvents = $workflowDefinition->getArgument(4); + + $this->assertSame([WorkflowEvents::LEAVE, WorkflowEvents::COMPLETED], $dispatchedEvents); + } + public function testEnabledPhpErrorsConfig() { $container = $this->createContainerFromFile('php_errors_enabled'); diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 263f2db5e803..627fabb39763 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -14,7 +14,7 @@ CHANGELOG * Added context to `TransitionException` and its child classes whenever they are thrown in `Workflow::apply()` * Added `Registry::has()` to check if a workflow exists - * Added support for `$context[Workflow::DISABLE_ANNOUNCE_EVENT] = true` when calling `workflow->apply()` to not fire the announce event + * Added support for specifying which events should be dispatched when calling `workflow->apply()` 5.0.0 ----- diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 210e7569579b..2305420bac47 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -22,6 +22,16 @@ */ final class Definition { + /** + * When `null` fire all events (the default behaviour). + * Setting this to an empty array `[]` means no events are dispatched except the Guard Event. + * Passing an array with WorkflowEvents will allow only those events to be dispatched plus + * the Guard Event. + * + * @var array|string[] + */ + private $dispatchedEvents; + private $places = []; private $transitions = []; private $initialPlaces = []; @@ -32,7 +42,7 @@ final class Definition * @param Transition[] $transitions * @param string|string[]|null $initialPlaces */ - public function __construct(array $places, array $transitions, $initialPlaces = null, MetadataStoreInterface $metadataStore = null) + public function __construct(array $places, array $transitions, $initialPlaces = null, MetadataStoreInterface $metadataStore = null, array $dispatchedEvents = null) { foreach ($places as $place) { $this->addPlace($place); @@ -45,6 +55,8 @@ public function __construct(array $places, array $transitions, $initialPlaces = $this->setInitialPlaces($initialPlaces); $this->metadataStore = $metadataStore ?: new InMemoryMetadataStore(); + + $this->dispatchedEvents = $dispatchedEvents ?? WorkflowEvents::getDefaultDispatchedEvents(); } /** @@ -76,6 +88,11 @@ public function getMetadataStore(): MetadataStoreInterface return $this->metadataStore; } + public function getDispatchedEvents(): array + { + return $this->dispatchedEvents; + } + private function setInitialPlaces($places = null) { if (!$places) { diff --git a/src/Symfony/Component/Workflow/DefinitionBuilder.php b/src/Symfony/Component/Workflow/DefinitionBuilder.php index 19e9067edda9..68ee124ed8f8 100644 --- a/src/Symfony/Component/Workflow/DefinitionBuilder.php +++ b/src/Symfony/Component/Workflow/DefinitionBuilder.php @@ -26,6 +26,7 @@ class DefinitionBuilder private $transitions = []; private $initialPlaces; private $metadataStore; + private $dispatchEvents = null; /** * @param string[] $places @@ -42,7 +43,7 @@ public function __construct(array $places = [], array $transitions = []) */ public function build() { - return new Definition($this->places, $this->transitions, $this->initialPlaces, $this->metadataStore); + return new Definition($this->places, $this->transitions, $this->initialPlaces, $this->metadataStore, $this->dispatchEvents); } /** @@ -56,6 +57,7 @@ public function clear() $this->transitions = []; $this->initialPlaces = null; $this->metadataStore = null; + $this->dispatchEvents = null; return $this; } @@ -133,4 +135,14 @@ public function setMetadataStore(MetadataStoreInterface $metadataStore) return $this; } + + /** + * @return $this + */ + public function setDispatchEvents(array $dispatchEvents) + { + $this->dispatchEvents = $dispatchEvents; + + return $this; + } } diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php index c749011e66a0..495892ba011f 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php @@ -6,6 +6,7 @@ use Symfony\Component\Workflow\DefinitionBuilder; use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore; use Symfony\Component\Workflow\Transition; +use Symfony\Component\Workflow\WorkflowEvents; class DefinitionBuilderTest extends TestCase { @@ -55,4 +56,32 @@ public function testSetMetadataStore() $this->assertSame($metadataStore, $definition->getMetadataStore()); } + + public function testCheckDefaultDispatchEvents() + { + $builder = new DefinitionBuilder(['a']); + $definition = $builder->build(); + + $this->assertSame(WorkflowEvents::getDefaultDispatchedEvents(), $definition->getDispatchedEvents()); + } + + public function testSetEmptyDispatchEvents() + { + $builder = new DefinitionBuilder(['a']); + $builder->setDispatchEvents([]); + $definition = $builder->build(); + + $this->assertSame([], $definition->getDispatchedEvents()); + } + + public function testSetSpecificDispatchEvents() + { + $events = [WorkflowEvents::ENTERED, WorkflowEvents::COMPLETED]; + + $builder = new DefinitionBuilder(['a']); + $builder->setDispatchEvents($events); + $definition = $builder->build(); + + $this->assertSame($events, $definition->getDispatchedEvents()); + } } diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php index 6ba3c1ef47f0..66c564a6b283 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php @@ -5,6 +5,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Transition; +use Symfony\Component\Workflow\WorkflowEvents; class DefinitionTest extends TestCase { @@ -69,4 +70,30 @@ public function testAddTransitionAndToPlaceIsNotDefined() new Definition($places, [new Transition('name', $places[0], 'c')]); } + + public function testSetDefaultDispatchEvents() + { + $places = range('a', 'b'); + $definition = new Definition($places, [], null, null, null); + + $this->assertSame(WorkflowEvents::getDefaultDispatchedEvents(), $definition->getDispatchedEvents()); + } + + public function testSetEmptyDispatchEvents() + { + $places = range('a', 'b'); + $definition = new Definition($places, [], null, null, []); + + $this->assertEmpty($definition->getDispatchedEvents()); + } + + public function testSetSpecificDispatchEvents() + { + $events = [WorkflowEvents::ENTERED, WorkflowEvents::COMPLETED]; + + $places = range('a', 'b'); + $definition = new Definition($places, [], null, null, $events); + + $this->assertSame($events, $definition->getDispatchedEvents()); + } } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 85543f928686..8f5793696afb 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\TransitionBlocker; use Symfony\Component\Workflow\Workflow; +use Symfony\Component\Workflow\WorkflowEvents; class WorkflowTest extends TestCase { @@ -427,28 +428,51 @@ public function testApplyWithEventDispatcher() $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); } - public function provideApplyWithEventDispatcherForAnnounceTests() + public function testApplyDispatchesNoEventsWhenSpecifiedByDefinition() { - yield [false, [Workflow::DISABLE_ANNOUNCE_EVENT => true]]; - yield [true, [Workflow::DISABLE_ANNOUNCE_EVENT => false]]; - yield [true, []]; + $transitions[] = new Transition('a-b', 'a', 'b'); + $transitions[] = new Transition('a-c', 'a', 'c'); + $definition = new Definition(['a', 'b', 'c'], $transitions, null, null, []); + + $subject = new Subject(); + $eventDispatcher = new EventDispatcherMock(); + $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name'); + + // Guard and Transition events are still called + $eventNameExpected = [ + 'workflow.guard', + 'workflow.workflow_name.guard', + 'workflow.workflow_name.guard.a-b', + ]; + + $workflow->apply($subject, 'a-b'); + + $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); } - /** @dataProvider provideApplyWithEventDispatcherForAnnounceTests */ - public function testApplyWithEventDispatcherForAnnounce(bool $fired, array $context) + public function testApplyOnlyDispatchesEventsThatHaveBeenSpecifiedByDefinition() { - $definition = $this->createComplexWorkflowDefinition(); + $transitions[] = new Transition('a-b', 'a', 'b'); + $transitions[] = new Transition('a-c', 'a', 'c'); + $definition = new Definition(['a', 'b', 'c'], $transitions, null, null, [WorkflowEvents::COMPLETED]); + $subject = new Subject(); $eventDispatcher = new EventDispatcherMock(); $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name'); - $workflow->apply($subject, 't1', $context); + // Guard and Transition events are still called + $eventNameExpected = [ + 'workflow.guard', + 'workflow.workflow_name.guard', + 'workflow.workflow_name.guard.a-b', + 'workflow.completed', + 'workflow.workflow_name.completed', + 'workflow.workflow_name.completed.a-b', + ]; - if ($fired) { - $this->assertContains('workflow.workflow_name.announce', $eventDispatcher->dispatchedEvents); - } else { - $this->assertNotContains('workflow.workflow_name.announce', $eventDispatcher->dispatchedEvents); - } + $workflow->apply($subject, 'a-b'); + + $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); } public function testApplyDoesNotTriggerExtraGuardWithEventDispatcher() diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 4220c4323391..38e4ece5b7fa 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -215,9 +215,7 @@ public function apply(object $subject, string $transitionName, array $context = $this->completed($subject, $transition, $marking, $context); - if (!($context[self::DISABLE_ANNOUNCE_EVENT] ?? false)) { - $this->announce($subject, $transition, $marking, $context); - } + $this->announce($subject, $transition, $marking, $context); } return $marking; @@ -334,7 +332,7 @@ private function leave(object $subject, Transition $transition, Marking $marking { $places = $transition->getFroms(); - if (null !== $this->dispatcher) { + if ($this->shouldDispatchEvent(WorkflowEvents::LEAVE)) { $event = new LeaveEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::LEAVE); @@ -352,7 +350,7 @@ private function leave(object $subject, Transition $transition, Marking $marking private function transition(object $subject, Transition $transition, Marking $marking, array $context): array { - if (null === $this->dispatcher) { + if (!$this->shouldDispatchEvent(WorkflowEvents::TRANSITION)) { return $context; } @@ -369,7 +367,7 @@ private function enter(object $subject, Transition $transition, Marking $marking { $places = $transition->getTos(); - if (null !== $this->dispatcher) { + if ($this->shouldDispatchEvent(WorkflowEvents::ENTER)) { $event = new EnterEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ENTER); @@ -387,46 +385,68 @@ private function enter(object $subject, Transition $transition, Marking $marking private function entered(object $subject, ?Transition $transition, Marking $marking, array $context): void { - if (null === $this->dispatcher) { - return; - } - - $event = new EnteredEvent($subject, $marking, $transition, $this, $context); + if ($this->shouldDispatchEvent(WorkflowEvents::ENTERED)) { + $event = new EnteredEvent($subject, $marking, $transition, $this, $context); - $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); + $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); - foreach ($marking->getPlaces() as $placeName => $nbToken) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $placeName)); + foreach ($marking->getPlaces() as $placeName => $nbToken) { + $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $placeName)); + } } } private function completed(object $subject, Transition $transition, Marking $marking, array $context): void { - if (null === $this->dispatcher) { - return; + if ($this->shouldDispatchEvent(WorkflowEvents::COMPLETED)) { + $event = new CompletedEvent($subject, $marking, $transition, $this); + + $this->dispatcher->dispatch($event, WorkflowEvents::COMPLETED); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed', $this->name)); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); } + } + + private function announce(object $subject, Transition $initialTransition, Marking $marking): void + { + if ($this->shouldDispatchEvent(WorkflowEvents::ANNOUNCE)) { + $event = new AnnounceEvent($subject, $marking, $initialTransition, $this); - $event = new CompletedEvent($subject, $marking, $transition, $this, $context); + $this->dispatcher->dispatch($event, WorkflowEvents::ANNOUNCE); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce', $this->name)); - $this->dispatcher->dispatch($event, WorkflowEvents::COMPLETED); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed', $this->name)); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); + foreach ($this->getEnabledTransitions($subject) as $transition) { + $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce.%s', $this->name, $transition->getName())); + } + } } - private function announce(object $subject, Transition $initialTransition, Marking $marking, array $context): void + private function shouldDispatchEvent(string $eventName): bool { + // If we don't have a dispatcher we can't dispatch the + // event even if we wanted to if (null === $this->dispatcher) { - return; + return false; } - $event = new AnnounceEvent($subject, $marking, $initialTransition, $this, $context); + $dispatchEvents = $this->getDefinition()->getDispatchedEvents(); - $this->dispatcher->dispatch($event, WorkflowEvents::ANNOUNCE); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce', $this->name)); + // A null value implies all events should be dispatched + if (null === $dispatchEvents) { + return true; + } + + // An empty array implies no events should be dispatched + if ([] === $dispatchEvents) { + return false; + } - foreach ($this->getEnabledTransitions($subject) as $transition) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce.%s', $this->name, $transition->getName())); + // Check if the WorkflowEvent name is in the events that + if (\count($dispatchEvents) >= 1) { + return \in_array($eventName, $dispatchEvents, true); } + + return true; } } diff --git a/src/Symfony/Component/Workflow/WorkflowEvents.php b/src/Symfony/Component/Workflow/WorkflowEvents.php index d64783054069..091a7e03c1ca 100644 --- a/src/Symfony/Component/Workflow/WorkflowEvents.php +++ b/src/Symfony/Component/Workflow/WorkflowEvents.php @@ -78,4 +78,9 @@ final class WorkflowEvents private function __construct() { } + + public static function getDefaultDispatchedEvents(): array + { + return [self::LEAVE, self::TRANSITION, self::ENTER, self::ENTERED, self::COMPLETED, self::ANNOUNCE]; + } } From cfc53ad7328f269aa5ee922ffb0e80f74d4d0492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 12 Aug 2020 16:43:40 +0200 Subject: [PATCH 2/2] [Workflow] Choose which Workflow events should be dispatched (fix previous commit) --- .../DependencyInjection/Configuration.php | 50 ++++++--- .../FrameworkExtension.php | 13 +-- .../Resources/config/schema/symfony-1.0.xsd | 20 ++-- .../Resources/config/workflow.php | 2 + .../workflow_with_no_dispatched_events.php | 42 ------- ...> workflow_with_no_events_to_dispatch.php} | 1 + ...low_with_specified_events_to_dispatch.php} | 6 +- ...> workflow_with_no_events_to_dispatch.xml} | 1 + ...kflow_with_specified_dispatched_events.xml | 29 ----- ...low_with_specified_events_to_dispatch.xml} | 3 +- ...> workflow_with_no_events_to_dispatch.yml} | 1 + ...kflow_with_specified_dispatched_events.yml | 22 ---- ...low_with_specified_events_to_dispatch.yml} | 2 +- .../FrameworkExtensionTest.php | 26 ++--- src/Symfony/Component/Workflow/CHANGELOG.md | 3 +- src/Symfony/Component/Workflow/Definition.php | 19 +--- .../Component/Workflow/DefinitionBuilder.php | 14 +-- .../Workflow/Tests/DefinitionBuilderTest.php | 29 ----- .../Workflow/Tests/DefinitionTest.php | 27 ----- .../Component/Workflow/Tests/WorkflowTest.php | 64 ++++++++++- src/Symfony/Component/Workflow/Workflow.php | 103 +++++++++++------- .../Component/Workflow/WorkflowEvents.php | 5 - 22 files changed, 193 insertions(+), 289 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/{workflow_with_all_dispatched_events.php => workflow_with_no_events_to_dispatch.php} (96%) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/{workflow_with_specified_dispatched_events.php => workflow_with_specified_events_to_dispatch.php} (90%) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{workflow_with_all_dispatched_events.xml => workflow_with_no_events_to_dispatch.xml} (95%) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{workflow_with_no_dispatched_events.xml => workflow_with_specified_events_to_dispatch.xml} (88%) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/{workflow_with_all_dispatched_events.yml => workflow_with_no_events_to_dispatch.yml} (94%) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/{workflow_with_no_dispatched_events.yml => workflow_with_specified_events_to_dispatch.yml} (89%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 8f43295ab7a9..0da222cc2876 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -34,6 +34,7 @@ use Symfony\Component\Translation\Translator; use Symfony\Component\Validator\Validation; use Symfony\Component\WebLink\HttpHeaderSerializer; +use Symfony\Component\Workflow\WorkflowEvents; /** * FrameworkExtension configuration structure. @@ -339,7 +340,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->fixXmlConfig('support') ->fixXmlConfig('place') ->fixXmlConfig('transition') - ->fixXmlConfig('dispatched_event') + ->fixXmlConfig('event_to_dispatch', 'events_to_dispatch') ->children() ->arrayNode('audit_trail') ->canBeEnabled() @@ -382,21 +383,32 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->defaultValue([]) ->prototype('scalar')->end() ->end() - ->arrayNode('dispatched_events') - ->beforeNormalization() - ->ifString() - ->then(function ($v) { - return [$v]; + ->variableNode('events_to_dispatch') + ->defaultValue(null) + ->validate() + ->ifTrue(function ($v) { + if (null === $v) { + return false; + } + if (!\is_array($v)) { + return true; + } + + foreach ($v as $value) { + if (!\is_string($value)) { + return true; + } + if (class_exists(WorkflowEvents::class) && !\in_array($value, WorkflowEvents::ALIASES)) { + return true; + } + } + + return false; }) + ->thenInvalid('The value must be "null" or an array of workflow events (like ["workflow.enter"]).') ->end() - // We have to specify a default here as when this config option - // isn't set the default behaviour of `arrayNode()` is to return an empty - // array which conflicts with our Definition, and we cannot set a default - // of `null` for arrayNode()'s - ->defaultValue(['all']) - ->prototype('scalar')->end() ->info('Select which Transition events should be dispatched for this Workflow') - ->example(['leave', 'completed']) + ->example(['workflow.enter', 'workflow.transition']) ->end() ->arrayNode('places') ->beforeNormalization() @@ -526,6 +538,18 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) }) ->thenInvalid('"supports" or "support_strategy" should be configured.') ->end() + ->beforeNormalization() + ->always() + ->then(function ($values) { + // Special case to deal with XML when the user wants an empty array + if (\array_key_exists('event_to_dispatch', $values) && null === $values['event_to_dispatch']) { + $values['events_to_dispatch'] = []; + unset($values['event_to_dispatch']); + } + + return $values; + }) + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 4ffbfc1b2cff..1c04a0ca7fac 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -742,17 +742,6 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $places = array_column($workflow['places'], 'name'); $initialMarking = $workflow['initial_marking'] ?? []; - // Record which events should be dispatched - if ($workflow['dispatched_events'] === ['all']) { - $dispatchedEvents = null; - } elseif ($workflow['dispatched_events'] === ['none']) { - $dispatchedEvents = []; - } else { - $dispatchedEvents = array_map(function (string $event) { - return 'workflow.'.$event; - }, $workflow['dispatched_events']); - } - // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); @@ -760,7 +749,6 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $definitionDefinition->addArgument($transitions); $definitionDefinition->addArgument($initialMarking); $definitionDefinition->addArgument($metadataStoreDefinition); - $definitionDefinition->addArgument($dispatchedEvents); $definitionDefinition->addTag('workflow.definition', [ 'name' => $name, 'type' => $type, @@ -784,6 +772,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $workflowDefinition->replaceArgument(1, $markingStoreDefinition); } $workflowDefinition->replaceArgument(3, $name); + $workflowDefinition->replaceArgument(4, $workflow['events_to_dispatch']); // Store to container $container->setDefinition($workflowId, $workflowDefinition); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 5c6f052e2938..41208143a7fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -288,7 +288,7 @@ - + @@ -346,16 +346,16 @@ - + - - - - - - - - + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php index 134bb6d33487..6eae2b16c411 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php @@ -25,6 +25,7 @@ abstract_arg('marking store'), service('event_dispatcher')->ignoreOnInvalid(), abstract_arg('workflow name'), + abstract_arg('events to dispatch'), ]) ->abstract() ->public() @@ -34,6 +35,7 @@ abstract_arg('marking store'), service('event_dispatcher')->ignoreOnInvalid(), abstract_arg('workflow name'), + abstract_arg('events to dispatch'), ]) ->abstract() ->public() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php deleted file mode 100644 index eb8c6fd81c5f..000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_dispatched_events.php +++ /dev/null @@ -1,42 +0,0 @@ -loadFromExtension('framework', [ - 'workflows' => [ - 'my_workflow' => [ - 'type' => 'state_machine', - 'marking_store' => [ - 'type' => 'method', - 'property' => 'state' - ], - 'supports' => [ - FrameworkExtensionTest::class, - ], - 'dispatched_events' => [], - 'places' => [ - 'one', - 'two', - 'three', - ], - 'transitions' => [ - 'count_to_two' => [ - 'from' => [ - 'one', - ], - 'to' => [ - 'two', - ], - ], - 'count_to_three' => [ - 'from' => [ - 'two', - ], - 'to' => [ - 'three' - ] - ] - ], - ], - ], -]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_events_to_dispatch.php similarity index 96% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_events_to_dispatch.php index 0016479f95c3..0ae6ac69ee7c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_all_dispatched_events.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_no_events_to_dispatch.php @@ -13,6 +13,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], + 'events_to_dispatch' => [], 'places' => [ 'one', 'two', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_events_to_dispatch.php similarity index 90% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_events_to_dispatch.php index 8211bcc99710..259ee5087ff2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_dispatched_events.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_specified_events_to_dispatch.php @@ -13,9 +13,9 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'dispatched_events' => [ - 'leave', - 'completed' + 'events_to_dispatch' => [ + 'workflow.leave', + 'workflow.completed', ], 'places' => [ 'one', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_events_to_dispatch.xml similarity index 95% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_events_to_dispatch.xml index f95d2a4e8adc..2f563da4bf96 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_all_dispatched_events.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_events_to_dispatch.xml @@ -11,6 +11,7 @@ one Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml deleted file mode 100644 index 454d3cd8dba2..000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_dispatched_events.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - one - - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - leave - completed - - - - - one - two - - - two - three - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_events_to_dispatch.xml similarity index 88% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_events_to_dispatch.xml index 39b6fa5bf875..d442828f8cfb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_no_dispatched_events.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_specified_events_to_dispatch.xml @@ -11,7 +11,8 @@ one Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - none + workflow.leave + workflow.completed diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_events_to_dispatch.yml similarity index 94% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_events_to_dispatch.yml index 8c509cff587f..e0a281f27db4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_all_dispatched_events.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_events_to_dispatch.yml @@ -3,6 +3,7 @@ framework: my_workflow: type: state_machine initial_marking: one + events_to_dispatch: [] marking_store: type: method property: state diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml deleted file mode 100644 index 80218c11a167..000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_dispatched_events.yml +++ /dev/null @@ -1,22 +0,0 @@ -framework: - workflows: - my_workflow: - type: state_machine - initial_marking: one - dispatched_events: ['leave', 'completed'] - marking_store: - type: method - property: state - supports: - - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - places: - - one - - two - - three - transitions: - count_to_two: - from: one - to: two - count_to_three: - from: two - to: three diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_events_to_dispatch.yml similarity index 89% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_events_to_dispatch.yml index c14a0c6c7f91..d5ff3d5e5fe0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_no_dispatched_events.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_specified_events_to_dispatch.yml @@ -3,7 +3,7 @@ framework: my_workflow: type: state_machine initial_marking: one - dispatched_events: [] + events_to_dispatch: ['workflow.leave', 'workflow.completed'] marking_store: type: method property: state diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 7d33cbfedf4d..7818d3c9c798 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -217,6 +217,8 @@ public function testWorkflows() $this->assertTrue($container->hasDefinition('workflow.article'), 'Workflow is registered as a service'); $this->assertSame('workflow.abstract', $container->getDefinition('workflow.article')->getParent()); + $this->assertNull($container->getDefinition('workflow.article')->getArgument('index_4'), 'Workflows has eventsToDispatch=null'); + $this->assertTrue($container->hasDefinition('workflow.article.definition'), 'Workflow definition is registered as a service'); $workflowDefinition = $container->getDefinition('workflow.article.definition'); @@ -424,34 +426,22 @@ public function testWorkflowsNamedExplicitlyEnabled() $this->assertTrue($container->hasDefinition('workflow.workflows.definition')); } - public function testWorkflowsWithAllDispatchedEvents() - { - $container = $this->createContainerFromFile('workflow_with_all_dispatched_events'); - - $workflowDefinition = $container->getDefinition('state_machine.my_workflow.definition'); - $dispatchedEvents = $workflowDefinition->getArgument(4); - - $this->assertNull($dispatchedEvents); - } - public function testWorkflowsWithNoDispatchedEvents() { - $container = $this->createContainerFromFile('workflow_with_no_dispatched_events'); + $container = $this->createContainerFromFile('workflow_with_no_events_to_dispatch'); - $workflowDefinition = $container->getDefinition('state_machine.my_workflow.definition'); - $dispatchedEvents = $workflowDefinition->getArgument(4); + $eventsToDispatch = $container->getDefinition('state_machine.my_workflow')->getArgument('index_4'); - $this->assertSame([], $dispatchedEvents); + $this->assertSame([], $eventsToDispatch); } public function testWorkflowsWithSpecifiedDispatchedEvents() { - $container = $this->createContainerFromFile('workflow_with_specified_dispatched_events'); + $container = $this->createContainerFromFile('workflow_with_specified_events_to_dispatch'); - $workflowDefinition = $container->getDefinition('state_machine.my_workflow.definition'); - $dispatchedEvents = $workflowDefinition->getArgument(4); + $eventsToDispatch = $container->getDefinition('state_machine.my_workflow')->getArgument('index_4'); - $this->assertSame([WorkflowEvents::LEAVE, WorkflowEvents::COMPLETED], $dispatchedEvents); + $this->assertSame([WorkflowEvents::LEAVE, WorkflowEvents::COMPLETED], $eventsToDispatch); } public function testEnabledPhpErrorsConfig() diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 627fabb39763..3d44a3b6e83f 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -8,13 +8,14 @@ CHANGELOG * Added context to the event dispatched * Dispatch an event when the subject enters in the workflow for the very first time * Added a default context to the previous event + * Added support for specifying which events should be dispatched when calling `workflow->apply()` 5.1.0 ----- * Added context to `TransitionException` and its child classes whenever they are thrown in `Workflow::apply()` * Added `Registry::has()` to check if a workflow exists - * Added support for specifying which events should be dispatched when calling `workflow->apply()` + * Added support for `$context[Workflow::DISABLE_ANNOUNCE_EVENT] = true` when calling `workflow->apply()` to not fire the announce event 5.0.0 ----- diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 2305420bac47..210e7569579b 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -22,16 +22,6 @@ */ final class Definition { - /** - * When `null` fire all events (the default behaviour). - * Setting this to an empty array `[]` means no events are dispatched except the Guard Event. - * Passing an array with WorkflowEvents will allow only those events to be dispatched plus - * the Guard Event. - * - * @var array|string[] - */ - private $dispatchedEvents; - private $places = []; private $transitions = []; private $initialPlaces = []; @@ -42,7 +32,7 @@ final class Definition * @param Transition[] $transitions * @param string|string[]|null $initialPlaces */ - public function __construct(array $places, array $transitions, $initialPlaces = null, MetadataStoreInterface $metadataStore = null, array $dispatchedEvents = null) + public function __construct(array $places, array $transitions, $initialPlaces = null, MetadataStoreInterface $metadataStore = null) { foreach ($places as $place) { $this->addPlace($place); @@ -55,8 +45,6 @@ public function __construct(array $places, array $transitions, $initialPlaces = $this->setInitialPlaces($initialPlaces); $this->metadataStore = $metadataStore ?: new InMemoryMetadataStore(); - - $this->dispatchedEvents = $dispatchedEvents ?? WorkflowEvents::getDefaultDispatchedEvents(); } /** @@ -88,11 +76,6 @@ public function getMetadataStore(): MetadataStoreInterface return $this->metadataStore; } - public function getDispatchedEvents(): array - { - return $this->dispatchedEvents; - } - private function setInitialPlaces($places = null) { if (!$places) { diff --git a/src/Symfony/Component/Workflow/DefinitionBuilder.php b/src/Symfony/Component/Workflow/DefinitionBuilder.php index 68ee124ed8f8..19e9067edda9 100644 --- a/src/Symfony/Component/Workflow/DefinitionBuilder.php +++ b/src/Symfony/Component/Workflow/DefinitionBuilder.php @@ -26,7 +26,6 @@ class DefinitionBuilder private $transitions = []; private $initialPlaces; private $metadataStore; - private $dispatchEvents = null; /** * @param string[] $places @@ -43,7 +42,7 @@ public function __construct(array $places = [], array $transitions = []) */ public function build() { - return new Definition($this->places, $this->transitions, $this->initialPlaces, $this->metadataStore, $this->dispatchEvents); + return new Definition($this->places, $this->transitions, $this->initialPlaces, $this->metadataStore); } /** @@ -57,7 +56,6 @@ public function clear() $this->transitions = []; $this->initialPlaces = null; $this->metadataStore = null; - $this->dispatchEvents = null; return $this; } @@ -135,14 +133,4 @@ public function setMetadataStore(MetadataStoreInterface $metadataStore) return $this; } - - /** - * @return $this - */ - public function setDispatchEvents(array $dispatchEvents) - { - $this->dispatchEvents = $dispatchEvents; - - return $this; - } } diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php index 495892ba011f..c749011e66a0 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php @@ -6,7 +6,6 @@ use Symfony\Component\Workflow\DefinitionBuilder; use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore; use Symfony\Component\Workflow\Transition; -use Symfony\Component\Workflow\WorkflowEvents; class DefinitionBuilderTest extends TestCase { @@ -56,32 +55,4 @@ public function testSetMetadataStore() $this->assertSame($metadataStore, $definition->getMetadataStore()); } - - public function testCheckDefaultDispatchEvents() - { - $builder = new DefinitionBuilder(['a']); - $definition = $builder->build(); - - $this->assertSame(WorkflowEvents::getDefaultDispatchedEvents(), $definition->getDispatchedEvents()); - } - - public function testSetEmptyDispatchEvents() - { - $builder = new DefinitionBuilder(['a']); - $builder->setDispatchEvents([]); - $definition = $builder->build(); - - $this->assertSame([], $definition->getDispatchedEvents()); - } - - public function testSetSpecificDispatchEvents() - { - $events = [WorkflowEvents::ENTERED, WorkflowEvents::COMPLETED]; - - $builder = new DefinitionBuilder(['a']); - $builder->setDispatchEvents($events); - $definition = $builder->build(); - - $this->assertSame($events, $definition->getDispatchedEvents()); - } } diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php index 66c564a6b283..6ba3c1ef47f0 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php @@ -5,7 +5,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Transition; -use Symfony\Component\Workflow\WorkflowEvents; class DefinitionTest extends TestCase { @@ -70,30 +69,4 @@ public function testAddTransitionAndToPlaceIsNotDefined() new Definition($places, [new Transition('name', $places[0], 'c')]); } - - public function testSetDefaultDispatchEvents() - { - $places = range('a', 'b'); - $definition = new Definition($places, [], null, null, null); - - $this->assertSame(WorkflowEvents::getDefaultDispatchedEvents(), $definition->getDispatchedEvents()); - } - - public function testSetEmptyDispatchEvents() - { - $places = range('a', 'b'); - $definition = new Definition($places, [], null, null, []); - - $this->assertEmpty($definition->getDispatchedEvents()); - } - - public function testSetSpecificDispatchEvents() - { - $events = [WorkflowEvents::ENTERED, WorkflowEvents::COMPLETED]; - - $places = range('a', 'b'); - $definition = new Definition($places, [], null, null, $events); - - $this->assertSame($events, $definition->getDispatchedEvents()); - } } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 8f5793696afb..1c6a3ebd0327 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -428,17 +428,70 @@ public function testApplyWithEventDispatcher() $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); } - public function testApplyDispatchesNoEventsWhenSpecifiedByDefinition() + public function provideApplyWithEventDispatcherForAnnounceTests() + { + yield [false, [Workflow::DISABLE_ANNOUNCE_EVENT => true]]; + yield [true, [Workflow::DISABLE_ANNOUNCE_EVENT => false]]; + yield [true, []]; + } + + /** @dataProvider provideApplyWithEventDispatcherForAnnounceTests */ + public function testApplyWithEventDispatcherForAnnounce(bool $fired, array $context) + { + $definition = $this->createComplexWorkflowDefinition(); + $subject = new Subject(); + $eventDispatcher = new EventDispatcherMock(); + $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name'); + + $workflow->apply($subject, 't1', $context); + + if ($fired) { + $this->assertContains('workflow.workflow_name.announce', $eventDispatcher->dispatchedEvents); + } else { + $this->assertNotContains('workflow.workflow_name.announce', $eventDispatcher->dispatchedEvents); + } + } + + public function testApplyDispatchesWithDisableEventInContext() { $transitions[] = new Transition('a-b', 'a', 'b'); $transitions[] = new Transition('a-c', 'a', 'c'); - $definition = new Definition(['a', 'b', 'c'], $transitions, null, null, []); + $definition = new Definition(['a', 'b', 'c'], $transitions); $subject = new Subject(); $eventDispatcher = new EventDispatcherMock(); $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name'); - // Guard and Transition events are still called + $eventNameExpected = [ + 'workflow.guard', + 'workflow.workflow_name.guard', + 'workflow.workflow_name.guard.a-b', + 'workflow.transition', + 'workflow.workflow_name.transition', + 'workflow.workflow_name.transition.a-b', + ]; + + $workflow->apply($subject, 'a-b', [ + Workflow::DISABLE_LEAVE_EVENT => true, + Workflow::DISABLE_ENTER_EVENT => true, + Workflow::DISABLE_ENTERED_EVENT => true, + Workflow::DISABLE_COMPLETED_EVENT => true, + Workflow::DISABLE_ANNOUNCE_EVENT => true, + ]); + + $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); + } + + public function testApplyDispatchesNoEventsWhenSpecifiedByDefinition() + { + $transitions[] = new Transition('a-b', 'a', 'b'); + $transitions[] = new Transition('a-c', 'a', 'c'); + $definition = new Definition(['a', 'b', 'c'], $transitions); + + $subject = new Subject(); + $eventDispatcher = new EventDispatcherMock(); + $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name', []); + $eventNameExpected = [ 'workflow.guard', 'workflow.workflow_name.guard', @@ -454,13 +507,12 @@ public function testApplyOnlyDispatchesEventsThatHaveBeenSpecifiedByDefinition() { $transitions[] = new Transition('a-b', 'a', 'b'); $transitions[] = new Transition('a-c', 'a', 'c'); - $definition = new Definition(['a', 'b', 'c'], $transitions, null, null, [WorkflowEvents::COMPLETED]); + $definition = new Definition(['a', 'b', 'c'], $transitions); $subject = new Subject(); $eventDispatcher = new EventDispatcherMock(); - $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name'); + $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name', [WorkflowEvents::COMPLETED]); - // Guard and Transition events are still called $eventNameExpected = [ 'workflow.guard', 'workflow.workflow_name.guard', diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 38e4ece5b7fa..00abecd4f153 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -34,20 +34,46 @@ */ class Workflow implements WorkflowInterface { + public const DISABLE_LEAVE_EVENT = 'workflow_disable_leave_event'; + public const DISABLE_TRANSITION_EVENT = 'workflow_disable_transition_event'; + public const DISABLE_ENTER_EVENT = 'workflow_disable_enter_event'; + public const DISABLE_ENTERED_EVENT = 'workflow_disable_entered_event'; + public const DISABLE_COMPLETED_EVENT = 'workflow_disable_completed_event'; public const DISABLE_ANNOUNCE_EVENT = 'workflow_disable_announce_event'; + public const DEFAULT_INITIAL_CONTEXT = ['initial' => true]; + private const DISABLE_EVENTS_MAPPING = [ + WorkflowEvents::LEAVE => self::DISABLE_LEAVE_EVENT, + WorkflowEvents::TRANSITION => self::DISABLE_TRANSITION_EVENT, + WorkflowEvents::ENTER => self::DISABLE_ENTER_EVENT, + WorkflowEvents::ENTERED => self::DISABLE_ENTERED_EVENT, + WorkflowEvents::COMPLETED => self::DISABLE_COMPLETED_EVENT, + WorkflowEvents::ANNOUNCE => self::DISABLE_ANNOUNCE_EVENT, + ]; + private $definition; private $markingStore; private $dispatcher; private $name; - public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, string $name = 'unnamed') + /** + * When `null` fire all events (the default behaviour). + * Setting this to an empty array `[]` means no events are dispatched (except the Guard Event). + * Passing an array with WorkflowEvents will allow only those events to be dispatched plus + * the Guard Event. + * + * @var array|string[]|null + */ + private $eventsToDispatch = null; + + public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, string $name = 'unnamed', array $eventsToDispatch = null) { $this->definition = $definition; $this->markingStore = $markingStore ?: new MethodMarkingStore(); $this->dispatcher = $dispatcher; $this->name = $name; + $this->eventsToDispatch = $eventsToDispatch; } /** @@ -332,7 +358,7 @@ private function leave(object $subject, Transition $transition, Marking $marking { $places = $transition->getFroms(); - if ($this->shouldDispatchEvent(WorkflowEvents::LEAVE)) { + if ($this->shouldDispatchEvent(WorkflowEvents::LEAVE, $context)) { $event = new LeaveEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::LEAVE); @@ -350,7 +376,7 @@ private function leave(object $subject, Transition $transition, Marking $marking private function transition(object $subject, Transition $transition, Marking $marking, array $context): array { - if (!$this->shouldDispatchEvent(WorkflowEvents::TRANSITION)) { + if (!$this->shouldDispatchEvent(WorkflowEvents::TRANSITION, $context)) { return $context; } @@ -367,7 +393,7 @@ private function enter(object $subject, Transition $transition, Marking $marking { $places = $transition->getTos(); - if ($this->shouldDispatchEvent(WorkflowEvents::ENTER)) { + if ($this->shouldDispatchEvent(WorkflowEvents::ENTER, $context)) { $event = new EnterEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ENTER); @@ -385,68 +411,67 @@ private function enter(object $subject, Transition $transition, Marking $marking private function entered(object $subject, ?Transition $transition, Marking $marking, array $context): void { - if ($this->shouldDispatchEvent(WorkflowEvents::ENTERED)) { - $event = new EnteredEvent($subject, $marking, $transition, $this, $context); + if (!$this->shouldDispatchEvent(WorkflowEvents::ENTERED, $context)) { + return; + } - $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); + $event = new EnteredEvent($subject, $marking, $transition, $this, $context); - foreach ($marking->getPlaces() as $placeName => $nbToken) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $placeName)); - } + $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); + + foreach ($marking->getPlaces() as $placeName => $nbToken) { + $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $placeName)); } } private function completed(object $subject, Transition $transition, Marking $marking, array $context): void { - if ($this->shouldDispatchEvent(WorkflowEvents::COMPLETED)) { - $event = new CompletedEvent($subject, $marking, $transition, $this); - - $this->dispatcher->dispatch($event, WorkflowEvents::COMPLETED); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed', $this->name)); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); + if (!$this->shouldDispatchEvent(WorkflowEvents::COMPLETED, $context)) { + return; } + + $event = new CompletedEvent($subject, $marking, $transition, $this, $context); + + $this->dispatcher->dispatch($event, WorkflowEvents::COMPLETED); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed', $this->name)); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); } - private function announce(object $subject, Transition $initialTransition, Marking $marking): void + private function announce(object $subject, Transition $initialTransition, Marking $marking, array $context): void { - if ($this->shouldDispatchEvent(WorkflowEvents::ANNOUNCE)) { - $event = new AnnounceEvent($subject, $marking, $initialTransition, $this); + if (!$this->shouldDispatchEvent(WorkflowEvents::ANNOUNCE, $context)) { + return; + } - $this->dispatcher->dispatch($event, WorkflowEvents::ANNOUNCE); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce', $this->name)); + $event = new AnnounceEvent($subject, $marking, $initialTransition, $this, $context); - foreach ($this->getEnabledTransitions($subject) as $transition) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce.%s', $this->name, $transition->getName())); - } + $this->dispatcher->dispatch($event, WorkflowEvents::ANNOUNCE); + $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce', $this->name)); + + foreach ($this->getEnabledTransitions($subject) as $transition) { + $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce.%s', $this->name, $transition->getName())); } } - private function shouldDispatchEvent(string $eventName): bool + private function shouldDispatchEvent(string $eventName, array $context): bool { - // If we don't have a dispatcher we can't dispatch the - // event even if we wanted to if (null === $this->dispatcher) { return false; } - $dispatchEvents = $this->getDefinition()->getDispatchedEvents(); + if ($context[self::DISABLE_EVENTS_MAPPING[$eventName]] ?? false) { + return false; + } - // A null value implies all events should be dispatched - if (null === $dispatchEvents) { + if (null === $this->eventsToDispatch) { return true; } - // An empty array implies no events should be dispatched - if ([] === $dispatchEvents) { + if ([] === $this->eventsToDispatch) { return false; } - // Check if the WorkflowEvent name is in the events that - if (\count($dispatchEvents) >= 1) { - return \in_array($eventName, $dispatchEvents, true); - } - - return true; + return \in_array($eventName, $this->eventsToDispatch, true); } } diff --git a/src/Symfony/Component/Workflow/WorkflowEvents.php b/src/Symfony/Component/Workflow/WorkflowEvents.php index 091a7e03c1ca..d64783054069 100644 --- a/src/Symfony/Component/Workflow/WorkflowEvents.php +++ b/src/Symfony/Component/Workflow/WorkflowEvents.php @@ -78,9 +78,4 @@ final class WorkflowEvents private function __construct() { } - - public static function getDefaultDispatchedEvents(): array - { - return [self::LEAVE, self::TRANSITION, self::ENTER, self::ENTERED, self::COMPLETED, self::ANNOUNCE]; - } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy