8000 [Validator] Deprecate annotations in favor of attributes · symfony/symfony@4fc3e7e · GitHub
[go: up one dir, main page]

Skip to content
Dismiss alert

Commit 4fc3e7e

Browse files
committed
[Validator] Deprecate annotations in favor of attributes
1 parent 503a7b3 commit 4fc3e7e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+357
-164
lines changed

UPGRADE-6.4.md

+8
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,11 @@ Security
7171
* `UserValueResolver` no longer implements `ArgumentValueResolverInterface`
7272
* Make `PersistentToken` immutable
7373
* Deprecate accepting only `DateTime` for `TokenProviderInterface::updateToken()`, use `DateTimeInterface` instead
74+
75+
Validator
76+
---------
77+
78+
* Deprecate Doctrine annotations support in favor of native attributes
79+
* Deprecate passing an annotation reader to the constructor signature of `AnnotationLoader`
80+
* Deprecate `ValidatorBuilder::setDoctrineAnnotationReader()`
81+
* Deprecate `ValidatorBuilder::addDefaultDoctrineAnnotationReader()`

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
use Symfony\Component\Validator\Mapping\ClassMetadata;
2929
use Symfony\Component\Validator\Mapping\PropertyMetadata;
3030
use Symfony\Component\Validator\Mapping\TraversalStrategy;
31-
use Symfony\Component\Validator\Tests\Fixtures\Entity;
31+
use Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity;
3232
use Symfony\Component\Validator\Validation;
3333

3434
/**
@@ -40,7 +40,6 @@ public function testLoadClassMetadata()
4040
{
4141
$validator = Validation::createValidatorBuilder()
4242
->enableAnnotationMapping(true)
43-
->addDefaultDoctrineAnnotationReader()
4443
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}'))
4544
->getValidator()
4645
;
@@ -144,7 +143,6 @@ public function testExtractEnum()
144143
$validator = Validation::createValidatorBuilder()
145144
->addMethodMapping('loadValidatorMetadata')
146145
->enableAnnotationMapping(true)
147-
->addDefaultDoctrineAnnotationReader()
148146
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}'))
149147
->getValidator()
150148
;
@@ -162,7 +160,6 @@ public function testFieldMappingsConfiguration()
162160
{
163161
$validator = Validation::createValidatorBuilder()
164162
->enableAnnotationMapping(true)
165-
->addDefaultDoctrineAnnotationReader()
166163
->addXmlMappings([__DIR__.'/../Resources/validator/BaseUser.xml'])
167164
->addLoader(
168165
new DoctrineLoader(
@@ -204,7 +201,6 @@ public function testClassNoAutoMapping()
204201
{
205202
$validator = Validation::createValidatorBuilder()
206203
->enableAnnotationMapping(true)
207-
->addDefaultDoctrineAnnotationReader()
208204
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{.*}'))
209205
->getValidator();
210206

src/Symfony/Bridge/Doctrine/composer.json

-2
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,13 @@
4343
"symfony/uid": "^5.4|^6.0|^7.0",
4444
"symfony/validator": "^5.4.25|~6.2.12|^6.3.1|^7.0",
4545
"symfony/var-dumper": "^5.4|^6.0|^7.0",
46-
"doctrine/annotations": "^1.13.1|^2",
4746
"doctrine/collections": "^1.0|^2.0",
4847
"doctrine/data-fixtures": "^1.1",
4948
"doctrine/dbal": "^2.13.1|^3.0",
5049
"doctrine/orm": "^2.15",
5150
"psr/log": "^1|^2|^3"
5251
},
5352
"conflict": {
54-
"doctrine/annotations": "<1.13.1",
5553
"doctrine/dbal": "<2.13.1",
5654
"doctrine/lexer": "<1.1",
5755
"doctrine/orm": "<2.15",

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
182182
use Symfony\Component\Validator\ObjectInitializerInterface;
183183
use Symfony\Component\Validator\Validation;
184+
use Symfony\Component\Validator\ValidatorBuilder;
184185
use Symfony\Component\Webhook\Controller\WebhookController;
185186
use Symfony\Component\WebLink\HttpHeaderSerializer;
186187
use Symfony\Component\Workflow;
@@ -1609,7 +1610,7 @@ private function registerValidationConfiguration(array $config, ContainerBuilder
16091610

16101611
if (\array_key_exists('enable_annotations', $config) && $config['enable_annotations']) {
16111612
$validatorBuilder->addMethodCall('enableAnnotationMapping', [true]);
1612-
if ($this->isInitializedConfigEnabled('annotations')) {
1613+
if ($this->isInitializedConfigEnabled('annotations') && method_exists(ValidatorBuilder::class, 'setDoctrineAnnotationReader')) {
16131614
$validatorBuilder->addMethodCall('setDoctrineAnnotationReader', [new Reference('annotation_reader')]);
16141615
}
16151616
}

src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ValidatorCacheWarmerTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public function testWarmUp()
2626
$validatorBuilder->addXmlMapping(__DIR__.'/../Fixtures/Validation/Resources/person.xml');
2727
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/author.yml');
2828
$validatorBuilder->addMethodMapping('loadValidatorMetadata');
29-
$validatorBuilder->enableAnnotationMapping(true)->addDefaultDoctrineAnnotationReader();
29+
$validatorBuilder->enableAnnotationMapping();
3030

3131
$file = sys_get_temp_dir().'/cache-validator.php';
3232
@unlink($file);
@@ -46,7 +46,7 @@ public function testWarmUpWithAnnotations()
4646
{
4747
$validatorBuilder = new ValidatorBuilder();
4848
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/categories.yml');
49-
$validatorBuilder->enableAnnotationMapping(true)->addDefaultDoctrineAnnotationReader();
49+
$validatorBuilder->enableAnnotationMapping();
5050

5151
$file = sys_get_temp_dir().'/cache-validator-with-annotations.php';
5252
@unlink($file);

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php

+12-6
< 10000 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
8282
use Symfony\Component\Validator\Validation;
8383
use Symfony\Component\Validator\Validator\ValidatorInterface;
84+
use Symfony\Component\Validator\ValidatorBuilder;
8485
use Symfony\Component\Webhook\Client\RequestParser;
8586
use Symfony\Component\Webhook\Controller\WebhookController;
8687
use Symfony\Component\Workflow;
@@ -1308,12 +1309,17 @@ public function testValidationLegacyAnnotations()
13081309

13091310
$this->assertCount(8, $calls);
13101311
$this->assertSame('enableAnnotationMapping', $calls[4][0]);
1311-
$this->assertSame('setDoctrineAnnotationReader', $calls[5][0]);
1312-
$this->assertEquals([new Reference('annotation_reader')], $calls[5][1]);
1313-
$this->assertSame('addMethodMapping', $calls[6][0]);
1314-
$this->assertSame(['loadValidatorMetadata'], $calls[6][1]);
1315-
$this->assertSame('setMappingCache', $calls[7][0]);
1316-
$this->assertEquals([new Reference('validator.mapping.cache.adapter')], $calls[7][1]);
1312+
if (method_exists(ValidatorBuilder::class, 'setDoctrineAnnotationReader')) {
1313+
$this->assertSame('setDoctrineAnnotationReader', $calls[5][0]);
1314+
$this->assertEquals([new Reference('annotation_reader')], $calls[5][1]);
1315+
$i = 6;
1316+
} else {
1317+
$i = 5;
1318+
}
1319+
$this->assertSame('addMethodMapping', $calls[$i][0]);
1320+
$this->assertSame(['loadValidatorMetadata'], $calls[$i][1]);
1321+
$this->assertSame('setMappingCache', $calls[++$i][0]);
1322+
$this->assertEquals([new Reference('validator.mapping.cache.adapter')], $calls[$i][1]);
13171323
// no cache this time
13181324
}
13191325

src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Category.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ class Category
1010

1111
public $id;
1212

13-
/**
14-
* @Assert\Type("string")
15-
*/
13+
#[Assert\Type('string')]
1614
public $name;
1715
}

