Skip to content

Commit 31e1344

Browse files
committed
[Workflow] Add a way to add more definition validator
1 parent 78c6ceb commit 31e1344

File tree

8 files changed

+207
-0
lines changed

8 files changed

+207
-0
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@
183183
use Symfony\Component\Webhook\Controller\WebhookController;
184184
use Symfony\Component\WebLink\HttpHeaderSerializer;
185185
use Symfony\Component\Workflow;
186+
use Symfony\Component\Workflow\Validator\ConfiguredDefinitionValidatorInterface;
186187
use Symfony\Component\Workflow\WorkflowInterface;
187188
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
188189
use Symfony\Component\Yaml\Yaml;
@@ -1010,6 +1011,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
10101011
$definitionDefinition->addArgument($transitions);
10111012
$definitionDefinition->addArgument($initialMarking);
10121013
$definitionDefinition->addArgument(new Reference(sprintf('%s.metadata_store', $workflowId)));
1014+
$definitionDefinition->addTag('workflow.definition', ['name' => $name]);
10131015

10141016
// Create MarkingStore
10151017
$markingStoreDefinition = null;
@@ -1104,6 +1106,9 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
11041106
$container->setParameter('workflow.has_guard_listeners', true);
11051107
}
11061108
}
1109+
1110+
$container->registerForAutoconfiguration(ConfiguredDefinitionValidatorInterface::class)
1111+
->addTag('workflow.definition_validator');
11071112
}
11081113

11091114
private function registerDebugConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
7171
use Symfony\Component\VarExporter\Internal\Hydrator;
7272
use Symfony\Component\VarExporter\Internal\Registry;
73+
use Symfony\Component\Workflow\DependencyInjection\DefinitionValidatorPass;
7374
use Symfony\Component\Workflow\DependencyInjection\WorkflowDebugPass;
7475
use Symfony\Component\Workflow\DependencyInjection\WorkflowGuardListenerPass;
7576

@@ -158,6 +159,7 @@ public function build(ContainerBuilder $container): void
158159
$container->addCompilerPass(new CachePoolPrunerPass(), PassConfig::TYPE_AFTER_REMOVING);
159160
$this->addCompilerPassIfExists($container, FormPass::class);
160161
$this->addCompilerPassIfExists($container, WorkflowGuardListenerPass::class);
162+
$this->addCompilerPassIfExists($container, DefinitionValidatorPass::class);
161163
$container->addCompilerPass(new ResettableServicePass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
162164
$container->addCompilerPass(new RegisterLocaleAwareServicesPass());
163165
$container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);

src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

14+
use Symfony\Component\Workflow\CacheWarmer\DefinitionValidatorCacheWarmer;
1415
use Symfony\Component\Workflow\EventListener\ExpressionLanguage;
1516
use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
1617
use Symfony\Component\Workflow\Registry;
@@ -42,5 +43,10 @@
4243
->set('workflow.registry', Registry::class)
4344
->alias(Registry::class, 'workflow.registry')
4445
->set('workflow.security.expression_language', ExpressionLanguage::class)
46+
->set('workflow.cache_warmer.definition_validator', DefinitionValidatorCacheWarmer::class)
47+
->args([
48+
abstract_arg('definition and validators'),
49+
])
50+
->tag('kernel.cache_warmer')
4551
;
4652
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
}
17+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Workflow\CacheWarmer;
13+
14+
use Symfony\Component\Workflow\Definition;
15+
use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface;
16+
17+
final class DefinitionAndValidator
18+
{
19+
public function __construct(
20+
public readonly DefinitionValidatorInterface $validator,
21+
public readonly Definition $definition,
22+
public readonly string $name,
23+
) {
24+
}
25+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Workflow\CacheWarmer;
13+
14+
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
15+
use Symfony\Component\Workflow\CacheWarmer\Model\DefinitionAndValidator;
16+
17+
final class DefinitionValidatorCacheWarmer implements CacheWarmerInterface
18+
{
19+
/**
20+
* @param iterable<DefinitionAndValidator> $definitionAndValidators
21+
*/
22+
public function __construct(
23+
private readonly iterable $definitionAndValidators,
24+
) {
25+
}
26+
27+
public function isOptional(): bool
28+
{
29+
return false;
30+
}
31+
32+
public function warmUp(string $cacheDir, ?string $buildDir = null): array
33+
{
34+
foreach ($this->definitionAndValidators as $definitionAndValidator) {
35+
$definitionAndValidator
36+
->validator
37+
->validate($definitionAndValidator->definition, $definitionAndValidator->name)
38+
;
39+
}
40+
41+
return [];
42+
}
43+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Workflow\DependencyInjection;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Definition;
17+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
18+
use Symfony\Component\DependencyInjection\Reference;
19+
use Symfony\Component\Workflow\CacheWarmer\DefinitionAndValidator;
20+
use Symfony\Component\Workflow\Validator\ConfiguredDefinitionValidatorInterface;
21+
22+
/**
23+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
24+
*/
25+
class DefinitionValidatorPass implements CompilerPassInterface
26+
{
27+
public function process(ContainerBuilder $container): void
28+
{
29+
if (!$container->hasDefinition('workflow.cache_warmer.definition_validator')) {
30+
return;
31+
}
32+
33+
$definitions = [];
34+
foreach ($container->findTaggedServiceIds('workflow.definition') as $id => $attributes) {
35+
$name = $attributes[0]['name'] ?? throw new InvalidArgumentException(sprintf('The "name" attribute is mandatory for the "workflow.definition" tag. Check the tag for service "%s".', $id));
36+
$definitions[$name] = new Reference($id);
37+
}
38+
39+
40+
$definitionAndValidators = [];
41+
foreach ($container->findTaggedServiceIds('workflow.definition_validator') as $id => $attributes)
42+
{
43+
$def = $container->getDefinition($id);
44+
45+
$class = $def->getClass();
46+
47+
if (!$r = $container->getReflectionClass($class)) {
48+
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
49+
}
50+
if (!$r->isSubclassOf(ConfiguredDefinitionValidatorInterface::class)) {
51+
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, ConfiguredDefinitionValidatorInterface::class));
52+
}
53+
54+
foreach ($class::getSupportedWorkflows() as $name) {
55+
if ('*' === $name) {
56+
foreach ($definitions as $definitionName => $definition) {
57+
$definitionAndValidators[] = new Definition(
58+
DefinitionAndValidator::class,
59+
[
60+
new Reference($id),
61+
$definition,
62+
$definitionName,
63+
]
64+
);
65+
}
66+
} elseif (isset($definitions[$name])) {
67+
$definitionAndValidators[] = new Definition(
68+
DefinitionAndValidator::class,
69+
[
70+
new Reference($id),
71+
$definitions[$name],
72+
$name,
73+
]
74+
);
75+
} else {
76+
throw new InvalidArgumentException(sprintf('The workflow "%s" does not exist. Check the "getConfiguration()" method of the service "%s".', $name, $id));
77+
}
78+
}
79+
}
80+
81+
$container
82+
->getDefinition('workflow.cache_warmer.definition_validator')
83+
->replaceArgument(0, $definitionAndValidators)
84+
;
85+
}
86+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Workflow\Validator;
13+
14+
/**
15+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
16+
*/
17+
interface ConfiguredDefinitionValidatorInterface extends DefinitionValidatorInterface
18+
{
19+
/**
20+
* @return list<string> A list of workflow name, or "*" for all workflows
21+
*/
22+
public static function getSupportedWorkflows(): iterable;
23+
}

0 commit comments

Comments
 (0)