Skip to content

Commit 8c9858f

Browse files
committed
[Validator][DoctrineBridge][FWBundle] Automatic data validation
1 parent 283d898 commit 8c9858f

File tree

10 files changed

+125
-3
lines changed

10 files changed

+125
-3
lines changed

DependencyInjection/Configuration.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,45 @@ private function addValidationSection(ArrayNodeDefinition $rootNode)
792792
->end()
793793
->end()
794794
->end()
795+
->arrayNode('auto_mapping')
796+
->useAttributeAsKey('namespace')
797+
->normalizeKeys(false)
798+
->beforeNormalization()
799+
->ifArray()
800+
->then(function (array $values): array {
801+
foreach ($values as $k => $v) {
802+
if (isset($v['service'])) {
803+
continue;
804+
}
805+
806+
if (isset($v['namespace'])) {
807+
$values[$k]['services'] = [];
808+
continue;
809+
}
810+
811+
if (!\is_array($v)) {
812+
$values[$v]['services'] = [];
813+
unset($values[$k]);
814+
continue;
815+
}
816+
817+
$tmp = $v;
818+
unset($values[$k]);
819+
$values[$k]['services'] = $tmp;
820+
}
821+
822+
return $values;
823+
})
824+
->end()
825+
->arrayPrototype()
826+
->fixXmlConfig('service')
827+
->children()
828+
->arrayNode('services')
829+
->prototype('scalar')->end()
830+
->end()
831+
->end()
832+
->end()
833+
->end()
795834
->end()
796835
->end()
797836
->end()

DependencyInjection/FrameworkExtension.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
108108
use Symfony\Component\Translation\Translator;
109109
use Symfony\Component\Validator\ConstraintValidatorInterface;
110+
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
110111
use Symfony\Component\Validator\ObjectInitializerInterface;
111112
use Symfony\Component\WebLink\HttpHeaderSerializer;
112113
use Symfony\Component\Workflow;
@@ -280,7 +281,8 @@ public function load(array $configs, ContainerBuilder $container)
280281
$container->removeDefinition('console.command.messenger_debug');
281282
}
282283

283-
$this->registerValidationConfiguration($config['validation'], $container, $loader);
284+
$propertyInfoEnabled = $this->isConfigEnabled($container, $config['property_info']);
285+
$this->registerValidationConfiguration($config['validation'], $container, $loader, $propertyInfoEnabled);
284286
$this->registerEsiConfiguration($config['esi'], $container, $loader);
285287
$this->registerSsiConfiguration($config['ssi'], $container, $loader);
286288
$this->registerFragmentsConfiguration($config['fragments'], $container, $loader);
@@ -301,7 +303,7 @@ public function load(array $configs, ContainerBuilder $container)
301303
$this->registerSerializerConfiguration($config['serializer'], $container, $loader);
302304
}
303305

304-
if ($this->isConfigEnabled($container, $config['property_info'])) {
306+
if ($propertyInfoEnabled) {
305307
$this->registerPropertyInfoConfiguration($container, $loader);
306308
}
307309

@@ -1152,7 +1154,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
11521154
}
11531155
}
11541156

1155-
private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
1157+
private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader, bool $propertyInfoEnabled)
11561158
{
11571159
if (!$this->validatorConfigEnabled = $this->isConfigEnabled($container, $config)) {
11581160
return;
@@ -1203,6 +1205,11 @@ private function registerValidationConfiguration(array $config, ContainerBuilder
12031205
if (!$container->getParameter('kernel.debug')) {
12041206
$validatorBuilder->addMethodCall('setMetadataCache', [new Reference('validator.mapping.cache.symfony')]);
12051207
}
1208+
1209+
$container->setParameter('validator.auto_mapping', $config['auto_mapping']);
1210+
if (!$propertyInfoEnabled || !$config['auto_mapping'] || !class_exists(PropertyInfoLoader::class)) {
1211+
$container->removeDefinition('validator.property_info_loader');
1212+
}
12061213
}
12071214

12081215
private function registerValidatorMapping(ContainerBuilder $container, array $config, array &$files)

FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
use Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass;
5454
use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
5555
use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass;
56+
use Symfony\Component\Validator\DependencyInjection\AddAutoMappingConfigurationPass;
5657
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
5758
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
5859

@@ -124,6 +125,7 @@ public function build(ContainerBuilder $container)
124125
$container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING);
125126
$this->addCompilerPassIfExists($container, AddMimeTypeGuesserPass::class);
126127
$this->addCompilerPassIfExists($container, MessengerPass::class);
128+
$this->addCompilerPassIfExists($container, AddAutoMappingConfigurationPass::class);
127129
$container->addCompilerPass(new RegisterReverseContainerPass(true));
128130
$container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING);
129131