src/Symfony/Component/Validator/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ CHANGELOG
66

77
* Allow single integer for the `versions` option of the `Uuid` constraint
88
* Allow single constraint to be passed to the `constraints` option of the `When` constraint
9+
* Deprecate Doctrine annotations support in favor of native attributes
10+
* Deprecate passing an annotation reader to the constructor signature of `AnnotationLoader`
11+
* Deprecate `ValidatorBuilder::setDoctrineAnnotationReader()`
12+
* Deprecate `ValidatorBuilder::addDefaultDoctrineAnnotationReader()`
913

1014
6.3
1115
---

src/Symfony/Component/Validator/Constraints/GroupSequence.php

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
*
2929
* When adding metadata to a class, you can override the "Default" group of
3030
* that class with a group sequence:
31-
* /**
32-
* * @GroupSequence({"Address", "Strict"})
33-
* *\/
31+
* #[GroupSequence(['Address', 'Strict'])]
3432
* class Address
3533
* {
3634
* // ...
@@ -47,6 +45,7 @@
4745
* $validator->validate($address, null, "Address")
4846
*
4947
* @Annotation
48+
*
5049
* @Target({"CLASS", "ANNOTATION"})
5150
*
5251
* @author Bernhard Schussek <bschussek@gmail.com>

src/Symfony/Component/Validator/Constraints/GroupSequenceProvider.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
namespace Symfony\Component\Validator\Constraints;
1313

1414
/**
15-
* Annotation to define a group sequence provider.
15+
* Attribute to define a group sequence provider.
1616
*
1717
* @Annotation
18+
*
1819
* @Target({"CLASS", "ANNOTATION"})
1920
*
2021
* @author Bernhard Schussek <bschussek@gmail.com>

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

+16-10
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,19 @@
2727
*/
2828
class AnnotationLoader implements LoaderInterface
2929
{
30+
/**
31+
* @deprecated since Symfony 6.4, this property will be removed in 7.0
32+
*
33+
* @var Reader|null
34+
*/
3035
protected $reader;
3136

3237
public function __construct(Reader $reader = null)
3338
{
39+
if ($reader) {
40+
trigger_deprecation('symfony/validator', '6.4', 'Passing a "%s" instance as argument 1 to "%s()" is deprecated, pass null or omit the parameter instead.', get_debug_type($reader), __METHOD__);
41+
}
42+
3443
$this->reader = $reader;
3544
}
3645

@@ -87,10 +96,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
8796
return $success;
8897
}
8998

