Skip to content

Commit 894ca8a

Browse files
bug #34694 [Validator] Fix auto-mapping constraints should not be validated (ogizanagi)
This PR was squashed before being merged into the 4.4 branch. Discussion ---------- [Validator] Fix auto-mapping constraints should not be validated | Q | A | ------------- | --- | Branch? | 4.4 <!-- see below --> | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | #34672 <!-- prefix each issue number with "Fix #", if any --> | License | MIT | Doc PR | N/A As for `Traverse`, I don't think we should add these "constraints" to the list. I'm also wondering if it really makes sense to have these annotations as constraints. I think it should rather behave like the `GroupSequence` annotation to add the info the generic metadata at loading time, but we don't need to rely on the constraints behavior at all. Commits ------- bc53e4bca0 [Validator] Fix auto-mapping constraints should not be validated
2 parents 40153ce + 1c5efe8 commit 894ca8a

File tree

5 files changed

+93
-24
lines changed

5 files changed

+93
-24
lines changed

Mapping/AutoMappingStrategy.php

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 <[email protected]>
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 <[email protected]>
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+
}

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;

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

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) {

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)