Skip to content

Commit bc53e4b

Browse files
ogizanaginicolas-grekas
authored andcommitted
[Validator] Fix auto-mapping constraints should not be validated
1 parent 2a2d2bc commit bc53e4b

File tree

8 files changed

+115
-40
lines changed

8 files changed

+115
-40
lines changed

src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderParentEntity;
2222
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
2323
use Symfony\Bridge\Doctrine\Validator\DoctrineLoader;
24-
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
2524
use Symfony\Component\Validator\Constraints\Length;
25+
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
2626
use Symfony\Component\Validator\Mapping\CascadingStrategy;
2727
use Symfony\Component\Validator\Mapping\ClassMetadata;
2828
use Symfony\Component\Validator\Mapping\Loader\AutoMappingTrait;
29+
use Symfony\Component\Validator\Mapping\PropertyMetadata;
2930
use Symfony\Component\Validator\Mapping\TraversalStrategy;
3031
use Symfony\Component\Validator\Tests\Fixtures\Entity;
3132
use Symfony\Component\Validator\Validation;
@@ -141,11 +142,12 @@ public function testLoadClassMetadata()
141142
$this->assertInstanceOf(Length::class, $textFieldConstraints[0]);
142143
$this->assertSame(1000, $textFieldConstraints[0]->max);
143144

145+
/** @var PropertyMetadata[] $noAutoMappingMetadata */
144146
$noAutoMappingMetadata = $classMetadata->getPropertyMetadata('noAutoMapping');
145147
$this->assertCount(1, $noAutoMappingMetadata);
146148
$noAutoMappingConstraints = $noAutoMappingMetadata[0]->getConstraints();
147-
$this->assertCount(1, $noAutoMappingConstraints);
148-
$this->assertInstanceOf(DisableAutoMapping::class, $noAutoMappingConstraints[0]);
149+
$this->assertCount(0, $noAutoMappingConstraints);
150+
$this->assertSame(AutoMappingStrategy::DISABLED, $noAutoMappingMetadata[0]->getAutoMappingStrategy());
149151
}
150152

151153
public function testFieldMappingsConfiguration()
@@ -207,13 +209,15 @@ public function testClassNoAutoMapping()
207209
$classMetadata = $validator->getMetadataFor(new DoctrineLoaderNoAutoMappingEntity());
208210

209211
$classConstraints = $classMetadata->getConstraints();
210-
$this->assertCount(1, $classConstraints);
211-
$this->assertInstanceOf(DisableAutoMapping::class, $classConstraints[0]);
212+
$this->assertCount(0, $classConstraints);
213+
$this->assertSame(AutoMappingStrategy::DISABLED, $classMetadata->getAutoMappingStrategy());
212214

213215
$maxLengthMetadata = $classMetadata->getPropertyMetadata('maxLength');
214216
$this->assertEmpty($maxLengthMetadata);
215217

218+
/** @var PropertyMetadata[] $autoMappingExplicitlyEnabledMetadata */
216219
$autoMappingExplicitlyEnabledMetadata = $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled');
217-
$this->assertCount(2, $autoMappingExplicitlyEnabledMetadata[0]->constraints);
220+
$this->assertCount(1, $autoMappingExplicitlyEnabledMetadata[0]->constraints);
221+
$this->assertSame(AutoMappingStrategy::ENABLED, $autoMappingExplicitlyEnabledMetadata[0]->getAutoMappingStrategy());
218222
}
219223
}

