[Workflow] Move code from ValidateWorkflowsPass to the FrameworkExtension

This commit is contained in:
Grégoire Pineau 2018-12-04 19:19:25 +01:00
parent 18cd3420a4
commit a608797165
10 changed files with 281 additions and 46 deletions

View File

@ -603,20 +603,15 @@ class FrameworkExtension extends Extension
// Create places
$places = array_column($workflow['places'], 'name');
$initialPlace = $workflow['initial_place'] ?? null;
// Create a Definition
$definitionDefinition = new Definition(Workflow\Definition::class);
$definitionDefinition->setPublic(false);
$definitionDefinition->addArgument($places);
$definitionDefinition->addArgument($transitions);
$definitionDefinition->addArgument($workflow['initial_place'] ?? null);
$definitionDefinition->addArgument($initialPlace);
$definitionDefinition->addArgument($metadataStoreDefinition);
$definitionDefinition->addTag('workflow.definition', [
'name' => $name,
'type' => $type,
'marking_store' => $workflow['marking_store']['type'] ?? null,
'single_state' => 'method' === ($workflow['marking_store']['type'] ?? null) && ($workflow['marking_store']['arguments'][0] ?? false),
]);
// Create MarkingStore
if (isset($workflow['marking_store']['type'])) {
@ -641,6 +636,34 @@ class FrameworkExtension extends Extension
$container->setDefinition(sprintf('%s.definition', $workflowId), $definitionDefinition);
$container->registerAliasForArgument($workflowId, WorkflowInterface::class, $name.'.'.$type);
// Validate Workflow
$validator = null;
switch (true) {
case 'state_machine' === $workflow['type']:
$validator = new Workflow\Validator\StateMachineValidator();
break;
case 'method' === ($workflow['marking_store']['type'] ?? null):
$singlePlace = $workflow['marking_store']['arguments'][0] ?? false;
$validator = new Workflow\Validator\WorkflowValidator($singlePlace);
break;
case 'single_state' === ($workflow['marking_store']['type'] ?? null):
$validator = new Workflow\Validator\WorkflowValidator(true);
break;
case 'multiple_state' === ($workflow['marking_store']['type'] ?? false):
$validator = new Workflow\Validator\WorkflowValidator(false);
break;
}
if ($validator) {
$realDefinition = (new Workflow\DefinitionBuilder($places))
->addTransitions(array_map(function (Reference $ref) use ($container): Workflow\Transition {
return $container->get((string) $ref);
}, $transitions))
->setInitialPlace($initialPlace)
->build()
;
$validator->validate($realDefinition, $name);
}
// Add workflow to Registry
if ($workflow['supports']) {
foreach ($workflow['supports'] as $supportedClassName) {

View File

@ -54,7 +54,6 @@ use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
use Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass;
/**
* Bundle.
@ -115,7 +114,6 @@ class FrameworkBundle extends Bundle
$container->addCompilerPass(new DataCollectorTranslatorPass());
$container->addCompilerPass(new ControllerArgumentValueResolverPass());
$container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32);
$this->addCompilerPassIfExists($container, ValidateWorkflowsPass::class);
$container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new CachePoolPrunerPass(), PassConfig::TYPE_AFTER_REMOVING);
$this->addCompilerPassIfExists($container, FormPass::class);

View File

@ -0,0 +1,30 @@
<?php
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest;
$container->loadFromExtension('framework', [
'workflows' => [
'my_workflow' => [
'type' => 'state_machine',
'supports' => [
FrameworkExtensionTest::class,
],
'places' => [
'first',
'middle',
'last',
],
'transitions' => [
'go' => [
'from' => [
'first',
],
'to' => [
'middle',
'last',
],
],
],
],
],
]);

View File

@ -0,0 +1,22 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config>
<framework:workflow name="my_workflow" type="state_machine">
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
<framework:place name="first" />
<framework:place name="middle" />
<framework:place name="last" />
<framework:transition name="go">
<framework:from>first</framework:from>
<framework:to>middle</framework:to>
<framework:to>last</framework:to>
</framework:transition>
</framework:workflow>
</framework:config>
</container>

View File

@ -29,12 +29,12 @@
<framework:to>approved_by_journalist</framework:to>
</framework:transition>
<framework:transition name="spellchecker_approval">
<framework:from>wait_for_spellcheker</framework:from>
<framework:to>approved_by_spellchker</framework:to>
<framework:from>wait_for_spellchecker</framework:from>
<framework:to>approved_by_spellchecker</framework:to>
</framework:transition>
<framework:transition name="publish">
<framework:from>approved_by_journalist</framework:from>
<framework:from>approved_by_spellchker</framework:from>
<framework:from>approved_by_spellchecker</framework:from>
<framework:to>published</framework:to>
</framework:transition>
</framework:workflow>

View File

@ -0,0 +1,11 @@
framework:
workflows:
my_workflow:
type: state_machine
supports:
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
places: [first, middle, last]
transitions:
go:
from: first
to: [last, middle ]

View File

@ -215,7 +215,6 @@ abstract class FrameworkExtensionTest extends TestCase
$workflowDefinition->getArgument(0),
'Places are passed to the workflow definition'
);
$this->assertSame(['workflow.definition' => [['name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state', 'single_state' => false]]], $workflowDefinition->getTags());
$this->assertCount(4, $workflowDefinition->getArgument(1));
$this->assertSame('draft', $workflowDefinition->getArgument(2));
@ -237,7 +236,6 @@ abstract class FrameworkExtensionTest extends TestCase
$stateMachineDefinition->getArgument(0),
'Places are passed to the state machine definition'
);
$this->assertSame(['workflow.definition' => [['name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state', 'single_state' => false]]], $stateMachineDefinition->getTags());
$this->assertCount(9, $stateMachineDefinition->getArgument(1));
$this->assertSame('start', $stateMachineDefinition->getArgument(2));
@ -272,6 +270,15 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertGreaterThan(0, \count($registryDefinition->getMethodCalls()));
}
/**
* @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".
*/
public function testWorkflowAreValidated()
{
$this->createContainerFromFile('workflow_not_valid');
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage "type" and "service" cannot be used together.

View File

@ -56,4 +56,178 @@ class PhpFrameworkExtensionTest extends FrameworkExtensionTest
]);
});
}
/**
* @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException
* @expectedExceptionMessage A transition from a place/state must have an unique name. Multiple transitions named "a_to_b" from place/state "a" where found on StateMachine "article".
*/
public function testWorkflowValidationStateMachine()
{
$this->createContainerFromClosure(function ($container) {
$container->loadFromExtension('framework', [
'workflows' => [
'article' => [
'type' => 'state_machine',
'supports' => [
__CLASS__,
],
'places' => [
'a',
'b',
'c',
],
'transitions' => [
'a_to_b' => [
'from' => ['a'],
'to' => ['b', 'c'],
],
],
],
],
]);
});
}
/**
* @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException
* @expectedExceptionMessage The marking store of workflow "article" can not store many places. But the transition "a_to_b" has too many output (2). Only one is accepted.
*/
public function testWorkflowValidationMethodSingle()
{
$this->createContainerFromClosure(function ($container) {
$container->loadFromExtension('framework', [
'workflows' => [
'article' => [
'type' => 'workflow',
'marking_store' => [
'type' => 'method',
'arguments' => [
true,
],
],
'supports' => [
__CLASS__,
],
'places' => [
'a',
'b',
'c',
],
'transitions' => [
'a_to_b' => [
'from' => ['a'],
'to' => ['b', 'c'],
],
],
],
],
]);
});
}
public function testWorkflowValidationMethodNotSingle()
{
$this->createContainerFromClosure(function ($container) {
$container->loadFromExtension('framework', [
'workflows' => [
'article' => [
'type' => 'workflow',
'marking_store' => [
'type' => 'method',
'arguments' => [
false,
],
],
'supports' => [
__CLASS__,
],
'places' => [
'a',
'b',
'c',
],
'transitions' => [
'a_to_b' => [
'from' => ['a'],
'to' => ['b', 'c'],
],
],
],
],
]);
});
// the test ensures that the validation does not fail (i.e. it does not throw any exceptions)
$this->addToAssertionCount(1);
}
public function testWorkflowValidationMultipleState()
{
$this->createContainerFromClosure(function ($container) {
$container->loadFromExtension('framework', [
'workflows' => [
'article' => [
'type' => 'workflow',
'marking_store' => [
'type' => 'multiple_state',
],
'supports' => [
__CLASS__,
],
'places' => [
'a',
'b',
'c',
],
'transitions' => [
'a_to_b' => [
'from' => ['a'],
'to' => ['b', 'c'],
],
],
],
],
]);
});
// the test ensures that the validation does not fail (i.e. it does not throw any exceptions)
$this->addToAssertionCount(1);
}
/**
* @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException
* @expectedExceptionMessage The marking store of workflow "article" can not store many places. But the transition "a_to_b" has too many output (2). Only one is accepted.
*/
public function testWorkflowValidationSingleState()
{
$this->createContainerFromClosure(function ($container) {
$container->loadFromExtension('framework', [
'workflows' => [
'article' => [
'type' => 'workflow',
'marking_store' => [
'type' => 'single_state',
],
'supports' => [
__CLASS__,
],
'places' => [
'a',
'b',
'c',
],
'transitions' => [
'a_to_b' => [
'from' => ['a'],
'to' => ['b', 'c'],
],
],
],
],
]);
});
// the test ensures that the validation does not fail (i.e. it does not throw any exceptions)
$this->addToAssertionCount(1);
}
}

