From 1af1bf29ef5f1306dfcaf15970df46146a6dbdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 6 Mar 2019 21:59:33 +0100 Subject: [PATCH] Added support for many inital places --- UPGRADE-4.3.md | 21 +++++++++ UPGRADE-5.0.md | 1 + .../DependencyInjection/Configuration.php | 12 ++++- .../FrameworkExtension.php | 6 +-- .../Resources/config/schema/symfony-1.0.xsd | 1 + .../Fixtures/php/workflow-legacy.php | 25 +++++++++++ .../php/workflow_with_guard_expression.php | 2 +- ...th_multiple_transitions_with_same_name.php | 2 +- .../Fixtures/php/workflows.php | 4 +- .../php/workflows_explicitly_enabled.php | 2 +- ...ows_explicitly_enabled_named_workflows.php | 2 +- .../Fixtures/xml/workflow-legacy.xml | 20 +++++++++ .../xml/workflow_with_guard_expression.xml | 3 +- ...th_multiple_transitions_with_same_name.xml | 3 +- .../Fixtures/xml/workflows.xml | 3 +- .../xml/workflows_explicitly_enabled.xml | 3 +- ...ows_explicitly_enabled_named_workflows.xml | 3 +- .../Fixtures/yml/workflow-legacy.yml | 14 ++++++ .../yml/workflow_with_guard_expression.yml | 2 +- ...th_multiple_transitions_with_same_name.yml | 2 +- .../Fixtures/yml/workflows.yml | 4 +- .../yml/workflows_explicitly_enabled.yml | 2 +- ...ows_explicitly_enabled_named_workflows.yml | 2 +- .../FrameworkExtensionTest.php | 26 ++++++++++- .../Bundle/FrameworkBundle/composer.json | 4 +- src/Symfony/Component/Workflow/CHANGELOG.md | 1 + src/Symfony/Component/Workflow/Definition.php | 45 ++++++++++++++----- .../Workflow/Dumper/GraphvizDumper.php | 2 +- .../Workflow/Dumper/PlantUmlDumper.php | 2 +- .../Workflow/Tests/DefinitionBuilderTest.php | 2 +- .../Workflow/Tests/DefinitionTest.php | 12 ++++- .../Validator/StateMachineValidatorTest.php | 28 ++++++++++++ .../Tests/Validator/WorkflowValidatorTest.php | 14 ++++++ .../DefinitionValidatorInterface.php | 1 + .../Validator/StateMachineValidator.php | 7 ++- .../Workflow/Validator/WorkflowValidator.php | 6 +++ src/Symfony/Component/Workflow/Workflow.php | 6 ++- 37 files changed, 250 insertions(+), 45 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 52165c10b539..a45814f09e67 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -127,6 +127,27 @@ Security } ``` +Workflow +-------- + + * `initial_place` is deprecated in favour of `initial_places`. + + Before: + ```yaml + framework: + workflows: + article: + initial_place: draft + ``` + + After: + ```yaml + framework: + workflows: + article: + initial_places: [draft] + ``` + Yaml ---- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 60b16b1c58df..16a034a85dc0 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -368,6 +368,7 @@ Workflow * `SupportStrategyInterface` has been removed, use `WorkflowSupportStrategyInterface` instead. * `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead. * `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`. + * Removed support of `initial_place`. Use `initial_places` instead. Yaml ---- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 1e52ce932248..04f2bdbe16c2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -231,7 +231,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) $workflows = []; } - if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_place', 'places', 'transitions']))) { + if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_places', 'places', 'transitions']))) { $workflows = $workflows['workflows']; } @@ -258,6 +258,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->prototype('array') ->fixXmlConfig('support') ->fixXmlConfig('place') + ->fixXmlConfig('initial_place') ->fixXmlConfig('transition') ->children() ->arrayNode('audit_trail') @@ -312,8 +313,17 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->cannotBeEmpty() ->end() ->scalarNode('initial_place') + ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3, use the "initial_places" configuration key instead.') ->defaultNull() ->end() + ->arrayNode('initial_places') + ->beforeNormalization() + ->ifTrue(function ($v) { return !\is_array($v); }) + ->then(function ($v) { return [$v]; }) + ->end() + ->defaultValue([]) + ->prototype('scalar')->end() + ->end() ->arrayNode('places') ->beforeNormalization() ->always() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 870c499aafbd..f2f2ab00fcf7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -615,14 +615,14 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ // Create places $places = array_column($workflow['places'], 'name'); - $initialPlace = $workflow['initial_place'] ?? null; + $initialPlaces = $workflow['initial_places'] ?? $workflow['initial_place'] ?? []; // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); $definitionDefinition->addArgument($places); $definitionDefinition->addArgument($transitions); - $definitionDefinition->addArgument($initialPlace); + $definitionDefinition->addArgument($initialPlaces); $definitionDefinition->addArgument($metadataStoreDefinition); // Create MarkingStore @@ -670,7 +670,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ ->addTransitions(array_map(function (Reference $ref) use ($container): Workflow\Transition { return $container->get((string) $ref); }, $transitions)) - ->setInitialPlace($initialPlace) + ->setInitialPlace($initialPlaces) ->build() ; $validator->validate($realDefinition, $name); 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 98baeb978b44..254c0085e8d1 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 @@ -270,6 +270,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php new file mode 100644 index 000000000000..e7d8919315da --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php @@ -0,0 +1,25 @@ +loadFromExtension('framework', [ + 'workflows' => [ + 'legacy' => [ + 'type' => 'workflow', + 'supports' => [ + stdClass::class, + ], + 'initial_place' => 'draft', + 'places' => [ + 'draft', + 'published', + ], + 'transitions' => [ + 'publish' => [ + 'from' => 'draft', + 'to' => 'published', + ], + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php index 19de6363e62c..03b6a0b79b0c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php @@ -12,7 +12,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'draft', + 'initial_places' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php index c1a525db03cd..613a38c6c0eb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php @@ -12,7 +12,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'draft', + 'initial_places' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php index 9d066a21ba36..17a0e1fa4a7e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php @@ -12,7 +12,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'draft', + 'initial_places' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', @@ -47,7 +47,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'start', + 'initial_places' => ['start'], 'metadata' => [ 'title' => 'workflow title', ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php index 165d0daa11ae..1c8190bd09d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php @@ -6,7 +6,7 @@ 'foo' => [ 'type' => 'workflow', 'supports' => ['Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest'], - 'initial_place' => 'bar', + 'initial_places' => ['bar'], 'places' => ['bar', 'baz'], 'transitions' => [ 'bar_baz' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php index 17055ec16f7d..6faae44f45ce 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php @@ -6,7 +6,7 @@ 'workflows' => [ 'type' => 'workflow', 'supports' => ['Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest'], - 'initial_place' => 'bar', + 'initial_places' => ['bar'], 'places' => ['bar', 'baz'], 'transitions' => [ 'bar_baz' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml new file mode 100644 index 000000000000..d1339d5f65cc --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml @@ -0,0 +1,20 @@ + + + + + + + stdClass + + + + draft + published + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml index fa5a96ab1188..32c33db5b812 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml @@ -7,7 +7,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + draft a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml index 51413201298d..ffc316c99e70 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml @@ -7,7 +7,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + draft a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml index 862ecae17cde..da5cd4c75820 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml @@ -7,7 +7,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + draft a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml index 08855f7569aa..b564c6ff7644 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml @@ -6,7 +6,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + bar Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest bar baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml index 8415c9c28066..b218480fe68a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml @@ -6,7 +6,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + bar Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest bar baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml new file mode 100644 index 000000000000..7ff70074d400 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml @@ -0,0 +1,14 @@ +framework: + workflows: + legacy: + type: workflow + initial_place: draft + supports: + - stdClass + places: + - draft + - published + transitions: + publish: + from: draft + to: published diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml index 458cb4ae1ee7..433771601c3d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml @@ -6,7 +6,7 @@ framework: type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: draft + initial_places: [draft] places: - draft - wait_for_journalist diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml index 36d00de46501..fee71c264569 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml @@ -6,7 +6,7 @@ framework: type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: draft + initial_places: [draft] places: - draft - wait_for_journalist diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml index c82c92791c86..894d5dcde207 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml @@ -6,7 +6,7 @@ framework: type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: draft + initial_places: [draft] places: # simple format - draft @@ -33,7 +33,7 @@ framework: type: single_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: start + initial_places: [start] metadata: title: workflow title places: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml index 21abbf03055a..d1545374705d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml @@ -6,7 +6,7 @@ framework: type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: bar + initial_places: [bar] places: - bar - baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml index a6c03de95d1b..bb468254aca0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml @@ -5,7 +5,7 @@ framework: type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: bar + initial_places: [bar] places: - bar - baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 5c0352b2658d..dd626d62c40b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -217,7 +217,7 @@ public function testWorkflows() 'Places are passed to the workflow definition' ); $this->assertCount(4, $workflowDefinition->getArgument(1)); - $this->assertSame('draft', $workflowDefinition->getArgument(2)); + $this->assertSame(['draft'], $workflowDefinition->getArgument(2)); $this->assertTrue($container->hasDefinition('state_machine.pull_request'), 'State machine is registered as a service'); $this->assertSame('state_machine.abstract', $container->getDefinition('state_machine.pull_request')->getParent()); @@ -238,7 +238,7 @@ public function testWorkflows() 'Places are passed to the state machine definition' ); $this->assertCount(9, $stateMachineDefinition->getArgument(1)); - $this->assertSame('start', $stateMachineDefinition->getArgument(2)); + $this->assertSame(['start'], $stateMachineDefinition->getArgument(2)); $metadataStoreDefinition = $stateMachineDefinition->getArgument(3); $this->assertInstanceOf(Definition::class, $metadataStoreDefinition); @@ -271,6 +271,28 @@ public function testWorkflows() $this->assertGreaterThan(0, \count($registryDefinition->getMethodCalls())); } + public function testWorkflowLegacy() + { + $container = $this->createContainerFromFile('workflow-legacy'); + + $this->assertTrue($container->hasDefinition('workflow.legacy'), 'Workflow is registered as a service'); + $this->assertSame('workflow.abstract', $container->getDefinition('workflow.legacy')->getParent()); + $this->assertTrue($container->hasDefinition('workflow.legacy.definition'), 'Workflow definition is registered as a service'); + + $workflowDefinition = $container->getDefinition('workflow.legacy.definition'); + + $this->assertSame(['draft'], $workflowDefinition->getArgument(2)); + + $this->assertSame( + [ + 'draft', + 'published', + ], + $workflowDefinition->getArgument(0), + 'Places are passed to the workflow definition' + ); + } + /** * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException * @expectedExceptionMessage A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" where found on StateMachine "my_workflow". diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 8279d4c7a3e7..86ad2fe1e6e6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -54,7 +54,7 @@ "symfony/twig-bundle": "~2.8|~3.2|~4.0", "symfony/validator": "^4.1", "symfony/var-dumper": "~3.4|~4.0", - "symfony/workflow": "^4.1", + "symfony/workflow": "^4.3", "symfony/yaml": "~3.4|~4.0", "symfony/property-info": "~3.4|~4.0", "symfony/lock": "~3.4|~4.0", @@ -79,7 +79,7 @@ "symfony/translation": "<4.3", "symfony/twig-bridge": "<4.1.1", "symfony/validator": "<4.1", - "symfony/workflow": "<4.1" + "symfony/workflow": "<4.3" }, "suggest": { "ext-apcu": "For best performance of the system caches", diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index a37db3857c47..0801deccc711 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -26,6 +26,7 @@ CHANGELOG * Dispatch `EnteredEvent` on `workflow.entered` * Dispatch `CompletedEvent` on `workflow.completed` * Dispatch `AnnounceEvent` on `workflow.announce` + * Added support for many `initialPlaces` 4.1.0 ----- diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index f614d46a3055..dd0c0626cf78 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -24,14 +24,15 @@ final class Definition { private $places = []; private $transitions = []; - private $initialPlace; + private $initialPlaces = []; private $metadataStore; /** - * @param string[] $places - * @param Transition[] $transitions + * @param string[] $places + * @param Transition[] $transitions + * @param string|string[]|null $initialPlaces */ - public function __construct(array $places, array $transitions, string $initialPlace = null, MetadataStoreInterface $metadataStore = null) + public function __construct(array $places, array $transitions, $initialPlaces = null, MetadataStoreInterface $metadataStore = null) { foreach ($places as $place) { $this->addPlace($place); @@ -41,17 +42,33 @@ public function __construct(array $places, array $transitions, string $initialPl $this->addTransition($transition); } - $this->setInitialPlace($initialPlace); + $this->setInitialPlaces($initialPlaces); $this->metadataStore = $metadataStore ?: new InMemoryMetadataStore(); } /** + * @deprecated since Symfony 4.3. Use the getInitialPlaces() instead. + * * @return string|null */ public function getInitialPlace() { - return $this->initialPlace; + @trigger_error(sprintf('Calling %s::getInitialPlace() is deprecated. Call %s::getInitialPlaces() instead.', __CLASS__, __CLASS__)); + + if (!$this->initialPlaces) { + return null; + } + + return reset($this->initialPlaces); + } + + /** + * @return string[] + */ + public function getInitialPlaces(): array + { + return $this->initialPlaces; } /** @@ -75,23 +92,27 @@ public function getMetadataStore(): MetadataStoreInterface return $this->metadataStore; } - private function setInitialPlace(string $place = null) + private function setInitialPlaces($places = null) { - if (null === $place) { + if (null === $places) { return; } - if (!isset($this->places[$place])) { - throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); + $places = (array) $places; + + foreach ($places as $place) { + if (!isset($this->places[$place])) { + throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); + } } - $this->initialPlace = $place; + $this->initialPlaces = $places; } private function addPlace(string $place) { if (!\count($this->places)) { - $this->initialPlace = $place; + $this->initialPlaces = [$place]; } $this->places[$place] = $place; diff --git a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php index 6822eab86bda..55cd832bbd7b 100644 --- a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php @@ -69,7 +69,7 @@ protected function findPlaces(Definition $definition, Marking $marking = null) foreach ($definition->getPlaces() as $place) { $attributes = []; - if ($place === $definition->getInitialPlace()) { + if (\in_array($place, $definition->getInitialPlaces(), true)) { $attributes['style'] = 'filled'; } if ($marking && $marking->has($place)) { diff --git a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php index 50d9046f2655..977ef69cdd2f 100644 --- a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php @@ -199,7 +199,7 @@ private function getState(string $place, Definition $definition, Marking $markin $placeEscaped = $this->escape($place); $output = "state $placeEscaped". - ($definition->getInitialPlace() === $place ? ' '.self::INITIAL : ''). + (\in_array($place, $definition->getInitialPlaces(), true) ? ' '.self::INITIAL : ''). ($marking && $marking->has($place) ? ' '.self::MARKED : ''); $backgroundColor = $workflowMetadata->getMetadata('bg_color', $place); diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php index fdc4703a1b42..62351d7d9218 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php @@ -15,7 +15,7 @@ public function testSetInitialPlace() $builder->setInitialPlace('b'); $definition = $builder->build(); - $this->assertEquals('b', $definition->getInitialPlace()); + $this->assertEquals(['b'], $definition->getInitialPlaces()); } public function testAddTransition() diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php index e10aad81cf14..8bbac4a8c784 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php @@ -15,7 +15,7 @@ public function testAddPlaces() $this->assertCount(5, $definition->getPlaces()); - $this->assertEquals('a', $definition->getInitialPlace()); + $this->assertEquals(['a'], $definition->getInitialPlaces()); } public function testSetInitialPlace() @@ -23,7 +23,15 @@ public function testSetInitialPlace() $places = range('a', 'e'); $definition = new Definition($places, [], $places[3]); - $this->assertEquals($places[3], $definition->getInitialPlace()); + $this->assertEquals([$places[3]], $definition->getInitialPlaces()); + } + + public function testSetInitialPlaces() + { + $places = range('a', 'e'); + $definition = new Definition($places, [], ['a', 'e']); + + $this->assertEquals(['a', 'e'], $definition->getInitialPlaces()); } /** diff --git a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php index 4e344560557d..35da1f2ec806 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php @@ -109,4 +109,32 @@ public function testValid() // | t2 | --> | c | // +----+ +----+ } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage The state machine "foo" can not store many places. But the definition has 2 initial places. Only one is supported. + */ + public function testWithTooManyInitialPlaces() + { + $places = range('a', 'c'); + $transitions = []; + $definition = new Definition($places, $transitions, ['a', 'b']); + + (new StateMachineValidator())->validate($definition, 'foo'); + + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); + + // The graph looks like: + // + // +----+ +----+ +---+ + // | a | --> | t1 | --> | b | + // +----+ +----+ +---+ + // | + // | + // v + // +----+ +----+ + // | t2 | --> | c | + // +----+ +----+ + } } diff --git a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php index 4a5c5a57dd85..5aa020fea45a 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php @@ -51,6 +51,20 @@ public function testWorkflowWithInvalidNames() (new WorkflowValidator())->validate($definition, 'foo'); } + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage The marking store of workflow "foo" can not store many places. But the definition has 2 initial places. Only one is supported. + */ + public function testWithTooManyInitialPlaces() + { + $places = range('a', 'c'); + $transitions = []; + + $definition = new Definition($places, $transitions, ['a', 'b']); + + (new WorkflowValidator(true))->validate($definition, 'foo'); + } + public function testSameTransitionNameButNotSamePlace() { $places = range('a', 'd'); diff --git a/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php b/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php index 244dceae9a9d..1282c966b7d3 100644 --- a/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php +++ b/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php @@ -16,6 +16,7 @@ /** * @author Tobias Nyholm + * @author Grégoire Pineau */ interface DefinitionValidatorInterface { diff --git a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php index 7dbe69494051..78b32e648e32 100644 --- a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php +++ b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php @@ -37,10 +37,15 @@ public function validate(Definition $definition, $name) // Enforcing uniqueness of the names of transitions starting at each node $from = reset($froms); if (isset($transitionFromNames[$from][$transition->getName()])) { - throw new InvalidDefinitionException(sprintf('A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" where found on StateMachine "%s". ', $transition->getName(), $from, $name)); + throw new InvalidDefinitionException(sprintf('A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" where found on StateMachine "%s".', $transition->getName(), $from, $name)); } $transitionFromNames[$from][$transition->getName()] = true; } + + $initialPlaces = $definition->getInitialPlaces(); + if (2 <= count($initialPlaces)) { + throw new InvalidDefinitionException(sprintf('The state machine "%s" can not store many places. But the definition has %s initial places. Only one is supported.', $name, \count($initialPlaces))); + } } } diff --git a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php index 0cb420ba6ad4..2a31ec8e4659 100644 --- a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php +++ b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php @@ -16,6 +16,7 @@ /** * @author Tobias Nyholm + * @author Grégoire Pineau */ class WorkflowValidator implements DefinitionValidatorInterface { @@ -48,5 +49,10 @@ public function validate(Definition $definition, $name) throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" can not store many places. But the transition "%s" has too many output (%d). Only one is accepted.', $name, $transition->getName(), \count($transition->getTos()))); } } + + $initialPlaces = $definition->getInitialPlaces(); + if (2 <= count($initialPlaces)) { + throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" can not store many places. But the definition has %s initial places. Only one is supported.', $name, \count($initialPlaces))); + } } } diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index c0866c663796..11fbe5f34837 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -61,10 +61,12 @@ public function getMarking($subject) // check if the subject is already in the workflow if (!$marking->getPlaces()) { - if (!$this->definition->getInitialPlace()) { + if (!$this->definition->getInitialPlaces()) { throw new LogicException(sprintf('The Marking is empty and there is no initial place for workflow "%s".', $this->name)); } - $marking->mark($this->definition->getInitialPlace()); + foreach ($this->definition->getInitialPlaces() as $place) { + $marking->mark($place); + } // update the subject with the new marking $this->markingStore->setMarking($subject, $marking);