Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 67b9b6b

Browse files
committed
[Workflow] Add support for executing custom workflow definition validators during the container compilation
1 parent 2ffd266 commit 67b9b6b

File tree

10 files changed

+110
-0
lines changed

10 files changed

+110
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ CHANGELOG
1616
* Deprecate `session.sid_length` and `session.sid_bits_per_character` config options
1717
* Add the ability to use an existing service as a lock/semaphore resource
1818
* Add support for configuring multiple serializer instances via the configuration
19+
* Add support for executing custom workflow definition validators during the
20+
container compilation
1921

2022
7.1
2123
---

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
use Symfony\Component\Validator\Validation;
5050
use Symfony\Component\Webhook\Controller\WebhookController;
5151
use Symfony\Component\WebLink\HttpHeaderSerializer;
52+
use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface;
5253
use Symfony\Component\Workflow\WorkflowEvents;
5354

5455
/**
@@ -381,6 +382,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
381382
->useAttributeAsKey('name')
382383
->prototype('array')
383384
->fixXmlConfig('support')
385+
->fixXmlConfig('definition_validator')
384386
->fixXmlConfig('place')
385387
->fixXmlConfig('transition')
386388
->fixXmlConfig('event_to_dispatch', 'events_to_dispatch')
@@ -418,6 +420,23 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
418420
->end()
419421
->end()
420422
->end()
423+
->arrayNode('definition_validators')
424+
->prototype('scalar')
425+
->cannotBeEmpty()
426+
->validate()
427+
->ifTrue(fn ($v) => !class_exists($v))
428+
->thenInvalid('The validation class %s does not exist.')
429+
->end()
430+
->validate()
431+
->ifTrue(fn ($v) => !is_a($v, DefinitionValidatorInterface::class, true))
432+
->thenInvalid(\sprintf('The validation class %%s is not an instance of %s.', DefinitionValidatorInterface::class))
433+
->end()
434+
->validate()
435+
->ifTrue(fn ($v) => 1 <= (new \ReflectionClass($v))->getConstructor()?->getNumberOfRequiredParameters())
436+
->thenInvalid('The validation class %s constructor must not have any arguments.')
437+
->end()
438+
->end()
439+
->end()
421440
->scalarNode('support_strategy')
422441
->cannotBeEmpty()
423442
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,10 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
10541054
$realDefinition = new Workflow\Definition($places, $trs, $initialMarking);
10551055
$validator->validate($realDefinition, $name);
10561056

1057+
foreach ($workflow['definition_validators'] as $validatorClass) {
1058+
(new $validatorClass())->validate($realDefinition, $name);
1059+
}
1060+
10571061
// Add workflow to Registry
10581062
if ($workflow['supports']) {
10591063
foreach ($workflow['supports'] as $supportedClassName) {

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@
397397
<xsd:element name="initial-marking" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
398398
<xsd:element name="marking-store" type="marking_store" minOccurs="0" maxOccurs="1" />
399399
<xsd:element name="support" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
400+
<xsd:element name="definition-validator" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
400401
<xsd:element name="event-to-dispatch" type="event_to_dispatch" minOccurs="0" maxOccurs="unbounded" />
401402
<xsd:element name="place" type="place" minOccurs="0" maxOccurs="unbounded" />
402403
<xsd:element name="transition" type="transition" minOccurs="0" maxOccurs="unbounded" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator;
4+
5+
use Symfony\Component\Workflow\Definition;
6+
use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface;
7+
8+
class DefinitionValidator implements DefinitionValidatorInterface
9+
{
10+
public static bool $called = false;
11+
12+
public function validate(Definition $definition, string $name): void
13+
{
14+
self::$called = true;
15+
}
16+
}

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
'supports' => [
1414
FrameworkExtensionTestCase::class,
1515
],
16+
'definition_validators' => [
17+
Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator\DefinitionValidator::class,
18+
],
1619
'initial_marking' => ['draft'],
1720
'metadata' => [
1821
'title' => 'article workflow',

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<framework:audit-trail enabled="true"/>
1414
<framework:initial-marking>draft</framework:initial-marking>
1515
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTestCase</framework:support>
16+
<framework:definition-validator>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator\DefinitionValidator</framework:definition-validator>
1617
<framework:place name="draft" />
1718
<framework:place name="wait_for_journalist" />
1819
<framework:place name="approved_by_journalist" />

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ framework:
99
type: workflow
1010
supports:
1111
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTestCase
12+
definition_validators:
13+
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator\DefinitionValidator
1214
initial_marking: [draft]
1315
metadata:
1416
title: article workflow

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait;
1717
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
1818
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
19+
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator\DefinitionValidator;
1920
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage;
2021
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
2122
use Symfony\Bundle\FullStack;
@@ -295,6 +296,8 @@ public function testProfilerCollectSerializerDataDefaultDisabled()
295296

296297
public function testWorkflows()
297298
{
299+
DefinitionValidator::$called = false;
300+
298301
$container = $this->createContainerFromFile('workflows');
299302

300303
$this->assertTrue($container->hasDefinition('workflow.article'), 'Workflow is registered as a service');
@@ -318,6 +321,7 @@ public function testWorkflows()
318321
], $tags['workflow'][0]['metadata'] ?? null);
319322

320323
$this->assertTrue($container->hasDefinition('workflow.article.definition'), 'Workflow definition is registered as a service');
324+
$this->assertTrue(DefinitionValidator::$called, 'DefinitionValidator is called');
321325

322326
$workflowDefinition = $container->getDefinition('workflow.article.definition');
323327

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,53 @@ public function testWorkflowValidationStateMachine()
128128
});
129129
}
130130

131+
/**
132+
* @dataProvider provideWorkflowValidationCustomTests
133+
*/
134+
public function testWorkflowValidationCustomBroken(string $class, string $message)
135+
{
136+
$this->expectException(InvalidConfigurationException::class);
137+
$this->expectExceptionMessage($message);
138+
$this->createContainerFromClosure(function ($container) use ($class) {
139+
$container->loadFromExtension('framework', [
140+
'annotations' => false,
141+
'http_method_override' => false,
142+
'handle_all_throwables' => true,
143+
'php_errors' => ['log' => true],
144+
'workflows' => [
145+
'article' => [
146+
'type' => 'state_machine',
147+
'supports' => [
148+
__CLASS__,
149+
],
150+
'places' => [
151+
'a',
152+
'b',
153+
],
154+
'transitions' => [
155+
'a_to_b' => [
156+
'from' => ['a'],
157+
'to' => ['b'],
158+
],
159+
],
160+
'definition_validators' => [
161+
$class,
162+
],
163+
],
164+
],
165+
]);
166+
});
167+
}
168+
169+
public static function provideWorkflowValidationCustomTests()
170+
{
171+
yield ['classDoesNotExist', 'Invalid configuration for path "framework.workflows.workflows.article.definition_validators.0": The validation class "classDoesNotExist" does not exist.'];
172+
173+
yield [\DateTime::class, 'Invalid configuration for path "framework.workflows.workflows.article.definition_validators.0": The validation class "DateTime" is not an instance of Symfony\Component\Workflow\Validator\DefinitionValidatorInterface.'];
174+
175+
yield [WorkflowValidatorWithConstructor::class, 'Invalid configuration for path "framework.workflows.workflows.article.definition_validators.0": The validation class "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Tests\\\\DependencyInjection\\\\WorkflowValidatorWithConstructor" constructor must not have any arguments.'];
176+
}
177+
131178
public function testWorkflowDefaultMarkingStoreDefinition()
132179
{
133180
$container = $this->createContainerFromClosure(function ($container) {
@@ -266,3 +313,14 @@ public function testRateLimiterIsTagged()
266313
$this->assertSame('second', $container->getDefinition('limiter.second')->getTag('rate_limiter')[0]['name']);
267314
}
268315
}
316+
317+
class WorkflowValidatorWithConstructor implements \Symfony\Component\Workflow\Validator\DefinitionValidatorInterface
318+
{
319+
public function __construct(bool $enabled)
320+
{
321+
}
322+
323+
public function validate(\Symfony\Component\Workflow\Definition $definition, string $name): void
324+
{
325+
}
326+
}

0 commit comments

Comments
 (0)