[Validator] Add AutoMapping constraint to enable or disable auto-validation
This commit is contained in:
parent
42be5f8132
commit
f6519ce88b
@ -69,6 +69,12 @@ class DoctrineLoaderEntity extends DoctrineLoaderParentEntity
|
||||
/** @ORM\Column(type="simple_array", length=100) */
|
||||
public $simpleArrayField = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(length=10)
|
||||
* @Assert\DisableAutoMapping
|
||||
*/
|
||||
public $noAutoMapping;
|
||||
|
||||
public static function loadValidatorMetadata(ClassMetadata $metadata): void
|
||||
{
|
||||
$allowEmptyString = property_exists(Assert\Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
|
||||
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\Tests\Fixtures;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @Assert\DisableAutoMapping
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DoctrineLoaderNoAutoMappingEntity
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(length=20, unique=true)
|
||||
*/
|
||||
public $maxLength;
|
||||
|
||||
/**
|
||||
* @Assert\EnableAutoMapping
|
||||
* @ORM\Column(length=20)
|
||||
*/
|
||||
public $autoMappingExplicitlyEnabled;
|
||||
}
|
@ -17,12 +17,15 @@ use Symfony\Bridge\Doctrine\Tests\Fixtures\BaseUser;
|
||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderEmbed;
|
||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderEntity;
|
||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderNestedEmbed;
|
||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderNoAutoMappingEntity;
|
||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderParentEntity;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Bridge\Doctrine\Validator\DoctrineLoader;
|
||||
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Mapping\CascadingStrategy;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Mapping\Loader\AutoMappingTrait;
|
||||
use Symfony\Component\Validator\Mapping\TraversalStrategy;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\Entity;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
@ -33,12 +36,15 @@ use Symfony\Component\Validator\ValidatorBuilder;
|
||||
*/
|
||||
class DoctrineLoaderTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
if (!trait_exists(AutoMappingTrait::class)) {
|
||||
$this->markTestSkipped('Auto-mapping requires symfony/validation 4.4+');
|
||||
}
|
||||
}
|
||||
|
||||
public function testLoadClassMetadata()
|
||||
{
|
||||
if (!method_exists(ValidatorBuilder::class, 'addLoader')) {
|
||||
$this->markTestSkipped('Auto-mapping requires symfony/validation 4.2+');
|
||||
}
|
||||
|
||||
$validator = Validation::createValidatorBuilder()
|
||||
->addMethodMapping('loadValidatorMetadata')
|
||||
->enableAnnotationMapping()
|
||||
@ -134,6 +140,12 @@ class DoctrineLoaderTest extends TestCase
|
||||
$this->assertCount(1, $textFieldConstraints);
|
||||
$this->assertInstanceOf(Length::class, $textFieldConstraints[0]);
|
||||
$this->assertSame(1000, $textFieldConstraints[0]->max);
|
||||
|
||||
$noAutoMappingMetadata = $classMetadata->getPropertyMetadata('noAutoMapping');
|
||||
$this->assertCount(1, $noAutoMappingMetadata);
|
||||
$noAutoMappingConstraints = $noAutoMappingMetadata[0]->getConstraints();
|
||||
$this->assertCount(1, $noAutoMappingConstraints);
|
||||
$this->assertInstanceOf(DisableAutoMapping::class, $noAutoMappingConstraints[0]);
|
||||
}
|
||||
|
||||
public function testFieldMappingsConfiguration()
|
||||
@ -180,4 +192,28 @@ class DoctrineLoaderTest extends TestCase
|
||||
[false, '{^'.preg_quote(Entity::class).'$}'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testClassNoAutoMapping()
|
||||
{
|
||||
if (!method_exists(ValidatorBuilder::class, 'addLoader')) {
|
||||
$this->markTestSkipped('Auto-mapping requires symfony/validation 4.2+');
|
||||
}
|
||||
|
||||
$validator = Validation::createValidatorBuilder()
|
||||
->enableAnnotationMapping()
|
||||
->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager()))
|
||||
->getValidator();
|
||||
|
||||
$classMetadata = $validator->getMetadataFor(new DoctrineLoaderNoAutoMappingEntity());
|
||||
|
||||
$classConstraints = $classMetadata->getConstraints();
|
||||
$this->assertCount(1, $classConstraints);
|
||||
$this->assertInstanceOf(DisableAutoMapping::class, $classConstraints[0]);
|
||||
|
||||
$maxLengthMetadata = $classMetadata->getPropertyMetadata('maxLength');
|
||||
$this->assertEmpty($maxLengthMetadata);
|
||||
|
||||
$autoMappingExplicitlyEnabledMetadata = $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled');
|
||||
$this->assertCount(2, $autoMappingExplicitlyEnabledMetadata[0]->constraints);
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,12 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Mapping\Loader\AutoMappingTrait;
|
||||
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
|
||||
|
||||
/**
|
||||
@ -28,6 +31,8 @@ use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
|
||||
*/
|
||||
final class DoctrineLoader implements LoaderInterface
|
||||
{
|
||||
use AutoMappingTrait;
|
||||
|
||||
private $entityManager;
|
||||
private $classValidatorRegexp;
|
||||
|
||||
@ -43,10 +48,6 @@ final class DoctrineLoader implements LoaderInterface
|
||||
public function loadClassMetadata(ClassMetadata $metadata): bool
|
||||
{
|
||||
$className = $metadata->getClassName();
|
||||
if (null !== $this->classValidatorRegexp && !preg_match($this->classValidatorRegexp, $className)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$doctrineMetadata = $this->entityManager->getClassMetadata($className);
|
||||
} catch (MappingException | OrmMappingException $exception) {
|
||||
@ -57,6 +58,9 @@ final class DoctrineLoader implements LoaderInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
$loaded = false;
|
||||
$enabledForClass = $this->isAutoMappingEnabledForClass($metadata, $this->classValidatorRegexp);
|
||||
|
||||
/* Available keys:
|
||||
- type
|
||||
- scale
|
||||
@ -69,41 +73,49 @@ final class DoctrineLoader implements LoaderInterface
|
||||
|
||||
// Type and nullable aren't handled here, use the PropertyInfo Loader instead.
|
||||
foreach ($doctrineMetadata->fieldMappings as $mapping) {
|
||||
$enabledForProperty = $enabledForClass;
|
||||
$lengthConstraint = null;
|
||||
foreach ($metadata->getPropertyMetadata($mapping['fieldName']) as $propertyMetadata) {
|
||||
foreach ($propertyMetadata->getConstraints() as $constraint) {
|
||||
// Enabling or disabling auto-mapping explicitly always takes precedence
|
||||
if ($constraint instanceof DisableAutoMapping) {
|
||||
continue 3;
|
||||
} elseif ($constraint instanceof EnableAutoMapping) {
|
||||
$enabledForProperty = true;
|
||||
} elseif ($constraint instanceof Length) {
|
||||
$lengthConstraint = $constraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$enabledForProperty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true === ($mapping['unique'] ?? false) && !isset($existingUniqueFields[$mapping['fieldName']])) {
|
||||
$metadata->addConstraint(new UniqueEntity(['fields' => $mapping['fieldName']]));
|
||||
$loaded = true;
|
||||
}
|
||||
|
||||
if (null === ($mapping['length'] ?? null) || !\in_array($mapping['type'], ['string', 'text'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$constraint = $this->getLengthConstraint($metadata, $mapping['fieldName']);
|
||||
if (null === $constraint) {
|
||||
if (null === $lengthConstraint) {
|
||||
if (isset($mapping['originalClass']) && false === strpos($mapping['declaredField'], '.')) {
|
||||
$metadata->addPropertyConstraint($mapping['declaredField'], new Valid());
|
||||
$loaded = true;
|
||||
} elseif (property_exists($className, $mapping['fieldName'])) {
|
||||
$metadata->addPropertyConstraint($mapping['fieldName'], new Length(['max' => $mapping['length']]));
|
||||
$loaded = true;
|
||||
}
|
||||
} elseif (null === $constraint->max) {
|
||||
} elseif (null === $lengthConstraint->max) {
|
||||
// If a Length constraint exists and no max length has been explicitly defined, set it
|
||||
$constraint->max = $mapping['length'];
|
||||
$lengthConstraint->max = $mapping['length'];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getLengthConstraint(ClassMetadata $metadata, string $fieldName): ?Length
|
||||
{
|
||||
foreach ($metadata->getPropertyMetadata($fieldName) as $propertyMetadata) {
|
||||
foreach ($propertyMetadata->getConstraints() as $constraint) {
|
||||
if ($constraint instanceof Length) {
|
||||
return $constraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return $loaded;
|
||||
}
|
||||
|
||||
private function getExistingUniqueFields(ClassMetadata $metadata): array
|
||||
|
@ -4,6 +4,7 @@ CHANGELOG
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* added `EnableAutoMapping` and `DisableAutoMapping` constraints to enable or disable auto mapping for class or a property
|
||||
* using anything else than a `string` as the code of a `ConstraintViolation` is deprecated, a `string` type-hint will
|
||||
be added to the constructor of the `ConstraintViolation` class and to the `ConstraintViolationBuilder::setCode()`
|
||||
method in 5.0
|
||||
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
|
||||
/**
|
||||
* Disables auto mapping.
|
||||
*
|
||||
* Using the annotations on a property has higher precedence than using it on a class,
|
||||
* which has higher precedence than any configuration that might be defined outside the class.
|
||||
*
|
||||
* @Annotation
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DisableAutoMapping extends Constraint
|
||||
{
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if (\is_array($options) && \array_key_exists('groups', $options)) {
|
||||
throw new ConstraintDefinitionException(sprintf('The option "groups" is not supported by the constraint "%s".', __CLASS__));
|
||||
}
|
||||
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTargets()
|
||||
{
|
||||
return [self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT];
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
|
||||
/**
|
||||
* Enables auto mapping.
|
||||
*
|
||||
* Using the annotations on a property has higher precedence than using it on a class,
|
||||
* which has higher precedence than any configuration that might be defined outside the class.
|
||||
*
|
||||
* @Annotation
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class EnableAutoMapping extends Constraint
|
||||
{
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if (\is_array($options) && \array_key_exists('groups', $options)) {
|
||||
throw new ConstraintDefinitionException(sprintf('The option "groups" is not supported by the constraint "%s".', __CLASS__));
|
||||
}
|
||||
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTargets()
|
||||
{
|
||||
return [self::PROPERTY_CONSTRAINT, self::CLASS_CONSTRAINT];
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Mapping\Loader;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* Utility methods to create auto mapping loaders.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
trait AutoMappingTrait
|
||||
{
|
||||
private function isAutoMappingEnabledForClass(ClassMetadata $metadata, string $classValidatorRegexp = null): bool
|
||||
{
|
||||
// Check if AutoMapping constraint is set first
|
||||
foreach ($metadata->getConstraints() as $constraint) {
|
||||
if ($constraint instanceof DisableAutoMapping) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($constraint instanceof EnableAutoMapping) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback on the config
|
||||
return null === $classValidatorRegexp || preg_match($classValidatorRegexp, $metadata->getClassName());
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\Type as PropertyInfoType;
|
||||
use Symfony\Component\Validator\Constraints\All;
|
||||
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Constraints\NotNull;
|
||||
use Symfony\Component\Validator\Constraints\Type;
|
||||
@ -28,6 +30,8 @@ use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
*/
|
||||
final class PropertyInfoLoader implements LoaderInterface
|
||||
{
|
||||
use AutoMappingTrait;
|
||||
|
||||
private $listExtractor;
|
||||
private $typeExtractor;
|
||||
private $accessExtractor;
|
||||
@ -47,14 +51,12 @@ final class PropertyInfoLoader implements LoaderInterface
|
||||
public function loadClassMetadata(ClassMetadata $metadata): bool
|
||||
{
|
||||
$className = $metadata->getClassName();
|
||||
if (null !== $this->classValidatorRegexp && !preg_match($this->classValidatorRegexp, $className)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$properties = $this->listExtractor->getProperties($className)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$loaded = false;
|
||||
$enabledForClass = $this->isAutoMappingEnabledForClass($metadata, $this->classValidatorRegexp);
|
||||
foreach ($properties as $property) {
|
||||
if (false === $this->accessExtractor->isWritable($className, $property)) {
|
||||
continue;
|
||||
@ -69,12 +71,22 @@ final class PropertyInfoLoader implements LoaderInterface
|
||||
continue;
|
||||
}
|
||||
|
||||
$enabledForProperty = $enabledForClass;
|
||||
$hasTypeConstraint = false;
|
||||
$hasNotNullConstraint = false;
|
||||
$hasNotBlankConstraint = false;
|
||||
$allConstraint = null;
|
||||
foreach ($metadata->getPropertyMetadata($property) as $propertyMetadata) {
|
||||
foreach ($propertyMetadata->getConstraints() as $constraint) {
|
||||
// Enabling or disabling auto-mapping explicitly always takes precedence
|
||||
if ($constraint instanceof DisableAutoMapping) {
|
||||
continue 3;
|
||||
}
|
||||
|
||||
if ($constraint instanceof EnableAutoMapping) {
|
||||
$enabledForProperty = true;
|
||||
}
|
||||
|
||||
if ($constraint instanceof Type) {
|
||||
$hasTypeConstraint = true;
|
||||
} elseif ($constraint instanceof NotNull) {
|
||||
@ -87,6 +99,11 @@ final class PropertyInfoLoader implements LoaderInterface
|
||||
}
|
||||
}
|
||||
|
||||
if (!$enabledForProperty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$loaded = true;
|
||||
$builtinTypes = [];
|
||||
$nullable = false;
|
||||
$scalar = true;
|
||||
@ -118,7 +135,7 @@ final class PropertyInfoLoader implements LoaderInterface
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return $loaded;
|
||||
}
|
||||
|
||||
private function getTypeConstraint(string $builtinType, PropertyInfoType $type): Type
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Constraints;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
|
||||
/**
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DisableAutoMappingTest extends TestCase
|
||||
{
|
||||
public function testGroups()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage(sprintf('The option "groups" is not supported by the constraint "%s".', DisableAutoMapping::class));
|
||||
|
||||
new DisableAutoMapping(['groups' => 'foo']);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Constraints;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraints\EnableAutoMapping;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
|
||||
/**
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class EnableAutoMappingTest extends TestCase
|
||||
{
|
||||
public function testGroups()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage(sprintf('The option "groups" is not supported by the constraint "%s".', EnableAutoMapping::class));
|
||||
|
||||
new EnableAutoMapping(['groups' => 'foo']);
|
||||
}
|
||||
}
|
@ -49,6 +49,11 @@ class PropertyInfoLoaderEntity
|
||||
|
||||
public $readOnly;
|
||||
|
||||
/**
|
||||
* @Assert\DisableAutoMapping
|
||||
*/
|
||||
public $noAutoMapping;
|
||||
|
||||
public function setNonExistentField()
|
||||
{
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Validator\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* @Assert\DisableAutoMapping
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class PropertyInfoLoaderNoAutoMappingEntity
|
||||
{
|
||||
public $string;
|
||||
|
||||
/**
|
||||
* @Assert\EnableAutoMapping
|
||||
*/
|
||||
public $autoMappingExplicitlyEnabled;
|
||||
}
|
@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
use Symfony\Component\Validator\Constraints\All;
|
||||
use Symfony\Component\Validator\Constraints\DisableAutoMapping;
|
||||
use Symfony\Component\Validator\Constraints\Iban;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Constraints\NotNull;
|
||||
@ -23,6 +24,7 @@ use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\Entity;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\PropertyInfoLoaderEntity;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\PropertyInfoLoaderNoAutoMappingEntity;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
|
||||
/**
|
||||
@ -47,6 +49,7 @@ class PropertyInfoLoaderTest extends TestCase
|
||||
'alreadyPartiallyMappedCollection',
|
||||
'readOnly',
|
||||
'nonExistentField',
|
||||
'noAutoMapping',
|
||||
])
|
||||
;
|
||||
$propertyInfoStub
|
||||
@ -61,6 +64,7 @@ class PropertyInfoLoaderTest extends TestCase
|
||||
[new Type(Type::BUILTIN_TYPE_STRING, true)],
|
||||
[new Type(Type::BUILTIN_TYPE_STRING, true)],
|
||||
[new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, null, new Type(Type::BUILTIN_TYPE_FLOAT))],
|
||||
[new Type(Type::BUILTIN_TYPE_STRING)],
|
||||
[new Type(Type::BUILTIN_TYPE_STRING)]
|
||||
))
|
||||
;
|
||||
@ -76,7 +80,8 @@ class PropertyInfoLoaderTest extends TestCase
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
))
|
||||
;
|
||||
|
||||
@ -158,6 +163,12 @@ class PropertyInfoLoaderTest extends TestCase
|
||||
|
||||
$readOnlyMetadata = $classMetadata->getPropertyMetadata('readOnly');
|
||||
$this->assertEmpty($readOnlyMetadata);
|
||||
|
||||
$noAutoMappingMetadata = $classMetadata->getPropertyMetadata('noAutoMapping');
|
||||
$this->assertCount(1, $noAutoMappingMetadata);
|
||||
$noAutoMappingConstraints = $noAutoMappingMetadata[0]->getConstraints();
|
||||
$this->assertCount(1, $noAutoMappingConstraints);
|
||||
$this->assertInstanceOf(DisableAutoMapping::class, $noAutoMappingConstraints[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,4 +200,30 @@ class PropertyInfoLoaderTest extends TestCase
|
||||
[false, '{^'.preg_quote(Entity::class).'$}'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testClassNoAutoMapping()
|
||||
{
|
||||
$propertyInfoStub = $this->createMock(PropertyInfoExtractorInterface::class);
|
||||
$propertyInfoStub
|
||||
->method('getProperties')
|
||||
->willReturn(['string', 'autoMappingExplicitlyEnabled'])
|
||||
;
|
||||
$propertyInfoStub
|
||||
->method('getTypes')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[new Type(Type::BUILTIN_TYPE_STRING)],
|
||||
[new Type(Type::BUILTIN_TYPE_BOOL)]
|
||||
);
|
||||
|
||||
$propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub, $propertyInfoStub);
|
||||
$validator = Validation::createValidatorBuilder()
|
||||
->enableAnnotationMapping()
|
||||
->addLoader($propertyInfoLoader)
|
||||
->getValidator()
|
||||
;
|
||||
|
||||
$classMetadata = $validator->getMetadataFor(new PropertyInfoLoaderNoAutoMappingEntity());
|
||||
$this->assertEmpty($classMetadata->getPropertyMetadata('string'));
|
||||
$this->assertCount(3, $classMetadata->getPropertyMetadata('autoMappingExplicitlyEnabled')[0]->constraints);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user