90-
/**
91-
* @param \ReflectionClass|\ReflectionMethod|\ReflectionProperty $reflection
92-
*/
93-
private function getAnnotations(object $reflection): iterable
99+
private function getAnnotations(\ReflectionMethod|\ReflectionClass|\ReflectionProperty $reflection): iterable
94100
{
95101
$dedup = [];
96102

@@ -112,14 +118,14 @@ private function getAnnotations(object $reflection): iterable
112118

113119
$annotations = [];
114120

115-
if ($reflection instanceof \ReflectionClass) {
116-
$annotations = $this->reader->getClassAnnotations($reflection);
121+
if ($reflection instanceof \ReflectionClass && $annotations = $this->reader->getClassAnnotations($reflection)) {
122+
trigger_deprecation('symfony/validator', '6.4', 'Class "%s" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.', $reflection->getName());
117123
}
118-
if ($reflection instanceof \ReflectionMethod) {
119-
$annotations = $this->reader->getMethodAnnotations($reflection);
124+
if ($reflection instanceof \ReflectionMethod && $annotations = $this->reader->getMethodAnnotations($reflection)) {
125+
trigger_deprecation('symfony/validator', '6.4', 'Method "%s::%s()" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.', $reflection->getDeclaringClass()->getName(), $reflection->getName());
120126
}
121-
if ($reflection instanceof \ReflectionProperty) {
122-
$annotations = $this->reader->getPropertyAnnotations($reflection);
127+
if ($reflection instanceof \ReflectionProperty && $annotations = $this->reader->getPropertyAnnotations($reflection)) {
128+
trigger_deprecation('symfony/validator', '6.4', 'Property "%s::$%s" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.', $reflection->getDeclaringClass()->getName(), $reflection->getName());
123129
}
124130

125131
foreach ($dedup as $annotation) {

src/Symfony/Component/Validator/Tests/Command/DebugCommandTest.php

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\Validator\Tests\Command;
1313

14-
use Doctrine\Common\Annotations\AnnotationReader;
1514
use PHPUnit\Framework\TestCase;
1615
use Symfony\Component\Console\Tester\CommandTester;
1716
use Symfony\Component\Validator\Command\DebugCommand;
@@ -27,7 +26,7 @@ class DebugCommandTest extends TestCase
2726
{
2827
public function testOutputWithClassArgument()
2928
{
30-
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader(new AnnotationReader())));
29+
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader()));
3130

3231
$tester = new CommandTester($command);
3332
$tester->execute(['class' => DummyClassOne::class], ['decorated' => false]);
@@ -68,7 +67,7 @@ public function testOutputWithClassArgument()
6867

6968
public function testOutputWithPathArgument()
7069
{
71-
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader(new AnnotationReader())));
70+
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader()));
7271

7372
$tester = new CommandTester($command);
7473
$tester->execute(['class' => __DIR__.'/../Dummy'], ['decorated' => false]);

src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Symfony\Component\Validator\Constraints\Expression;
1616
use Symfony\Component\Validator\Constraints\ExpressionValidator;
1717
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
18-
use Symfony\Component\Validator\Tests\Fixtures\Annotation\Entity;
18+
use Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity;
1919
use Symfony\Component\Validator\Tests\Fixtures\ToString;
2020

2121
class ExpressionValidatorTest extends ConstraintValidatorTestCase

src/Symfony/Component/Validator/Tests/Constraints/ValidValidatorTest.php

+5-17
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Validator\Constraints as Assert;
16-
use Symfony\Component\Validator\Constraints\ValidValidator;
1716
use Symfony\Component\Validator\ValidatorBuilder;
1817

