Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbecb816

Browse files
committed
[Workflow] Add support for executing custom workflow definition validators during the container compilation
1 parentd5b5581 commitbecb816

File tree

14 files changed

+256
-29
lines changed

14 files changed

+256
-29
lines changed

‎src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ CHANGELOG
2525
* Set`framework.rate_limiter.limiters.*.lock_factory` to`auto` by default
2626
* Deprecate`RateLimiterFactory` autowiring aliases, use`RateLimiterFactoryInterface` instead
2727
* Allow configuring compound rate limiters
28+
* Support executing custom workflow validators during container compilation
2829

2930
7.2
3031
---

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

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
useSymfony\Component\Validator\Validation;
5252
useSymfony\Component\Webhook\Controller\WebhookController;
5353
useSymfony\Component\WebLink\HttpHeaderSerializer;
54+
useSymfony\Component\Workflow\Validator\DefinitionValidatorInterface;
5455
useSymfony\Component\Workflow\WorkflowEvents;
5556

5657
/**
@@ -402,6 +403,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
402403
->useAttributeAsKey('name')
403404
->prototype('array')
404405
->fixXmlConfig('support')
406+
->fixXmlConfig('definition_validator')
405407
->fixXmlConfig('place')
406408
->fixXmlConfig('transition')
407409
->fixXmlConfig('event_to_dispatch','events_to_dispatch')
@@ -431,11 +433,28 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
431433
->prototype('scalar')
432434
->cannotBeEmpty()
433435
->validate()
434-
->ifTrue(fn ($v) => !class_exists($v) && !interface_exists($v,false))
436+
->ifTrue(staticfn ($v) => !class_exists($v) && !interface_exists($v,false))
435437
->thenInvalid('The supported class or interface "%s" does not exist.')
436438
->end()
437439
->end()
438440
->end()
441+
->arrayNode('definition_validators')
442+
->prototype('scalar')
443+
->cannotBeEmpty()
444+
->validate()
445+
->ifTrue(staticfn ($v) => !class_exists($v))
446+
->thenInvalid('The validation class %s does not exist.')
447+
->end()
448+
->validate()
449+
->ifTrue(staticfn ($v) => !is_a($v, DefinitionValidatorInterface::class,true))
450+
->thenInvalid(\sprintf('The validation class %%s is not an instance of "%s".', DefinitionValidatorInterface::class))
451+
->end()
452+
->validate()
453+
->ifTrue(staticfn ($v) =>1 <= (new \ReflectionClass($v))->getConstructor()?->getNumberOfRequiredParameters())
454+
->thenInvalid('The validation class %s constructor must not have any arguments.')
455+
->end()
456+
->end()
457+
->end()
439458
->scalarNode('support_strategy')
440459
->cannotBeEmpty()
441460
->end()
@@ -447,7 +466,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
447466
->variableNode('events_to_dispatch')
448467
->defaultValue(null)
449468
->validate()
450-
->ifTrue(function ($v) {
469+
->ifTrue(staticfunction ($v) {
451470
if (null ===$v) {
452471
returnfalse;
453472
}
@@ -474,14 +493,14 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
474493
->arrayNode('places')
475494
->beforeNormalization()
476495
->always()
477-
->then(function ($places) {
496+
->then(staticfunction ($places) {
478497
if (!\is_array($places)) {
479498
thrownewInvalidConfigurationException('The "places" option must be an array in workflow configuration.');
480499
}
481500

482501
// It's an indexed array of shape ['place1', 'place2']
483502
if (isset($places[0]) &&\is_string($places[0])) {
484-
returnarray_map(function (string$place) {
503+
returnarray_map(staticfunction (string$place) {
485504
return ['name' =>$place];
486505
},$places);
487506
}
@@ -521,7 +540,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
521540
->arrayNode('transitions')
522541
->beforeNormalization()
523542
->always()
524-
->then(function ($transitions) {
543+
->then(staticfunction ($transitions) {
525544
if (!\is_array($transitions)) {
526545
thrownewInvalidConfigurationException('The "transitions" option must be an array in workflow configuration.');
527546
}
@@ -588,20 +607,20 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
588607
->end()
589608
->end()
590609
->validate()
591-
->ifTrue(function ($v) {
610+
->ifTrue(staticfunction ($v) {
592611
return$v['supports'] &&isset($v['support_strategy']);
593612
})
594613
->thenInvalid('"supports" and "support_strategy" cannot be used together.')
595614
->end()
596615
->validate()
597-
->ifTrue(function ($v) {
616+
->ifTrue(staticfunction ($v) {
598617
return !$v['supports'] && !isset($v['support_strategy']);
599618
})
600619
->thenInvalid('"supports" or "support_strategy" should be configured.')
601620
->end()
602621
->beforeNormalization()
603622
->always()
604-
->then(function ($values) {
623+
->then(staticfunction ($values) {
605624
// Special case to deal with XML when the user wants an empty array
606625
if (\array_key_exists('event_to_dispatch',$values) &&null ===$values['event_to_dispatch']) {
607626
$values['events_to_dispatch'] = [];

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

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,8 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
11171117
}
11181118
}
11191119
$metadataStoreDefinition->replaceArgument(2,$transitionsMetadataDefinition);
1120-
$container->setDefinition(\sprintf('%s.metadata_store',$workflowId),$metadataStoreDefinition);
1120+
$metadataStoreId =\sprintf('%s.metadata_store',$workflowId);
1121+
$container->setDefinition($metadataStoreId,$metadataStoreDefinition);
11211122

11221123
// Create places
11231124
$places =array_column($workflow['places'],'name');
@@ -1128,7 +1129,8 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
11281129
$definitionDefinition->addArgument($places);
11291130
$definitionDefinition->addArgument($transitions);
11301131
$definitionDefinition->addArgument($initialMarking);
1131-
$definitionDefinition->addArgument(newReference(\sprintf('%s.metadata_store',$workflowId)));
1132+
$definitionDefinition->addArgument(newReference($metadataStoreId));
1133+
$definitionDefinitionId =\sprintf('%s.definition',$workflowId);
11321134

11331135
// Create MarkingStore
11341136
$markingStoreDefinition =null;
@@ -1142,14 +1144,26 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
11421144
$markingStoreDefinition =newReference($workflow['marking_store']['service']);
11431145
}
11441146

1147+
// Validation
1148+
$workflow['definition_validators'][] =match ($workflow['type']) {
1149+
'state_machine' =>Workflow\Validator\StateMachineValidator::class,
1150+
'workflow' =>Workflow\Validator\WorkflowValidator::class,
1151+
default =>thrownew \LogicException(\sprintf('Invalid workflow type "%s".',$workflow['type'])),
1152+
};
1153+
11451154
// Create Workflow
11461155
$workflowDefinition =newChildDefinition(\sprintf('%s.abstract',$type));
1147-
$workflowDefinition->replaceArgument(0,newReference(\sprintf('%s.definition',$workflowId)));
1156+
$workflowDefinition->replaceArgument(0,newReference($definitionDefinitionId));
11481157
$workflowDefinition->replaceArgument(1,$markingStoreDefinition);
11491158
$workflowDefinition->replaceArgument(3,$name);
11501159
$workflowDefinition->replaceArgument(4,$workflow['events_to_dispatch']);
11511160

1152-
$workflowDefinition->addTag('workflow', ['name' =>$name,'metadata' =>$workflow['metadata']]);
1161+
$workflowDefinition->addTag('workflow', [
1162+
'name' =>$name,
1163+
'metadata' =>$workflow['metadata'],
1164+
'definition_validators' =>$workflow['definition_validators'],
1165+
'definition_id' =>$definitionDefinitionId,
1166+
]);
11531167
if ('workflow' ===$type) {
11541168
$workflowDefinition->addTag('workflow.workflow', ['name' =>$name]);
11551169
}elseif ('state_machine' ===$type) {
@@ -1158,21 +1172,10 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
11581172

11591173
// Store to container
11601174
$container->setDefinition($workflowId,$workflowDefinition);
1161-
$container->setDefinition(\sprintf('%s.definition',$workflowId),$definitionDefinition);
1175+
$container->setDefinition($definitionDefinitionId,$definitionDefinition);
11621176
$container->registerAliasForArgument($workflowId, WorkflowInterface::class,$name.'.'.$type);
11631177
$container->registerAliasForArgument($workflowId, WorkflowInterface::class,$name);
11641178

1165-
// Validate Workflow
1166-
if ('state_machine' ===$workflow['type']) {
1167-
$validator =newWorkflow\Validator\StateMachineValidator();
1168-
}else {
1169-
$validator =newWorkflow\Validator\WorkflowValidator();
1170-
}
1171-
1172-
$trs =array_map(fn (Reference$ref):Workflow\Transition =>$container->get((string)$ref),$transitions);
1173-
$realDefinition =newWorkflow\Definition($places,$trs,$initialMarking);
1174-
$validator->validate($realDefinition,$name);
1175-
11761179
// Add workflow to Registry
11771180
if ($workflow['supports']) {
11781181
foreach ($workflow['supports']as$supportedClassName) {

‎src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
useSymfony\Component\VarExporter\Internal\Registry;
7878
useSymfony\Component\Workflow\DependencyInjection\WorkflowDebugPass;
7979
useSymfony\Component\Workflow\DependencyInjection\WorkflowGuardListenerPass;
80+
useSymfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass;
8081

8182
// Help opcache.preload discover always-needed symbols
8283
class_exists(ApcuAdapter::class);
@@ -173,6 +174,7 @@ public function build(ContainerBuilder $container): void
173174
$container->addCompilerPass(newCachePoolPrunerPass(), PassConfig::TYPE_AFTER_REMOVING);
174175
$this->addCompilerPassIfExists($container, FormPass::class);
175176
$this->addCompilerPassIfExists($container, WorkflowGuardListenerPass::class);
177+
$this->addCompilerPassIfExists($container, WorkflowValidatorPass::class);
176178
$container->addCompilerPass(newResettableServicePass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
177179
$container->addCompilerPass(newRegisterLocaleAwareServicesPass());
178180
$container->addCompilerPass(newTestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);

‎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
@@ -449,6 +449,7 @@
449449
<xsd:elementname="initial-marking"type="xsd:string"minOccurs="0"maxOccurs="unbounded" />
450450
<xsd:elementname="marking-store"type="marking_store"minOccurs="0"maxOccurs="1" />
451451
<xsd:elementname="support"type="xsd:string"minOccurs="0"maxOccurs="unbounded" />
452+
<xsd:elementname="definition-validator"type="xsd:string"minOccurs="0"maxOccurs="unbounded" />
452453
<xsd:elementname="event-to-dispatch"type="event_to_dispatch"minOccurs="0"maxOccurs="unbounded" />
453454
<xsd:elementname="place"type="place"minOccurs="0"maxOccurs="unbounded" />
454455
<xsd:elementname="transition"type="transition"minOccurs="0"maxOccurs="unbounded" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespaceSymfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator;
4+
5+
useSymfony\Component\Workflow\Definition;
6+
useSymfony\Component\Workflow\Validator\DefinitionValidatorInterface;
7+
8+
class DefinitionValidatorimplements DefinitionValidatorInterface
9+
{
10+
publicstaticbool$called =false;
11+
12+
publicfunctionvalidate(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-trailenabled="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:placename="draft" />
1718
<framework:placename="wait_for_journalist" />
1819
<framework:placename="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: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
usePsr\Log\LoggerAwareInterface;
1616
useSymfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
1717
useSymfony\Bundle\FrameworkBundle\FrameworkBundle;
18+
useSymfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Fixtures\Workflow\Validator\DefinitionValidator;
1819
useSymfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\DummyMessage;
1920
useSymfony\Bundle\FrameworkBundle\Tests\TestCase;
2021
useSymfony\Bundle\FullStack;
@@ -287,7 +288,11 @@ public function testProfilerCollectSerializerDataEnabled()
287288

288289
publicfunctiontestWorkflows()
289290
{
290-
$container =$this->createContainerFromFile('workflows');
291+
DefinitionValidator::$called =false;
292+
293+
$container =$this->createContainerFromFile('workflows', compile:false);
294+
$container->addCompilerPass(new \Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass());
295+
$container->compile();
291296

292297
$this->assertTrue($container->hasDefinition('workflow.article'),'Workflow is registered as a service');
293298
$this->assertSame('workflow.abstract',$container->getDefinition('workflow.article')->getParent());
@@ -310,6 +315,7 @@ public function testWorkflows()
310315
],$tags['workflow'][0]['metadata'] ??null);
311316

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

314320
$workflowDefinition =$container->getDefinition('workflow.article.definition');
315321

@@ -403,7 +409,9 @@ public function testWorkflowAreValidated()
403409
{
404410
$this->expectException(InvalidDefinitionException::class);
405411
$this->expectExceptionMessage('A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" were found on StateMachine "my_workflow".');
406-
$this->createContainerFromFile('workflow_not_valid');
412+
$container =$this->createContainerFromFile('workflow_not_valid', compile:false);
413+
$container->addCompilerPass(new \Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass());
414+
$container->compile();
407415
}
408416

409417
publicfunctiontestWorkflowCannotHaveBothSupportsAndSupportStrategy()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp