8000 [Validator] Deprecate annotations in favor of attributes by derrabus · Pull Request #50982 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Validator] Deprecate annotations in favor of attributes #50982

New issue

8000 Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions UPGRADE-6.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,11 @@ Serializer

* Deprecate Doctrine annotations support in favor of native attributes
* Deprecate passing an annotation reader to the constructor of `AnnotationLoader`

Validator
---------

* Deprecate Doctrine annotations support in favor of native attributes
* Deprecate passing an annotation reader to the constructor signature of `AnnotationLoader`
* Deprecate `ValidatorBuilder::setDoctrineAnnotationReader()`
* Deprecate `ValidatorBuilder::addDefaultDoctrineAnnotationReader()`
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\PropertyMetadata;
use Symfony\Component\Validator\Mapping\TraversalStrategy;
use Symfony\Component\Validator\Tests\Fixtures\Entity;
use Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity;
use Symfony\Component\Validator\Validation;

/**
Expand All @@ -40,7 +40,6 @@ public function testLoadClassMetadata()
{
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping(true)
->addDefaultDoctrineAnnotationReader()
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}'))
->getValidator()
;
Expand Down Expand Up @@ -144,7 +143,6 @@ public function testExtractEnum()
$validator = Validation::createValidatorBuilder()
->addMethodMapping('loadValidatorMetadata')
->enableAnnotationMapping(true)
->addDefaultDoctrineAnnotationReader()
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}'))
->getValidator()
;
Expand All @@ -162,7 +160,6 @@ public function testFieldMappingsConfiguration()
{
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping(true)
->addDefaultDoctrineAnnotationReader()
->addXmlMappings([__DIR__.'/../Resources/validator/BaseUser.xml'])
->addLoader(
new DoctrineLoader(
Expand Down Expand Up @@ -204,7 +201,6 @@ public function testClassNoAutoMapping()
{
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping(true)
->addDefaultDoctrineAnnotationReader()
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{.*}'))
->getValidator();

Expand Down
2 changes: 0 additions & 2 deletions src/Symfony/Bridge/Doctrine/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,13 @@
"symfony/uid": "^5.4|^6.0|^7.0",
"symfony/validator": "^5.4.25|~6.2.12|^6.3.1|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0",
"doctrine/annotations": "^1.13.1|^2",
"doctrine/collections": "^1.0|^2.0",
"doctrine/data-fixtures": "^1.1",
"doctrine/dbal": "^2.13.1|^3.0",
"doctrine/orm": "^2.1 9E12 5",
"psr/log": "^1|^2|^3"
},
"conflict": {
"doctrine/annotations": "<1.13.1",
"doctrine/dbal": "<2.13.1",
"doctrine/lexer": "<1.1",
"doctrine/orm": "<2.15",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
use Symfony\Component\Validator\ObjectInitializerInterface;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\ValidatorBuilder;
use Symfony\Component\Webhook\Controller\WebhookController;
use Symfony\Component\WebLink\HttpHeaderSerializer;
use Symfony\Component\Workflow;
Expand Down Expand Up @@ -1609,7 +1610,7 @@ private function registerValidationConfiguration(array $config, ContainerBuilder

if (\array_key_exists('enable_annotations', $config) && $config['enable_annotations']) {
$validatorBuilder->addMethodCall('enableAnnotationMapping', [true]);
if ($this->isInitializedConfigEnabled('annotations')) {
if ($this->isInitializedConfigEnabled('annotations') && method_exists(ValidatorBuilder::class, 'setDoctrineAnnotationReader')) {
$validatorBuilder->addMethodCall('setDoctrineAnnotationReader', [new Reference('annotation_reader')]);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function testWarmUp()
$validatorBuilder->addXmlMapping(__DIR__.'/../Fixtures/Validation/Resources/person.xml');
$validatorBuilder->addYamlMapping(__DIR__.'/../Fixtures/Validation/Resources/author.yml');
$validatorBuilder->addMethodMapping('loadValidatorMetadata');
$validatorBuilder->enableAnnotationMapping(true)->addDefaultDoctrineAnnotationReader();
$validatorBuilder->enableAnnotationMapping();

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

$file = sys_get_temp_dir().'/cache-validator-with-annotations.php';
@unlink($file);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\Validation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ValidatorBuilder;
use Symfony\Component\Webhook\Client\RequestParser;
use Symfony\Component\Webhook\Controller\WebhookController;
use Symfony\Component\Workflow;
Expand Down Expand Up @@ -1308,12 +1309,17 @@ public function testValidationLegacyAnnotations()

$this->assertCount(8, $calls);
$this->assertSame('enableAnnotationMapping', $calls[4][0]);
$this->assertSame('setDoctrineAnnotationReader', $calls[5][0]);
$this->assertEquals([new Reference('annotation_reader')], $calls[5][1]);
$this->assertSame('addMethodMapping', $calls[6][0]);
$this->assertSame(['loadValidatorMetadata'], $calls[6][1]);
$this->assertSame('setMappingCache', $calls[7][0]);
$this->assertEquals([new Reference('validator.mapping.cache.adapter')], $calls[7][1]);
if (method_exists(ValidatorBuilder::class, 'setDoctrineAnnotationReader')) {
$this->assertSame('setDoctrineAnnotationReader', $calls[5][0]);
$this->assertEquals([new Reference('annotation_reader')], $calls[5][1]);
$i = 6;
} else {
$i = 5;
}
$this->assertSame('addMethodMapping', $calls[$i][0]);
$this->assertSame(['loadValidatorMetadata'], $calls[$i][1]);
$this->assertSame('setMappingCache', $calls[++$i][0]);
$this->assertEquals([new Reference('validator.mapping.cache.adapter')], $calls[$i][1]);
// no cache this time
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ class Category

public $id;

/**
* @Assert\Type("string")
*/
#[Assert\Type('string')]
public $name;
}
4 changes: 4 additions & 0 deletions src/Symfony/Component/Validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ CHANGELOG

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