Resources/config/schema/symfony-1.0.xsd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
<xsd:choice minOccurs="0" maxOccurs="unbounded">
191191
<xsd:element name="static-method" type="xsd:string" />
192192
<xsd:element name="mapping" type="file_mapping" />
193+
<xsd:element name="auto-mapping" type="auto_mapping" />
193194
</xsd:choice>
194195

195196
<xsd:attribute name="enabled" type="xsd:boolean" />
@@ -207,6 +208,13 @@
207208
</xsd:sequence>
208209
</xsd:complexType>
209210

211+
<xsd:complexType name="auto_mapping">
212+
<xsd:sequence>
213+
<xsd:element name="service" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
214+
</xsd:sequence>
215+
<xsd:attribute name="namespace" type="xsd:string" use="required" />
216+
</xsd:complexType>
217+
210218
<xsd:simpleType name="email-validation-mode">
211219
<xsd:restriction base="xsd:string">
212220
<xsd:enumeration value="html5" />

Resources/config/validator.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,12 @@
6060
<argument></argument>
6161
<tag name="validator.constraint_validator" alias="Symfony\Component\Validator\Constraints\EmailValidator" />
6262
</service>
63+
64+
<service id="validator.property_info_loader" class="Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader">
65+
<argument type="service" id="property_info" />
66+
<argument type="service" id="property_info" />
67+
68+
<tag name="validator.auto_mapper" />
69+
</service>
6370
</services>
6471
</container>

Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ protected static function getBundleDefaultConfig()
232232
'mapping' => [
233233
'paths' => [],
234234
],
235+
'auto_mapping' => [],
235236
],
236237
'annotations' => [
237238
'cache' => 'php_array',
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
$container->loadFromExtension('framework', [
4+
'property_info' => ['enabled' => true],
5+
'validation' => [
6+
'auto_mapping' => [
7+
'App\\' => ['foo', 'bar'],
8+
'Symfony\\' => ['a', 'b'],
9+
'Foo\\',
10+
],
11+
],
12+
]);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:framework="http://symfony.com/schema/dic/symfony">
5+
6+
<framework:config>
7+
<framework:property-info enabled="true" />
8+
<framework:validation>
9+
<framework:auto-mapping namespace="App\">
10+
<framework:service>foo</framework:service>
11+
<framework:service>bar</framework:service>
12+
</framework:auto-mapping>
13+
<framework:auto-mapping namespace="Symfony\">
14+
<framework:service>a</framework:service>
15+
<framework:service>b</framework:service>
16+
</framework:auto-mapping>
17+
<framework:auto-mapping namespace="Foo\" />
18+
</framework:validation>
19+
</framework:config>
20+
</container>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework:
2+
property_info: { enabled: true }
3+
validation:
4+
auto_mapping:
5+
'App\': ['foo', 'bar']
6+
'Symfony\': ['a', 'b']
7+
'Foo\': []

Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
use Symfony\Component\Serializer\Serializer;
5151
use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
5252
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
53+
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
54+
use Symfony\Component\Validator\Validation;
5355
use Symfony\Component\Workflow;
5456
use Symfony\Contracts\HttpClient\HttpClientInterface;
5557

@@ -1033,6 +1035,23 @@ public function testValidationMapping()
10331035
$this->assertContains('validation.yaml', $calls[4][1][0][2]);
10341036
}
10351037

1038+
public function testValidationAutoMapping()
1039+
{
1040+
if (!class_exists(PropertyInfoLoader::class)) {
1041+
$this->markTestSkipped('Auto-mapping requires symfony/validation 4.2+');
1042+
}
1043+
1044+
$container = $this->createContainerFromFile('validation_auto_mapping');
1045+
$parameter = [
1046+
'App\\' => ['services' => ['foo', 'bar']],
1047+
'Symfony\\' => ['services' => ['a', 'b']],
1048+
'Foo\\' => ['services' => []],
1049+
];
1050+
1051+
$this->assertSame($parameter, $container->getParameter('validator.auto_mapping'));
1052+
$this->assertTrue($container->hasDefinition('validator.property_info_loader'));
1053+
}
1054+
10361055
public function testFormsCanBeEnabledWithoutCsrfProtection()
10371056
{
10381057
$container = $this->createContainerFromFile('form_no_csrf');

0 commit comments

Comments
 (0)