View File

@ -19,6 +19,8 @@ use Symfony\Component\Workflow\Validator\WorkflowValidator;
/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*
* @deprecated since Symfony 4.3
*/
class ValidateWorkflowsPass implements CompilerPassInterface
{

View File

@ -1,32 +0,0 @@
<?php
namespace Symfony\Component\Workflow\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\Workflow\Definition as WorkflowDefinition;
use Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass;
use Symfony\Component\Workflow\Transition;
class ValidateWorkflowsPassTest extends TestCase
{
public function testProcess()
{
$container = new ContainerBuilder();
$container->register('definition1', WorkflowDefinition::class)
->addArgument(['a', 'b', 'c'])
->addArgument([
new Definition(Transition::class, ['t1', 'a', 'b']),
new Definition(Transition::class, ['t2', 'a', 'c']),
])
->addTag('workflow.definition', ['name' => 'wf1', 'type' => 'state_machine', 'marking_store' => 'foo']);
(new ValidateWorkflowsPass())->process($container);
$workflowDefinition = $container->get('definition1');
$this->assertSame(['a' => 'a', 'b' => 'b', 'c' => 'c'], $workflowDefinition->getPlaces());
$this->assertEquals([new Transition('t1', 'a', 'b'), new Transition('t2', 'a', 'c')], $workflowDefinition->getTransitions());
}
}