6.3
---
Expand Down
5 changes: 2 additions & 3 deletions src/Symfony/Component/Validator/Constraints/GroupSequence.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
*
* When adding metadata to a class, you can override the "Default" group of
* that class with a group sequence:
* /**
* * @GroupSequence({"Address", "Strict"})
* *\/
* #[GroupSequence(['Address', 'Strict'])]
* class Address
* {
* // ...
Expand All @@ -47,6 +45,7 @@
* $validator->validate($address, null, "Address")
*
* @Annotation
*
* @Target({"CLASS", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
namespace Symfony\Component\Validator\Constraints;

/**
* Annotation to define a group sequence provider.
* Attribute to define a group sequence provider.
*
* @Annotation
*
* @Target({"CLASS", "ANNOTATION"})
*
* @author Bernhard Schussek <bschussek@gmail.com>
Expand Down
26 changes: 16 additions & 10 deletions src/Symfony/Component/Validator/Mapping/Loader/AnnotationLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,19 @@
*/
class AnnotationLoader implements LoaderInterface
{
/**
* @deprecated since Symfony 6.4, this property will be removed in 7.0
*
* @var Reader|null
*/
protected $reader;

public function __construct(Reader $reader = null)
{
if ($reader) {
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__);
}

$this->reader = $reader;
}

Expand Down Expand Up @@ -87,10 +96,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
return $success;
}

/**
* @param \ReflectionClass|\ReflectionMethod|\ReflectionProperty $reflection
*/
private function getAnnotations(object $reflection): iterable
private function getAnnotations(\ReflectionMethod|\ReflectionClass|\ReflectionProperty $reflection): iterable
{
$dedup = [];

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

$annotations = [];

if ($reflection instanceof \ReflectionClass) {
$annotations = $this->reader->getClassAnnotations($reflection);
if ($reflection instanceof \ReflectionClass && $annotations = $this->reader->getClassAnnotations($reflection)) {
trigger_deprecation('symfony/validator', '6.4', 'Class "%s" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.', $reflection->getName());
}
if ($reflection instanceof \ReflectionMethod) {
$annotations = $this->reader->getMethodAnnotations($reflection);
if ($reflection instanceof \ReflectionMethod && $annotations = $this->reader->getMethodAnnotations($reflection)) {
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());
}
if ($reflection instanceof \ReflectionProperty) {
$annotations = $this->reader->getPropertyAnnotations($reflection);
if ($reflection instanceof \ReflectionProperty && $annotations = $this->reader->getPropertyAnnotations($reflection)) {
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());
}

foreach ($dedup as $annotation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace Symfony\Component\Validator\Tests\Command;

use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Validator\Command\DebugCommand;
Expand All @@ -27,7 +26,7 @@ class DebugCommandTest extends TestCase
{
public function testOutputWithClassArgument()
{
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader(new AnnotationReader())));
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader()));

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

10000 public function testOutputWithPathArgument()
{
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader(new AnnotationReader())));
$command = new DebugCommand(new LazyLoadingMetadataFactory(new AnnotationLoader()));

