8000 Add AutoMapping annotation · symfony/symfony@5059899 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5059899

Browse files
committed
Add AutoMapping annotation
1 parent 5e62174 commit 5059899

File tree

11 files changed

+106
-68
lines changed

11 files changed

+106
-68
lines changed

src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class DoctrineLoaderEntity extends DoctrineLoaderParentEntity
7171

7272
/**
7373
* @ORM\Column(length=10)
74-
* @Assert\NoAutoMapping
74+
* @Assert\AutoMapping(false)
7575
*/
7676
public $noAutoMapping;
7777

src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderNoAutoMappingEntity.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/**
1818
* @ORM\Entity
19-
* @Assert\NoAutoMapping
19+
* @Assert\AutoMapping(false)
2020
*
2121
* @author Kévin Dunglas <dunglas@gmail.com>
2222
*/
@@ -32,4 +32,10 @@ class DoctrineLoaderNoAutoMappingEntity
3232
* @ORM\Column(length=20, unique=true)
3333
*/
3434
public $maxLength;
35+
36+
/**
37+
* @Assert\AutoMapping(true)
38+
* @ORM\Column(length=20)
39+
*/
40+
public $autoMappingExplicitlyEnabled;
3541
}

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
2323
use Symfony\Bridge\Doctrine\Validator\DoctrineLoader;
2424
use Symfony\Component\Validator\Constraints\Length;
25-
use Symfony\Component\Validator\Constraints\NoAutoMapping;
25+
use Symfony\Component\Validator\Constraints\AutoMapping;
2626
use Symfony\Component\Validator\Mapping\CascadingStrategy;
2727
use Symfony\Component\Validator\Mapping\ClassMetadata;
2828
use Symfony\Component\Validator\Mapping\ F438 TraversalStrategy;
@@ -141,7 +141,7 @@ public function testLoadClassMetadata()
141141
$this->assertCount(1, $noAutoMappingMetadata);
142142
$noAutoMappingConstraints = $noAutoMappingMetadata[0]->getConstraints();
143143
$this->assertCount(1, $noAutoMappingConstraints);
144-
$this->assertInstanceOf(NoAutoMapping::class, $noAutoMappingConstraints[0]);
144+
$this->assertInstanceOf(AutoMapping::class, $noAutoMappingConstraints[0]);
145145
}
146146

147147
public function testFieldMappingsConfiguration()
@@ -184,8 +184,8 @@ public function regexpProvider()
184184
{
185185
return [
186186
[true, null],
187-
[true, '{^'.preg_quote(DoctrineLoaderEntity::class).'$|^'.preg_quote(Entity::class).'$}'],
188-
[false, '{^'.preg_quote(Entity::class).'$}'],
187+
[true, '{^'.preg_quote(DoctrineLoaderEntity::class, '{').'$|^'.preg_quote(Entity::class, '{').'$}'],
188+
[false, '{^'.preg_quote(Entity::class, '{').'$}'],
189189
];
190190
}
191191

@@ -204,9 +204,12 @@ public function testClassNoAutoMapping()
204204

205205
$classConstraints = $classMetadata->getConstraints();
206206
$this->assertCount(1, $classConstraints);
207-
$this->assertInstanceOf(NoAutoMapping::class, $classConstraints[0]);
207+
$this->assertInstanceOf(AutoMapping::class, $classConstraints[0]);
208208

