minor #20458 Added XML support for Workflow configuration (wouterj, xabbuh)

This PR was merged into the 3.2-dev branch.

Discussion
----------

Added XML support for Workflow configuration

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | symfony/symfony-docs#6871

Commits
-------

94a7e7e [Workflow] streamline XML schema definition
6381caa Added XML support for Workflow configuration
This commit is contained in:
Christophe Coevoet 2016-11-16 09:33:36 +01:00
commit de787544f0
9 changed files with 313 additions and 100 deletions

View File

@ -231,16 +231,21 @@ class Configuration implements ConfigurationInterface
private function addWorkflowSection(ArrayNodeDefinition $rootNode)
{
$rootNode
->fixXmlConfig('workflow')
->children()
->arrayNode('workflows')
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('support')
->fixXmlConfig('place')
->fixXmlConfig('transition')
->children()
->enumNode('type')
->values(array('workflow', 'state_machine'))
->defaultValue('workflow')
->end()
->arrayNode('marking_store')
->fixXmlConfig('argument')
->children()
->enumNode('type')
->values(array('multiple_state', 'single_state'))

View File

@ -8,7 +8,7 @@
<xsd:element name="config" type="config" />
<xsd:complexType name="config">
<xsd:all>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="assets" type="assets" minOccurs="0" maxOccurs="1" />
<xsd:element name="form" type="form" minOccurs="0" maxOccurs="1" />
<xsd:element name="csrf-protection" type="csrf_protection" minOccurs="0" maxOccurs="1" />
@ -26,8 +26,8 @@
<xsd:element name="serializer" type="serializer" minOccurs="0" maxOccurs="1" />
<xsd:element name="property-info" type="property_info" minOccurs="0" maxOccurs="1" />
<xsd:element name="cache" type="cache" minOccurs="0" maxOccurs="1" />
<xsd:element name="workflows" type="workflows" minOccurs="0" maxOccurs="1" />
</xsd:all>
<xsd:element name="workflow" type="workflow" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attribute name="http-method-override" type="xsd:boolean" />
<xsd:attribute name="trusted-proxies" type="xsd:string" />
@ -228,42 +228,45 @@
<xsd:attribute name="clearer" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="workflows">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="workflow" type="workflow" />
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="workflow">
<xsd:sequence>
<xsd:element name="marking-store" type="marking_store" />
<xsd:element name="supports" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="places" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="transitions" type="transitions" />
<xsd:element name="support" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="place" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="transition" type="transition" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="type" type="workflow_type" />
<xsd:attribute name="initial-place" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="marking_store">
<xsd:sequence>
<xsd:element name="type" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="arguments" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="service" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="argument" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="type" type="marking_store_type" />
<xsd:attribute name="service" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="transitions">
<xsd:sequence>
<xsd:element name="transition" type="transition" />
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="marking_store_type">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="multiple_state" />
<xsd:enumeration value="single_state" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="transition">
<xsd:sequence>
<xsd:element name="from" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
<xsd:element name="to" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
<xsd:simpleType name="workflow_type">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="state_machine" />
<xsd:enumeration value="workflow" />
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

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

View File

@ -0,0 +1,92 @@
<?php
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest;
$container->loadFromExtension('framework', array(
'workflows' => array(
'article' => array(
'type' => 'workflow',
'marking_store' => array(
'type' => 'multiple_state',
),
'supports' => array(
FrameworkExtensionTest::class,
),
'initial_place' => 'draft',
'places' => array(
'draft',
'wait_for_journalist',
'approved_by_journalist',
'wait_for_spellchecker',
'approved_by_spellchecker',
'published',
),
'transitions' => array(
'request_review' => array(
'from' => 'draft',
'to' => array('wait_for_journalist', 'wait_for_spellchecker'),
),
'journalist_approval' => array(
'from' => 'wait_for_journalist',
'to' => 'approved_by_journalist',
),
'spellchecker_approval' => array(
'from' => 'wait_for_spellchecker',
'to' => 'approved_by_spellchecker',
),
'publish' => array(
'from' => array('approved_by_journalist', 'approved_by_spellchecker'),
'to' => 'published',
),
),
),
'pull_request' => array(
'type' => 'state_machine',
'marking_store' => array(
'type' => 'single_state',
),
'supports' => array(
FrameworkExtensionTest::class,
),
'initial_place' => 'start',
'places' => array(
'start',
'coding',
'travis',
'review',
'merged',
'closed',
),
'transitions' => array(
'submit' => array(
'from' => 'start',
'to' => 'travis',
),
'update' => array(
'from' => array('coding', 'travis', 'review'),
'to' => 'travis',
),
'wait_for_review' => array(
'from' => 'travis',
'to' => 'review',
),
'request_change' => array(
'from' => 'review',
'to' => 'coding',
),
'accept' => array(
'from' => 'review',
'to' => 'merged',
),
'reject' => array(
'from' => 'review',
'to' => 'closed',
),
'reopen' => array(
'from' => 'closed',
'to' => 'review',
),
),
),
),
));

View File

@ -1,29 +0,0 @@
<?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:workflows>
<framework:workflow name="my_workflow">
<framework:marking-store>
<framework:type>multiple_state</framework:type>
<framework:arguments>a</framework:arguments>
<framework:arguments>a</framework:arguments>
</framework:marking-store>
<framework:supports>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:supports>
<framework:places>first</framework:places>
<framework:places>last</framework:places>
<framework:transitions>
<framework:transition name="foobar">
<framework:from>a</framework:from>
<framework:to>a</framework:to>
</framework:transition>
</framework:transitions>
</framework:workflow>
</framework:workflows>
</framework:config>
</container>

View File

@ -0,0 +1,83 @@
<?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="article" type="workflow" initial-place="draft">
<framework:marking-store type="multiple_state">
<framework:argument>a</framework:argument>
<framework:argument>a</framework:argument>
</framework:marking-store>
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
<framework:place>draft</framework:place>
<framework:place>wait_for_journalist</framework:place>
<framework:place>approved_by_journalist</framework:place>
<framework:place>wait_for_spellchecker</framework:place>
<framework:place>approved_by_spellchecker</framework:place>
<framework:place>published</framework:place>
<framework:transition name="request_review">
<framework:from>draft</framework:from>
<framework:to>wait_for_journalist</framework:to>
<framework:to>wait_for_spellchecker</framework:to>
</framework:transition>
<framework:transition name="journalist_approval">
<framework:from>wait_for_journalist</framework:from>
<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:transition>
<framework:transition name="publish">
<framework:from>approved_by_journalist</framework:from>
<framework:from>approved_by_spellchker</framework:from>
<framework:to>published</framework:to>
</framework:transition>
</framework:workflow>
<framework:workflow name="pull_request" type="state_machine" initial-place="start">
<framework:marking-store type="single_state"/>
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
<framework:place>start</framework:place>
<framework:place>coding</framework:place>
<framework:place>travis</framework:place>
<framework:place>review</framework:place>
<framework:place>merged</framework:place>
<framework:place>closed</framework:place>
<framework:transition name="submit">
<framework:from>start</framework:from>
<framework:to>travis</framework:to>
</framework:transition>
<framework:transition name="update">
<framework:from>coding</framework:from>
<framework:from>travis</framework:from>
<framework:from>review</framework:from>
<framework:to>travis</framework:to>
</framework:transition>
<framework:transition name="wait_for_review">
<framework:from>travis</framework:from>
<framework:to>review</framework:to>
</framework:transition>
<framework:transition name="request_change">
<framework:from>review</framework:from>
<framework:to>coding</framework:to>
</framework:transition>
<framework:transition name="accept">
<framework:from>review</framework:from>
<framework:to>merged</framework:to>
</framework:transition>
<framework:transition name="reject">
<framework:from>review</framework:from>
<framework:to>closed</framework:to>
</framework:transition>
<framework:transition name="reopen">
<framework:from>closed</framework:from>
<framework:to>review</framework:to>
</framework:transition>
</framework:workflow>
</framework:config>
</container>

View File

@ -1,16 +0,0 @@
framework:
workflows:
my_workflow:
marking_store:
type: multiple_state
supports:
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
places:
- first
- last
transitions:
go:
from:
- first
to:
- last

View File

@ -0,0 +1,65 @@
framework:
workflows:
article:
type: workflow
marking_store:
type: multiple_state
supports:
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
initial_place: draft
places:
- draft
- wait_for_journalist
- approved_by_journalist
- wait_for_spellchecker
- approved_by_spellchecker
- published
transitions:
request_review:
from: [draft]
to: [wait_for_journalist, wait_for_spellchecker]
journalist_approval:
from: [wait_for_journalist]
to: [approved_by_journalist]
spellchecker_approval:
from: [wait_for_spellchecker]
to: [approved_by_spellchecker]
publish:
from: [approved_by_journalist, approved_by_spellchecker]
to: [published]
pull_request:
type: state_machine
marking_store:
type: single_state
supports:
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
initial_place: start
places:
- start
- coding
- travis
- review
- merged
- closed
transitions:
submit:
from: start
to: travis
update:
from: [coding, travis, review]
to: travis
wait_for_review:
from: travis
to: review
request_change:
from: review
to: coding
accept:
from: review
to: merged
reject:
from: review
to: closed
reopen:
from: closed
to: review

View File

@ -120,11 +120,51 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertFalse($container->hasDefinition('data_collector.config'), '->registerProfilerConfiguration() does not load collectors.xml');
}
public function testWorkflow()
public function testWorkflows()
{
$container = $this->createContainerFromFile('workflow');
$container = $this->createContainerFromFile('workflows');
$this->assertTrue($container->hasDefinition('workflow.my_workflow'));
$this->assertTrue($container->hasDefinition('workflow.article', 'Workflow is registered as a service'));
$this->assertTrue($container->hasDefinition('workflow.article.definition', 'Workflow definition is registered as a service'));
$workflowDefinition = $container->getDefinition('workflow.article.definition');
$this->assertSame(
array(
'draft',
'wait_for_journalist',
'approved_by_journalist',
'wait_for_spellchecker',
'approved_by_spellchecker',
'published',
),
$workflowDefinition->getArgument(0),
'Places are passed to the workflow definition'
);
$this->assertSame(array('workflow.definition' => array(array('name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state'))), $workflowDefinition->getTags());
$this->assertTrue($container->hasDefinition('state_machine.pull_request', 'State machine is registered as a service'));
$this->assertTrue($container->hasDefinition('state_machine.pull_request.definition', 'State machine definition is registered as a service'));
$this->assertCount(4, $workflowDefinition->getArgument(1));
$this->assertSame('draft', $workflowDefinition->getArgument(2));
$stateMachineDefinition = $container->getDefinition('state_machine.pull_request.definition');
$this->assertSame(
array(
'start',
'coding',
'travis',
'review',
'merged',
'closed',
),
$stateMachineDefinition->getArgument(0),
'Places are passed to the state machine definition'
);
$this->assertSame(array('workflow.definition' => array(array('name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state'))), $stateMachineDefinition->getTags());
$this->assertCount(9, $stateMachineDefinition->getArgument(1));
$this->assertSame('start', $stateMachineDefinition->getArgument(2));
}
public function testRouter()