src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616
use Doctrine\ORM\Mapping\ClassMetadataInfo;
1717
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
1818
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
19-
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
20-
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
2119
use Symfony\Component\Validator\Constraints\Length;
2220
use Symfony\Component\Validator\Constraints\Valid;
21+
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
2322
use Symfony\Component\Validator\Mapping\ClassMetadata;
2423
use Symfony\Component\Validator\Mapping\Loader\AutoMappingTrait;
2524
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
@@ -76,13 +75,16 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
7675
$enabledForProperty = $enabledForClass;
7776
$lengthConstraint = null;
7877
foreach ($metadata->getPropertyMetadata($mapping['fieldName']) as $propertyMetadata) {
78+
// Enabling or disabling auto-mapping explicitly always takes precedence
79+
if (AutoMappingStrategy::DISABLED === $propertyMetadata->getAutoMappingStrategy()) {
80+
continue 2;
81+
}
82+
if (AutoMappingStrategy::ENABLED === $propertyMetadata->getAutoMappingStrategy()) {
83+
$enabledForProperty = true;
84+
}
85+
7986
foreach ($propertyMetadata->getConstraints() as $constraint) {
80-
// Enabling or disabling auto-mapping explicitly always takes precedence
81-
if ($constraint instanceof DisableAutoMapping) {
82-
continue 3;
83-
} elseif ($constraint instanceof EnableAutoMapping) {
84-
$enabledForProperty = true;
85-
} elseif ($constraint instanceof Length) {
87+
if ($constraint instanceof Length) {
8688
$lengthConstraint = $constraint;
8789
}
8890
}

src/Symfony/Bridge/Doctrine/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"symfony/proxy-manager-bridge": "^3.4|^4.0|^5.0",
3636
"symfony/security-core": "^4.4|^5.0",
3737
"symfony/expression-language": "^3.4|^4.0|^5.0",
38-
"symfony/validator": "^4.4|^5.0",
38+
"symfony/validator": "^4.4.1|^5.0.1",
3939
"symfony/var-dumper": "^3.4|^4.0|^5.0",
4040
"symfony/translation": "^3.4|^4.0|^5.0",
4141
"doctrine/annotations": "~1.7",
@@ -53,7 +53,7 @@
5353
"symfony/http-kernel": "<4.3.7",
5454
"symfony/messenger": "<4.3",
5555
"symfony/security-core": "<4.4",
56-
"symfony/validator": "<4.4"
56+
"symfony/validator": "<4.4.1|<5.0.1,>=5.0"
5757
},
5858
"suggest": {
5959
"symfony/form": "",
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\Validator\Mapping;
13+
14+
/**
15+
* Specifies how the auto-mapping feature should behave.
16+
*
17+
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
18+
*/
19+
final class AutoMappingStrategy
20+
{
21+
/**
22+
* Nothing explicitly set, rely on auto-mapping configured regex.
23+
*/
24+
public const NONE = 0;
25+
26+
/**
27+
* Explicitly enabled.
28+
*/
29+
public const ENABLED = 1;
30+
31+
/**
32+
* Explicitly disabled.
33+
*/
34+
public const DISABLED = 2;
35+
36+
/**
37+
* Not instantiable.
38+
*/
39+
private function __construct()
40+
{
41+
}
42+
}

src/Symfony/Component/Validator/Mapping/GenericMetadata.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Component\Validator\Mapping;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
16+
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
1517
use Symfony\Component\Validator\Constraints\Length;
1618
use Symfony\Component\Validator\Constraints\NotBlank;
1719
use Symfony\Component\Validator\Constraints\Traverse;
@@ -75,6 +77,19 @@ class GenericMetadata implements MetadataInterface
7577
*/
7678
public $traversalStrategy = TraversalStrategy::NONE;
7779

80+
/**
81+
* Is auto-mapping enabled?
82+
*
83+
* @var int
84+
*
85+
* @see AutoMappingStrategy
86+
*
87+
* @internal This property is public in order to reduce the size of the
88+
* class' serialized representation. Do not access it. Use
89+
* {@link getAutoMappingStrategy()} instead.
90+
*/
91+
public $autoMappingStrategy = AutoMappingStrategy::NONE;
92+
7893
/**
7994
* Returns the names of the properties that should be serialized.
8095
*
@@ -87,6 +102,7 @@ public function __sleep()
87102
'constraintsByGroup',
88103
'cascadingStrategy',
89104
'traversalStrategy',
105+
'autoMappingStrategy',
90106
];
91107
}
92108

@@ -139,6 +155,13 @@ public function addConstraint(Constraint $constraint)
139155
return $this;
140156
}
141157

158+
if ($constraint instanceof DisableAutoMapping || $constraint instanceof EnableAutoMapping) {
159+
$this->autoMappingStrategy = $constraint instanceof EnableAutoMapping ? AutoMappingStrategy::ENABLED : AutoMappingStrategy::DISABLED;
160+
161+
// The constraint is not added
162+
return $this;
163+
}
164+
142165
$this->constraints[] = $constraint;
143166

144167
foreach ($constraint->groups as $group) {
@@ -213,6 +236,14 @@ public function getTraversalStrategy()
213236
return $this->traversalStrategy;
214237
}
215238

239+
/**
240+
* @see AutoMappingStrategy
241+
*/
242+
public function getAutoMappingStrategy(): int
243+
{
244+
return $this->autoMappingStrategy;
245+
}
246+
216247
private function configureLengthConstraints(array $constraints): void
217248
{
218249
$allowEmptyString = true;

src/Symfony/Component/Validator/Mapping/Loader/AutoMappingTrait.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111

1212
namespace Symfony\Component\Validator\Mapping\Loader;
1313

14-
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
15-
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
14+
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
1615
use Symfony\Component\Validator\Mapping\ClassMetadata;
1716

1817
/**
@@ -25,14 +24,8 @@ trait AutoMappingTrait
2524
private function isAutoMappingEnabledForClass(ClassMetadata $metadata, string $classValidatorRegexp = null): bool
2625
{
2726
// Check if AutoMapping constraint is set first
28-
foreach ($metadata->getConstraints() as $constraint) {
29-
if ($constraint instanceof DisableAutoMapping) {
30-
return false;
31-
}
32-
33-
if ($constraint instanceof EnableAutoMapping) {
34-
return true;
35-
}
27+
if (AutoMappingStrategy::NONE !== $strategy = $metadata->getAutoMappingStrategy()) {
28+
return AutoMappingStrategy::ENABLED === $strategy;
3629
}
3730

3831
// Fallback on the config

src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
1717
use Symfony\Component\PropertyInfo\Type as PropertyInfoType;
1818
use Symfony\Component\Validator\Constraints\All;
19-
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
20-
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
2119
use Symfony\Component\Validator\Constraints\NotBlank;
2220
use Symfony\Component\Validator\Constraints\NotNull;
2321
use Symfony\Component\Validator\Constraints\Type;
22+
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
2423
use Symfony\Component\Validator\Mapping\ClassMetadata;
2524

2625
/**
@@ -77,16 +76,16 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
7776
$hasNotBlankConstraint = false;
7877
$allConstraint = null;
7978
foreach ($metadata->getPropertyMetadata($property) as $propertyMetadata) {
80-
foreach ($propertyMetadata->getConstraints() as $constraint) {
81-
// Enabling or disabling auto-mapping explicitly always takes precedence
82-
if ($constraint instanceof DisableAutoMapping) {
83-
continue 3;
84-
}
79+
// Enabling or disabling auto-mapping explicitly always takes precedence
80+
if (AutoMappingStrategy::DISABLED === $propertyMetadata->getAutoMappingStrategy()) {
81+
continue 2;
82+
}
8583

86-
if ($constraint instanceof EnableAutoMapping) {
87-
$enabledForProperty = true;
88-
}
84+
if (AutoMappingStrategy::ENABLED === $propertyMetadata->getAutoMappingStrategy()) {
85+
$enabledForProperty = true;
86+
}
8987

88+
foreach ($propertyMetadata->getConstraints() as $constraint) {
9089
if ($constraint instanceof Type) {
9190
$hasTypeConstraint = true;
9291
} elseif ($constraint instanceof NotNull) {

src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
1616
use Symfony\Component\PropertyInfo\Type;
1717
use Symfony\Component\Validator\Constraints\All;
18-
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
1918
use Symfony\Component\Validator\Constraints\Iban;
2019
use Symfony\Component\Validator\Constraints\NotBlank;
2120
use Symfony\Component\Validator\Constraints\NotNull;
2221
use Symfony\Component\Validator\Constraints\Type as TypeConstraint;
22+
use Symfony\Component\Validator\Mapping\AutoMappingStrategy;
2323
use Symfony\Component\Validator\Mapping\ClassMetadata;
2424
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
25+
use Symfony\Component\Validator\Mapping\PropertyMetadata;
2526
use Symfony\Component\Validator\Tests\Fixtures\Entity;
2627
use Symfony\Component\Validator\Tests\Fixtures\PropertyInfoLoaderEntity;
2728
use Symfony\Component\Validator\Tests\Fixtures\PropertyInfoLoaderNoAutoMappingEntity;
@@ -164,11 +165,12 @@ public function testLoadClassMetadata()
164165
$readOnlyMetadata = $classMetadata->getPropertyMetadata('readOnly');
165166
$this->assertEmpty($readOnlyMetadata);
166167

168+
/** @var PropertyMetadata[] $noAutoMappingMetadata */
167169
$noAutoMappingMetadata = $classMetadata->getPropertyMetadata('noAutoMapping');
168170
$this->assertCount(1, $noAutoMappingMetadata);
171+
$this->assertSame(AutoMappingStrategy::DISABLED, $noAutoMappingMetadata[0]->getAutoMappingStrategy());
169172
$noAutoMappingConstraints = $noAutoMappingMetadata[0]->getConstraints();
170-
$this->assertCount(1, $noAutoMappingConstraints);
171-
$this->assertInstanceOf(DisableAutoMapping::class, $noAutoMappingConstraints[0]);
173+
$this->assertCount(0, $noAutoMappingConstraints, 'DisableAutoMapping constraint is not added in the list');
172174
}
173175

174176
/**
@@ -222,8 +224,10 @@ public function testClassNoAutoMapping()
222224
->getValidator()
223225
;
224226

227+
/** @var ClassMetadata $classMetadata */
225228
$classMetadata = $validator->getMetadataFor(new PropertyInfoLoaderNoAutoMappingEntity());
226229
$this->assertEmpty($classMetadata->getPropertyMetadata('string'));
227-
$this->assertCount(3, $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled')[0]->constraints);
230+
$this->assertCount(2, $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled')[0]->constraints);
231+
$this->assertSame(AutoMappingStrategy::ENABLED, $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled')[0]->getAutoMappingStrategy());
228232
}
229233
}

0 commit comments

Comments
 (0)