Skip to content

Commit

Permalink
[FrameworkBundle][Validator] Remove remaining deprecations
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandre-daubois committed Aug 23, 2023
1 parent ca6a07d commit 6e8cab7
Show file tree
Hide file tree
Showing 18 changed files with 100 additions and 188 deletions.
6 changes: 5 additions & 1 deletion UPGRADE-7.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ FrameworkBundle
* Make the `framework.uid.default_uuid_version` config option default to `7`
* Make the `framework.uid.time_based_uuid_version` config option default to `7`
* Make the `framework.validation.email_validation_mode` config option default to `html5`
* Remove the `framework.validation.enable_annotations` config option, use `framework.validation.enable_attributes` instead
* Remove the `framework.serializer.enable_annotations` config option, use `framework.serializer.enable_attributes` instead

HttpFoundation
--------------
Expand Down Expand Up @@ -472,9 +474,11 @@ Validator
* Remove `VALIDATION_MODE_LOOSE` from `Email` constraint, use `VALIDATION_MODE_HTML5` instead
* Remove constraint `ExpressionLanguageSyntax`, use `ExpressionSyntax` instead
* Remove Doctrine annotations support in favor of native attributes
* Remove the annotation reader parameter from the constructor signature of `AnnotationLoader`
* Remove `ValidatorBuilder::setDoctrineAnnotationReader()`
* Remove `ValidatorBuilder::addDefaultDoctrineAnnotationReader()`
* Remove `ValidatorBuilder::enableAnnotationMapping()`, use `ValidatorBuilder::enableAttributeMapping()` instead
* Remove `ValidatorBuilder::disableAnnotationMapping()`, use `ValidatorBuilder::disableAttributeMapping()` instead
* Remove `AnnotationLoader`, use `AttributeLoader` instead

VarDumper
---------
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ CHANGELOG
* Make the `framework.uid.default_uuid_version` config option default to `7`
* Make the `framework.uid.time_based_uuid_version` config option default to `7`
* Make the `framework.validation.email_validation_mode` config option default to `html5`
* Remove the `framework.validation.enable_annotations` config option, use `framework.validation.enable_attributes` instead
* Remove the `framework.serializer.enable_annotations` config option, use `framework.serializer.enable_attributes` instead

