be able to enable workflow support explicitly

This commit is contained in:
Christian Flothmann 2017-09-03 12:36:19 +02:00
parent 012c56b8cb
commit eaa506f562
8 changed files with 182 additions and 126 deletions

View File

@ -247,141 +247,165 @@ class Configuration implements ConfigurationInterface
->fixXmlConfig('workflow')
->children()
->arrayNode('workflows')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('support')
->fixXmlConfig('place')
->fixXmlConfig('transition')
->children()
->arrayNode('audit_trail')
->canBeEnabled()
->end()
->enumNode('type')
->values(array('workflow', 'state_machine'))
->end()
->arrayNode('marking_store')
->fixXmlConfig('argument')
->canBeEnabled()
->beforeNormalization()
->always(function ($v) {
if (true === $v['enabled']) {
$workflows = $v;
unset($workflows['enabled']);
if (count($workflows) === 1 && isset($workflows[0]['enabled'])) {
$workflows = array();
}
$v = array(
'enabled' => true,
'workflows' => $workflows,
);
}
return $v;
})
->end()
->children()
->arrayNode('workflows')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('support')
->fixXmlConfig('place')
->fixXmlConfig('transition')
->children()
->enumNode('type')
->values(array('multiple_state', 'single_state'))
->arrayNode('audit_trail')
->canBeEnabled()
->end()
->arrayNode('arguments')
->enumNode('type')
->values(array('workflow', 'state_machine'))
->end()
->arrayNode('marking_store')
->fixXmlConfig('argument')
->children()
->enumNode('type')
->values(array('multiple_state', 'single_state'))
->end()
->arrayNode('arguments')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->requiresAtLeastOneElement()
->prototype('scalar')
->end()
->end()
->scalarNode('service')
->cannotBeEmpty()
->end()
->end()
->validate()
->ifTrue(function ($v) { return isset($v['type']) && isset($v['service']); })
->thenInvalid('"type" and "service" cannot be used together.')
->end()
->validate()
->ifTrue(function ($v) { return !empty($v['arguments']) && isset($v['service']); })
->thenInvalid('"arguments" and "service" cannot be used together.')
->end()
->end()
->arrayNode('supports')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->validate()
->ifTrue(function ($v) { return !class_exists($v); })
->thenInvalid('The supported class %s does not exist.')
->end()
->end()
->end()
->scalarNode('service')
->scalarNode('support_strategy')
->cannotBeEmpty()
->end()
->end()
->validate()
->ifTrue(function ($v) { return isset($v['type']) && isset($v['service']); })
->thenInvalid('"type" and "service" cannot be used together.')
->end()
->validate()
->ifTrue(function ($v) { return !empty($v['arguments']) && isset($v['service']); })
->thenInvalid('"arguments" and "service" cannot be used together.')
->end()
->end()
->arrayNode('supports')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->prototype('scalar')
->cannotBeEmpty()
->validate()
->ifTrue(function ($v) { return !class_exists($v); })
->thenInvalid('The supported class %s does not exist.')
->scalarNode('initial_place')
->defaultNull()
->end()
->arrayNode('places')
->isRequired()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->arrayNode('transitions')
->beforeNormalization()
->always()
->then(function ($transitions) {
// It's an indexed array, we let the validation occurs
if (isset($transitions[0])) {
return $transitions;
}
foreach ($transitions as $name => $transition) {
if (array_key_exists('name', $transition)) {
continue;
}
$transition['name'] = $name;
$transitions[$name] = $transition;
}
return $transitions;
})
->end()
->isRequired()
->requiresAtLeastOneElement()
->prototype('array')
->children()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('guard')
->cannotBeEmpty()
->info('An expression to block the transition')
->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
->end()
->arrayNode('from')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->arrayNode('to')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->scalarNode('support_strategy')
->cannotBeEmpty()
->end()
->scalarNode('initial_place')
->defaultNull()
->end()
->arrayNode('places')
->isRequired()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->arrayNode('transitions')
->beforeNormalization()
->always()
->then(function ($transitions) {
// It's an indexed array, we let the validation occurs
if (isset($transitions[0])) {
return $transitions;
}
foreach ($transitions as $name => $transition) {
if (array_key_exists('name', $transition)) {
continue;
}
$transition['name'] = $name;
$transitions[$name] = $transition;
}
return $transitions;
->validate()
->ifTrue(function ($v) {
return $v['supports'] && isset($v['support_strategy']);
})
->thenInvalid('"supports" and "support_strategy" cannot be used together.')
->end()
->isRequired()
->requiresAtLeastOneElement()
->prototype('array')
->children()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('guard')
->cannotBeEmpty()
->info('An expression to block the transition')
->example('is_fully_authenticated() and has_role(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
->end()
->arrayNode('from')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->arrayNode('to')
->beforeNormalization()
->ifString()
->then(function ($v) { return array($v); })
->end()
->requiresAtLeastOneElement()
->prototype('scalar')
->cannotBeEmpty()
->end()
->end()
->end()
->validate()
->ifTrue(function ($v) {
return !$v['supports'] && !isset($v['support_strategy']);
})
->thenInvalid('"supports" or "support_strategy" should be configured.')
->end()
->end()
->end()
->validate()
->ifTrue(function ($v) {
return $v['supports'] && isset($v['support_strategy']);
})
->thenInvalid('"supports" and "support_strategy" cannot be used together.')
->end()
->validate()
->ifTrue(function ($v) {
return !$v['supports'] && !isset($v['support_strategy']);
})
->thenInvalid('"supports" or "support_strategy" should be configured.')
->end()
->end()
->end()
->end()

View File

@ -530,13 +530,13 @@ class FrameworkExtension extends Extension
/**
* Loads the workflow configuration.
*
* @param array $workflows A workflow configuration array
* @param array $config A workflow configuration array
* @param ContainerBuilder $container A ContainerBuilder instance
* @param XmlFileLoader $loader An XmlFileLoader instance
*/
private function registerWorkflowConfiguration(array $workflows, ContainerBuilder $container, XmlFileLoader $loader)
private function registerWorkflowConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
if (!$workflows) {
if (!$config['enabled']) {
if (!class_exists(Workflow\Workflow::class)) {
$container->removeDefinition(WorkflowDumpCommand::class);
}
@ -552,7 +552,7 @@ class FrameworkExtension extends Extension
$registryDefinition = $container->getDefinition('workflow.registry');
foreach ($workflows as $name => $workflow) {
foreach ($config['workflows'] as $name => $workflow) {
if (!array_key_exists('type', $workflow)) {
$workflow['type'] = 'workflow';
@trigger_error(sprintf('The "type" option of the "framework.workflows.%s" configuration entry must be defined since Symfony 3.3. The default value will be "state_machine" in Symfony 4.0.', $name), E_USER_DEPRECATED);

View File

@ -254,15 +254,16 @@
<xsd:complexType name="workflow">
<xsd:sequence>
<xsd:element name="marking-store" type="marking_store" />
<xsd:element name="marking-store" type="marking_store" minOccurs="0" maxOccurs="1" />
<xsd:element name="support" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="place" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="transition" type="transition" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="place" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="transition" type="transition" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="workflow_type" />
<xsd:attribute name="initial-place" type="xsd:string" />
<xsd:attribute name="support-strategy" type="xsd:string" />
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>
<xsd:complexType name="marking_store">

View File

@ -331,7 +331,10 @@ class ConfigurationTest extends TestCase
'default_redis_provider' => 'redis://localhost',
'default_memcached_provider' => 'memcached://localhost',
),
'workflows' => array(),
'workflows' => array(
'enabled' => false,
'workflows' => array(),
),
'php_errors' => array(
'log' => true,
'throw' => true,

View File

@ -0,0 +1,5 @@
<?php
$container->loadFromExtension('framework', array(
'workflows' => null,
));

View File

@ -0,0 +1,11 @@
<?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 enabled="true" />
</framework:config>
</container>

View File

@ -0,0 +1,2 @@
framework:
workflows: ~

View File

@ -12,6 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
use Doctrine\Common\Annotations\Annotation;
use Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand;
use Symfony\Bundle\FullStack;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
@ -42,6 +43,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Workflow\Registry;
abstract class FrameworkExtensionTest extends TestCase
{
@ -307,6 +309,14 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertSame(array('draft'), $transitions[4]->getArgument(1));
}
public function testWorkflowServicesCanBeEnabled()
{
$container = $this->createContainerFromFile('workflows_enabled');
$this->assertTrue($container->has(Registry::class));
$this->assertTrue($container->hasDefinition(WorkflowDumpCommand::class));
}
public function testRouter()
{
$container = $this->createContainerFromFile('full');