1918
class ValidValidatorTest extends TestCase
2019
{
2120
public function testPropertyPathsArePassedToNestedContexts()
2221
{
2322
$validatorBuilder = new ValidatorBuilder();
24-
$validator = $validatorBuilder->enableAnnotationMapping()->addDefaultDoctrineAnnotationReader()->getValidator();
23+
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();
2524

2625
$violations = $validator->validate(new Foo(), null, ['nested']);
2726

@@ -32,26 +31,19 @@ public function testPropertyPathsArePassedToNestedContexts()
3231
public function testNullValues()
3332
{
3433
$validatorBuilder = new ValidatorBuilder();
35-
$validator = $validatorBuilder->enableAnnotationMapping()->addDefaultDoctrineAnnotationReader()->getValidator();
34+
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();
3635

3736
$foo = new Foo();
3837
$foo->fooBar = null;
3938
$violations = $validator->validate($foo, null, ['nested']);
4039

4140
$this->assertCount(0, $violations);
4241
}
43-
44-
protected function createValidator()
45-
{
46-
return new ValidValidator();
47-
}
4842
}
4943

5044
class Foo
5145
{
52-
/**
53-
* @Assert\Valid(groups={"nested"})
54-
*/
46+
#[Assert\Valid(groups: ['nested'])]
5547
public $fooBar;
5648

5749
public function __construct()
@@ -62,9 +54,7 @@ public function __construct()
6254

6355
class FooBar
6456
{
65-
/**
66-
* @Assert\Valid(groups={"nested"})
67-
*/
57+
#[Assert\Valid(groups: ['nested'])]
6858
public $fooBarBaz;
6959

7060
public function __construct()
@@ -75,8 +65,6 @@ public function __construct()
7565

7666
class FooBarBaz
7767
{
78-
/**
79-
* @Assert\NotBlank(groups={"nested"})
80-
*/
68+
#[Assert\NotBlank(groups: ['nested'])]
8169
public $foo;
8270
}

src/Symfony/Component/Validator/Tests/Constraints/WhenTest.php

+15-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Doctrine\Common\Annotations\AnnotationReader;
1515
use PHPUnit\Framework\TestCase;
16+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1617
use Symfony\Component\Validator\Constraints\Callback;
1718
use Symfony\Component\Validator\Constraints\NotBlank;
1819
use Symfony\Component\Validator\Constraints\NotNull;
@@ -25,6 +26,8 @@
2526

2627
final class WhenTest extends TestCase
2728
{
29+
use ExpectDeprecationTrait;
30+
2831
public function testMissingOptionsExceptionIsThrown()
2932
{
3033
$this->expectException(MissingOptionsException::class);
@@ -42,11 +45,22 @@ public function testNonConstraintsAreRejected()
4245
]);
4346
}
4447

48+
/**
49+
* @group legacy
50+
*/
4551
public function testAnnotations()
4652
{
53+
$this->expectDeprecation('Since symfony/validator 6.4: Passing a "Doctrine\Common\Annotations\AnnotationReader" instance as argument 1 to "Symfony\Component\Validator\Mapping\Loader\AnnotationLoader::__construct()" is deprecated, pass null or omit the parameter instead.');
54+
4755
$loader = new AnnotationLoader(new AnnotationReader());
4856
$metadata = new ClassMetadata(WhenTestWithAnnotations::class);
4957

58+
$this->expectDeprecation('Since symfony/validator 6.4: Class "Symfony\Component\Validator\Tests\Constraints\WhenTestWithAnnotations" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.');
59+
$this->expectDeprecation('Since symfony/validator 6.4: Property "Symfony\Component\Validator\Tests\Constraints\WhenTestWithAnnotations::$foo" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.');
60+
$this->expectDeprecation('Since symfony/validator 6.4: Property "Symfony\Component\Validator\Tests\Constraints\WhenTestWithAnnotations::$bar" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.');
61+
$this->expectDeprecation('Since symfony/validator 6.4: Property "Symfony\Component\Validator\Tests\Constraints\WhenTestWithAnnotations::$qux" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.');
62+
$this->expectDeprecation('Since symfony/validator 6.4: Method "Symfony\Component\Validator\Tests\Constraints\WhenTestWithAnnotations::getBaz()" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.');
63+
5064
self::assertTrue($loader->loadClassMetadata($metadata));
5165

5266
[$classConstraint] = $metadata->getConstraints();
@@ -114,12 +128,9 @@ public function testAnnotations()
114128
self::assertSame(['Default', 'WhenTestWithAnnotations'], $bazConstraint->groups);
115129
}
116130

117-
/**
118-
* @requires PHP 8.1
119-
*/
120131
public function testAttributes()
121132
{
122-
$loader = new AnnotationLoader(new AnnotationReader());
133+
$loader = new AnnotationLoader();
123134
$metadata = new ClassMetadata(WhenTestWithAttributes::class);
124135

125136
self::assertTrue($loader->loadClassMetadata($metadata));

0 commit comments

Comments
 (0)
0