6.4
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,6 @@ private function addValidationSection(ArrayNodeDefinition $rootNode, callable $e
->{$enableIfStandalone('symfony/validator', Validation::class)}()
->children()
->scalarNode('cache')->end()
->booleanNode('enable_annotations')->end()
->booleanNode('enable_attributes')->{!class_exists(FullStack::class) ? 'defaultTrue' : 'defaultFalse'}()->end()
->arrayNode('static_method')
->defaultValue(['loadValidatorMetadata'])
Expand Down Expand Up @@ -1090,24 +1089,9 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode, callable $e
$rootNode
->children()
->arrayNode('serializer')
->validate()
->always(function ($v) {
if (isset($v['enable_annotations'])) {
trigger_deprecation('symfony/framework-bundle', '6.4', 'Option "enable_annotations" at "framework.serializer" is deprecated. Use the "enable_attributes" option instead.');

if (!isset($v['enable_attributes'])) {
$v['enable_attributes'] = $v['enable_annotations'];
} else {
throw new LogicException('The "enable_annotations" and "enable_attributes" options at path "framework.serializer" must not be both set. Only the "enable_attributes" option must be used.');
}
}

return $v;
})->end()
->info('serializer configuration')
->{$enableIfStandalone('symfony/serializer', Serializer::class)}()
->children()
->booleanNode('enable_annotations')->end()
->booleanNode('enable_attributes')->{!class_exists(FullStack::class) ? 'defaultTrue' : 'defaultFalse'}()->end()
->scalarNode('name_converter')->end()
->scalarNode('circular_reference_handler')->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@

<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="enable-attributes" type="xsd:boolean" />
<xsd:attribute name="static-method" type="xsd:boolean" />
<xsd:attribute name="translation-domain" type="xsd:string" />
Expand Down Expand Up @@ -320,7 +319,6 @@
<xsd:element name="default-context" type="metadata" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="enable-attributes" type="xsd:boolean" />
<xsd:attribute name="name-converter" type="xsd:string" />
<xsd:attribute name="circular-reference-handler" type="xsd:string" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public function testDenormalizeWithNestedAttributesWithoutMetadata()

public function testDenormalizeWithSnakeCaseNestedAttributes()
{
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$factory = new ClassMetadataFactory(new AnnotationLoader());
$normalizer = new ObjectNormalizer($factory, new CamelCaseToSnakeCaseNameConverter());
$data = [
'one' => [
Expand All @@ -155,7 +155,7 @@ public function testDenormalizeWithSnakeCaseNestedAttributes()

public function testNormalizeWithSnakeCaseNestedAttributes()
{
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$factory = new ClassMetadataFactory(new AnnotationLoader());
$normalizer = new ObjectNormalizer($factory, new CamelCaseToSnakeCaseNameConverter());
$dummy = new SnakeCaseNestedDummy();
$dummy->fooBar = 'fooBar';
Expand Down
3 changes: 3 additions & 0 deletions src/Symfony/Component/Validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ CHANGELOG
* Remove the annotation reader parameter from the constructor signature of `AnnotationLoader`
* Remove `ValidatorBuilder::setDoctrineAnnotationReader()`
* Remove `ValidatorBuilder::addDefaultDoctrineAnnotationReader()`
* Remove `ValidatorBuilder::enableAnnotationMapping()`, use `ValidatorBuilder::enableAttributeMapping()` instead
* Remove `ValidatorBuilder::disableAnnotationMapping()`, use `ValidatorBuilder::disableAttributeMapping()` instead
* Remove `AnnotationLoader`, use `AttributeLoader` instead

6.4
---
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Validator/Constraints/Callback.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Callback extends Constraint

public function __construct(array|string|callable $callback = null, array $groups = null, mixed $payload = null, array $options = [])
{
// Invocation through annotations with an array parameter only
// Invocation through attributes with an array parameter only
if (\is_array($callback) && 1 === \count($callback) && isset($callback['value'])) {
$callback = $callback['value'];
}
Expand Down
3 changes: 0 additions & 3 deletions src/Symfony/Component/Validator/Constraints/When.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\LogicException;

/**
* @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class When extends Composite
{
Expand Down

This file was deleted.

74 changes: 71 additions & 3 deletions src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,85 @@

namespace Symfony\Component\Validator\Mapping\Loader;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\GroupSequenceProvider;
use Symfony\Component\Validator\Exception\MappingException;
use Symfony\Component\Validator\Mapping\ClassMetadata;

/**
* Loads validation metadata using PHP attributes.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Alexander M. Turek <me@derrabus.de>
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
class AttributeLoader extends AnnotationLoader
class AttributeLoader implements LoaderInterface
{
public function __construct()
public function loadClassMetadata(ClassMetadata $metadata): bool
{
$reflClass = $metadata->getReflectionClass();
$className = $reflClass->name;
$success = false;

foreach ($this->getAttributes($reflClass) as $constraint) {
if ($constraint instanceof GroupSequence) {
$metadata->setGroupSequence($constraint->groups);

Check failure on line 38 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:38:45: InvalidArgument: Argument 1 of Symfony\Component\Validator\Mapping\ClassMetadata::setGroupSequence expects Symfony\Component\Validator\Constraints\GroupSequence|array<array-key, string>, but array<int, Symfony\Component\Validator\Constraints\GroupSequence|array<array-key, string>|string> provided (see https://psalm.dev/004)

Check failure on line 38 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:38:45: InvalidArgument: Argument 1 of Symfony\Component\Validator\Mapping\ClassMetadata::setGroupSequence expects Symfony\Component\Validator\Constraints\GroupSequence|array<array-key, string>, but array<int, Symfony\Component\Validator\Constraints\GroupSequence|array<array-key, string>|string> provided (see https://psalm.dev/004)
} elseif ($constraint instanceof GroupSequenceProvider) {
$metadata->setGroupSequenceProvider(true);
} elseif ($constraint instanceof Constraint) {
$metadata->addConstraint($constraint);
}

$success = true;
}

foreach ($reflClass->getProperties() as $property) {
if ($property->getDeclaringClass()->name === $className) {
foreach ($this->getAttributes($property) as $constraint) {
if ($constraint instanceof Constraint) {
$metadata->addPropertyConstraint($property->name, $constraint);
}

$success = true;
}
}
}

foreach ($reflClass->getMethods() as $method) {
if ($method->getDeclaringClass()->name === $className) {
foreach ($this->getAttributes($method) as $constraint) {
if ($constraint instanceof Callback) {
$constraint->callback = $method->getName();

$metadata->addConstraint($constraint);
} elseif ($constraint instanceof Constraint) {
if (preg_match('/^(get|is|has)(.+)$/i', $method->name, $matches)) {
$metadata->addGetterMethodConstraint(lcfirst($matches[2]), $matches[0], $constraint);
} else {
throw new MappingException(sprintf('The constraint on "%s::%s()" cannot be added. Constraints can only be added on methods beginning with "get", "is" or "has".', $className, $method->name));
}
}

$success = true;
}
}
}

return $success;
}

private function getAttributes(\ReflectionMethod|\ReflectionClass|\ReflectionProperty $reflection): iterable
{
parent::__construct(null);
foreach ($reflection->getAttributes(GroupSequence::class) as $attribute) {

Check failure on line 85 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidAttribute

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:85:45: InvalidAttribute: Attribute Symfony\Component\Validator\Constraints\GroupSequence cannot be used on a property (see https://psalm.dev/242)

Check failure on line 85 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidAttribute

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:85:45: InvalidAttribute: Attribute Symfony\Component\Validator\Constraints\GroupSequence cannot be used on a method (see https://psalm.dev/242)

Check failure on line 85 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidAttribute

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:85:45: InvalidAttribute: Attribute Symfony\Component\Validator\Constraints\GroupSequence cannot be used on a property (see https://psalm.dev/242)

Check failure on line 85 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidAttribute

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:85:45: InvalidAttribute: Attribute Symfony\Component\Validator\Constraints\GroupSequence cannot be used on a method (see https://psalm.dev/242)
yield $attribute->newInstance();
}
foreach ($reflection->getAttributes(GroupSequenceProvider::class) as $attribute) {

Check failure on line 88 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidAttribute

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:88:45: InvalidAttribute: Attribute Symfony\Component\Validator\Constraints\GroupSequenceProvider cannot be used on a property (see https://psalm.dev/242)

Check failure on line 88 in src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidAttribute

src/Symfony/Component/Validator/Mapping/Loader/AttributeLoader.php:88:45: InvalidAttribute: Attribute Symfony\Component\Validator\Constraints\GroupSequenceProvider cannot be used on a method (see https://psalm.dev/242)
yield $attribute->newInstance();
}
foreach ($reflection->getAttributes(Constraint::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
yield $attribute->newInstance();
}
}
}
2 changes: 1 addition & 1 deletion src/Symfony/Component/Validator/Tests/ConstraintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public function testOptionsWithInvalidInternalPointer()
$this->assertEquals('foo', $constraint->property1);
}

public function testAnnotationSetUndefinedDefaultOption()
public function testAttributeSetUndefinedDefaultOption()
{
$this->expectException(ConstraintDefinitionException::class);
$this->expectExceptionMessage('No default option is configured for constraint "Symfony\Component\Validator\Tests\Fixtures\ConstraintB".');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,22 +205,22 @@ public function testConstraintGetTargets()
$this->assertEquals($targets, $constraint->getTargets());
}

// Should succeed. Needed when defining constraints as annotations.
// Should succeed. Needed when defining constraints as attributes.
public function testNoConstructorArguments()
{
$constraint = new Callback();

$this->assertSame([Constraint::CLASS_CONSTRAINT, Constraint::PROPERTY_CONSTRAINT], $constraint->getTargets());
}

public function testAnnotationInvocationSingleValued()
public function testAttributeInvocationSingleValued()
{
$constraint = new Callback(['value' => 'validateStatic']);

$this->assertEquals(new Callback('validateStatic'), $constraint);
}

public function testAnnotationInvocationMultiValued()
public function testAttributeInvocationMultiValued()
{
$constraint = new Callback(['value' => [__CLASS__.'_Class', 'validateCallback']]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public function testDefaultOption()
$this->assertEquals(5, $constraint->max);
}

public function testConstraintAnnotationDefaultOption()
public function testConstraintAttributeDefaultOption()
{
$constraint = new Count(['value' => 5, 'exactMessage' => 'message']);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public function testConstraintDefaultOption()
self::assertEquals(5, $constraint->max);
}

public function testConstraintAnnotationDefaultOption()
public function testConstraintAttributeDefaultOption()
{
$constraint = new Length(['value' => 5, 'exactMessage' => 'message']);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\MissingOptionsException;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Validator\Mapping\Loader\AttributeLoader;
use Symfony\Component\Validator\Tests\Constraints\Fixtures\WhenTestWithAttributes;

Expand Down

0 comments on commit 6e8cab7

Please sign in to comment.