209-
$fooMetadata = $classMetadata->getPropertyMetadata('maxLength');
210-
$this->assertEmpty($fooMetadata);
209+
$maxLengthMetadata = $classMetadata->getPropertyMetadata('maxLength');
210+
$this->assertEmpty($maxLengthMetadata);
211+
212+
$autoMappingExplicitlyEnabledMetadata = $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled');
213+
$this->assertCount(2, $autoMappingExplicitlyEnabledMetadata[0]->constraints);
211214
}
212215
}

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

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
1818
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
1919
use Symfony\Component\Validator\Constraints\Length;
20-
use Symfony\Component\Validator\Constraints\NoAutoMapping;
20+
use Symfony\Component\Validator\Constraints\AutoMapping;
2121
use Symfony\Component\Validator\Constraints\Valid;
2222
use Symfony\Component\Validator\Mapping\ClassMetadata;
2323
use Symfony\Component\Validator\Mapping\Loader\AutoMappingTrait;
@@ -46,10 +46,6 @@ public function __construct(EntityManagerInterface $entityManager, string $class
4646
*/
4747
public function loadClassMetadata(ClassMetadata $metadata): bool
4848
{
49-
if (!$this->supports($metadata, $this->classValidatorRegexp)) {
50-
return false;
51-
}
52-
5349
$className = $metadata->getClassName();
5450
try {
5551
$doctrineMetadata = $this->entityManager->getClassMetadata($className);
@@ -61,6 +57,9 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
6157
return false;
6258
}
6359

60+
$loaded = false;
61+
$enabledForClass = $this->isEnabledForClass($metadata, $this->classValidatorRegexp);
62+
6463
/* Available keys:
6564
- type
6665
- scale
@@ -73,21 +72,31 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
7372

7473
// Type and nullable aren't handled here, use the PropertyInfo Loader instead.
7574
foreach ($doctrineMetadata->fieldMappings as $mapping) {
75+
$enabledForProperty = $enabledForClass;
7676
$lengthConstraint = null;
7777
foreach ($metadata->getPropertyMetadata($mapping['fieldName']) as $propertyMetadata) {
7878
foreach ($propertyMetadata->getConstraints() as $constraint) {
79-
if ($constraint instanceof NoAutoMapping) {
80-
continue 3;
81-
}
82-
83-
if ($constraint instanceof Length) {
79+
// Enabling or disabling auto-mapping explicitly always takes precedence
80+
if ($constraint instanceof AutoMapping) {
81+
// Enabling or disabling auto-mapping explicitly always takes precedence
82+
if (!$constraint->enabled) {
83+
continue 3;
84+
}
85+
86+
$enabledForProperty = true;
87+
} elseif ($constraint instanceof Length) {
8488
$lengthConstraint = $constraint;
8589
}
8690
}
8791
}
8892

93+
if (!$enabledForProperty) {
94+
continue;
95+
}
96+
8997
if (true === ($mapping['unique'] ?? false) && !isset($existingUniqueFields[$mapping['fieldName']])) {
9098
$metadata->addConstraint(new UniqueEntity(['fields' => $mapping['fieldName']]));
99+
$loaded = true;
91100
}
92101

93102
if (null === ($mapping['length'] ?? null) || !\in_array($mapping['type'], ['string', 'text'], true)) {
@@ -97,29 +106,18 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
97106
if (null === $lengthConstraint) {
98107
if (isset($mapping['originalClass']) && false === strpos($mapping['declaredField'], '.')) {
99108
$metadata->addPropertyConstraint($mapping['declaredField'], new Valid());
109+
$loaded = true;
100110
} elseif (property_exists($className, $mapping['fieldName'])) {
101111
$metadata->addPropertyConstraint($mapping['fieldName'], new Length(['max' => $mapping['length']]));
112+
$loaded = true;
102113
}
103114
} elseif (null === $lengthConstraint->max) {
104115
// If a Length constraint exists and no max length has been explicitly defined, set it
105116
$lengthConstraint->max = $mapping['length'];
106117
}
107118
}
108119

109-
return true;
110-
}
111-
112-
private function getLengthConstraint(ClassMetadata $metadata, string $fieldName): ?Length
113-
{
114-
foreach ($metadata->getPropertyMetadata($fieldName) as $propertyMetadata) {
115-
foreach ($propertyMetadata->getConstraints() as $constraint) {
116-
if ($constraint instanceof Length) {
117-
return $constraint;
118-
}
119-
}
120-
}
121-
122-
return null;
120+
return $loaded;
123121
}
124122

125123
private function getExistingUniqueFields(ClassMetadata $metadata): array

src/Symfony/Component/Validator/Constraints/NoAutoMapping.php renamed to src/Symfony/Component/Validator/Constraints/AutoMapping.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@
1515
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1616

1717
/**
18-
* Disables auto mapping.
18+
* Enables or disables auto mapping.
19+
*
20+
* If the constraint is present on:
21+
* * a property, and set to true, auto-mapping for this property is always enabled, regardless of the config, and of any class level annotation
22+
* * a property, and set to false, auto-mapping for this property is always disabled, regardless of the config, and of any class level annotation
23+
* * a class, and set to true, auto-mapping for this class is always enabled except if a the annotation has been added to a specific property, and regardless of the config
24+
* * a class, and set to false, auto-mapping is always disabled except if a the annotation has been added to a specific property, and regardless of the config
1925
*
2026
* @Annotation
2127
*
2228
* @author Kévin Dunglas <dunglas@gmail.com>
2329
*/
24-
class NoAutoMapping extends Constraint
30+
class AutoMapping extends Constraint
2531
{
32+
public $enabled = true;
33+
2634
public function __construct($options = null)
2735
{
2836
if (\is_array($options) && \array_key_exists('groups', $options)) {
@@ -39,4 +47,12 @@ public function getTargets()
3947
{
4048
return [self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT];
4149
}
50+
51+
/**
52+
* {@inheritdoc}
53+
*/
54+
public function getDefaultOption(): ?string
55+
{
56+
return 'enabled';
57+
}
4258
}

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,24 @@
1111

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

14-
use Symfony\Component\Validator\Constraints\NoAutoMapping;
14+
use Symfony\Component\Validator\Constraints\AutoMapping;
1515
use Symfony\Component\Validator\Mapping\ClassMetadata;
1616

1717
/**
1818
* Utility methods to create auto mapping loaders.
1919
*/
2020
trait AutoMappingTrait
2121
{
22-
private function supports(ClassMetadata $metadata, string $classValidatorRegexp = null): bool
22+
private function isEnabledForClass(ClassMetadata $metadata, string $classValidatorRegexp = null): bool
2323
{
24-
if (null !== $classValidatorRegexp && !preg_match($classValidatorRegexp, $metadata->getClassName())) {
25-
return false;
26-
}
27-
24+
// Check if AutoMapping constraint is set first
2825
foreach ($metadata->getConstraints() as $constraint) {
29-
if ($constraint instanceof NoAutoMapping) {
30-
return false;
26+
if ($constraint instanceof AutoMapping) {
27+
return $constraint->enabled;
3128
}
3229
}
3330

34-
return true;
31+
// Fallback on the config
32+
return null === $classValidatorRegexp || preg_match($classValidatorRegexp, $metadata->getClassName());
3533
}
3634
}

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
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\NoAutoMapping;
19+
use Symfony\Component\Validator\Constraints\AutoMapping;
2020
use Symfony\Component\Validator\Constraints\NotBlank;
2121
use Symfony\Component\Validator\Constraints\NotNull;
2222
use Symfony\Component\Validator\Constraints\Type;
@@ -49,15 +49,13 @@ public function __construct(PropertyListExtractorInterface $listExtractor, Prope
4949
*/
5050
public function loadClassMetadata(ClassMetadata $metadata): bool
5151
{
52-
if (!$this->supports($metadata, $this->classValidatorRegexp)) {
53-
return false;
54-
}
55-
5652
$className = $metadata->getClassName();
5753
if (!$properties = $this->listExtractor->getProperties($className)) {
5854
return false;
5955
}
6056

57+
$loaded = false;
58+
$enabledForClass = $this->isEnabledForClass($metadata, $this->classValidatorRegexp);
6159
foreach ($properties as $property) {
6260
if (false === $this->accessExtractor->isWritable($className, $property)) {
6361
continue;
@@ -72,14 +70,20 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
7270
continue;
7371
}
7472

73+
$enabledForProperty = $enabledForClass;
7574
$hasTypeConstraint = false;
7675
$hasNotNullConstraint = false;
7776
$hasNotBlankConstraint = false;
7877
$allConstraint = null;
7978
foreach ($metadata->getPropertyMetadata($property) as $propertyMetadata) {
8079
foreach ($propertyMetadata->getConstraints() as $constraint) {
81-
if ($constraint instanceof NoAutoMapping) {
82-
continue 3;
80+
if ($constraint instanceof AutoMapping) {
81+
// Enabling or disabling auto-mapping explicitly always takes precedence
82+
if (!$constraint->enabled) {
83+
continue 3;
84+
}
85+
86+
$enabledForProperty = true;
8387
}
8488

8589
if ($constraint instanceof Type) {
@@ -94,6 +98,11 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
9498
}
9599
}
96100

101+
if (!$enabledForProperty) {
102+
continue;
103+
}
104+
105+
$loaded = true;
97106
$builtinTypes = [];
98107
$nullable = false;
99108
$scalar = true;
@@ -125,7 +134,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
125134
}
126135
}
127136

128-
return true;
137+
return $loaded;
129138
}
130139

131140
private function getTypeConstraint(string $builtinType, PropertyInfoType $type): Type

src/Symfony/Component/Validator/Tests/Constraints/NoAutoMappingTest.php renamed to src/Symfony/Component/Validator/Tests/Constraints/AutoMappingTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@
1212
namespace Symfony\Component\Validator\Tests\Constraints;
1313

1414
use PHPUnit\Framework\TestCase;
15-
use Symfony\Component\Validator\Constraints\NoAutoMapping;
15+
use Symfony\Component\Validator\Constraints\AutoMapping;
16+
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1617

1718
/**
1819
* @author Kévin Dunglas <dunglas@gmail.com>
1920
*/
20-
class NoAutoMappingTest extends TestCase
21+
class AutoMappingTest extends TestCase
2122
{
22-
/**
23-
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
24-
* @expectedExceptionMessage The option "groups" is not supported by the constraint Symfony\Component\Validator\Constraints\NoAutoMapping
25-
*/
2623
public function testGroups()
2724
{
28-
new NoAutoMapping(['groups' => 'foo']);
25+
$this->expectException(ConstraintDefinitionException::class);
26+
$this->expectExceptionMessage('The option "groups" is not supported by the constraint '.AutoMapping::class);
27+
28+
new AutoMapping(['groups' => 'foo']);
2929
}
3030
}

src/Symfony/Component/Validator/Tests/Fixtures/PropertyInfoLoaderEntity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class PropertyInfoLoaderEntity
5050
public $readOnly;
5151

5252
/**
53-
* @Assert\NoAutoMapping
53+
* @Assert\AutoMapping(false)
5454
*/
5555
public $noAutoMapping;
5656

src/Symfony/Component/Validator/Tests/Fixtures/PropertyInfoLoaderNoAutoMappingEntity.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@
1414
use Symfony\Component\Validator\Constraints as Assert;
1515

1616
/**
17-
* @Assert\NoAutoMapping
17+
* @Assert\AutoMapping(false)
1818
*
1919
* @author Kévin Dunglas <dunglas@gmail.com>
2020
*/
2121
class PropertyInfoLoaderNoAutoMappingEntity
2222
{
2323
public $string;
24+
25+
/**
26+
* @Assert\AutoMapping(true)
27+
*/
28+
public $autoMappingExplicitlyEnabled;
2429
}

0 commit comments

Comments
 (0)
0