$tester = new CommandTester($command);
$tester->execute(['class' => __DIR__.'/../Dummy'], ['decorated' => false]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Symfony\Component\Validator\Constraints\Expression;
use Symfony\Component\Validator\Constraints\ExpressionValidator;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
use Symfony\Component\Validator\Tests\Fixtures\Annotation\Entity;
use Symfony\Component\Validator\Tests\Fixtures\NestedAttribute\Entity;
use Symfony\Component\Validator\Tests\Fixtures\ToString;

class ExpressionValidatorTest extends ConstraintValidatorTestCase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Constraints\ValidValidator;
use Symfony\Component\Validator\ValidatorBuilder;

class ValidValidatorTest extends TestCase
{
public function testPropertyPathsArePassedToNestedContexts()
{
$validatorBuilder = new ValidatorBuilder();
$validator = $validatorBuilder->enableAnnotationMapping()->addDefaultDoctrineAnnotationReader()->getValidator();
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();

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

Expand All @@ -32,26 +31,19 @@ public function testPropertyPathsArePassedToNestedContexts()
public function testNullValues()
{
$validatorBuilder = new ValidatorBuilder();
$validator = $validatorBuilder->enableAnnotationMapping()->addDefaultDoctrineAnnotationReader()->getValidator();
$validator = $validatorBuilder->enableAnnotationMapping()->getValidator();

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

$this->assertCount(0, $violations);
}

protected function createValidator()
{
return new ValidValidator();
}
}

class Foo
{
/**
* @Assert\Valid(groups={"nested"})
*/
#[Assert\Valid(groups: ['nested'])]
public $fooBar;

public function __construct()
Expand All @@ -62,9 +54,7 @@ public function __construct()

class FooBar
{
/**
* @Assert\Valid(groups={"nested"})
*/
#[Assert\Valid(groups: ['nested'])]
public $fooBarBaz;

public function __construct()
Expand All @@ -75,8 +65,6 @@ public function __construct()

class FooBarBaz
{
/**
* @Assert\NotBlank(groups={"nested"})
*/
#[Assert\NotBlank(groups: ['nested'])]
public $foo;
}
19 changes: 15 additions & 4 deletions src/Symfony/Component/Validator/Tests/Constraints/WhenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
Expand All @@ -25,6 +26,8 @@

final class WhenTest extends TestCase
{
use ExpectDeprecationTrait;

public function testMissingOptionsExceptionIsThrown()
{
$this->expectException(MissingOptionsException::class);
Expand All @@ -42,11 +45,22 @@ public function testNonConstraintsAreRejected()
]);
}

/**
* @group legacy
*/
public function testAnnotations()
{
$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.');

$loader = new AnnotationLoader(new AnnotationReader());
$metadata = new ClassMetadata(WhenTestWithAnnotations::class);

$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.');
$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.');
$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.');
$this->expectDeprecation('Since symfony/validator 6.4: Property "Symfony\Component\Validator\Tests\Constrain 85D0 ts\WhenTestWithAnnotations::$qux" uses Doctrine Annotations to configure validation constraints, which is deprecated. Use PHP attributes instead.');
$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.');

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

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

/**
* @requires PHP 8.1
*/
public function testAttributes()
{
$loader = new AnnotationLoader(new AnnotationReader());
$loader = new AnnotationLoader();
$metadata = new ClassMetadata(WhenTestWithAttributes::class);

self::assertTrue($loader->loadClassMetadata($metadata));
Expand Down
Loading
0