[Validator] Autovalidation: skip readonly props

This commit is contained in:
Kévin Dunglas 2019-05-12 11:42:24 +02:00
parent 6c5faef5cb
commit e7dc5e1045
No known key found for this signature in database
GPG Key ID: 4D04EBEF06AAF3A6
4 changed files with 34 additions and 4 deletions

View File

@ -71,6 +71,7 @@
<service id="validator.property_info_loader" class="Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader"> <service id="validator.property_info_loader" class="Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader">
<argument type="service" id="property_info" /> <argument type="service" id="property_info" />
<argument type="service" id="property_info" /> <argument type="service" id="property_info" />
<argument type="service" id="property_info" />
<tag name="validator.auto_mapper" /> <tag name="validator.auto_mapper" />
</service> </service>

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Validator\Mapping\Loader; namespace Symfony\Component\Validator\Mapping\Loader;
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\PropertyInfo\Type as PropertyInfoType; use Symfony\Component\PropertyInfo\Type as PropertyInfoType;
@ -29,12 +30,14 @@ final class PropertyInfoLoader implements LoaderInterface
{ {
private $listExtractor; private $listExtractor;
private $typeExtractor; private $typeExtractor;
private $accessExtractor;
private $classValidatorRegexp; private $classValidatorRegexp;
public function __construct(PropertyListExtractorInterface $listExtractor, PropertyTypeExtractorInterface $typeExtractor, string $classValidatorRegexp = null) public function __construct(PropertyListExtractorInterface $listExtractor, PropertyTypeExtractorInterface $typeExtractor, PropertyAccessExtractorInterface $accessExtractor, string $classValidatorRegexp = null)
{ {
$this->listExtractor = $listExtractor; $this->listExtractor = $listExtractor;
$this->typeExtractor = $typeExtractor; $this->typeExtractor = $typeExtractor;
$this->accessExtractor = $accessExtractor;
$this->classValidatorRegexp = $classValidatorRegexp; $this->classValidatorRegexp = $classValidatorRegexp;
} }
@ -53,6 +56,10 @@ final class PropertyInfoLoader implements LoaderInterface
} }
foreach ($properties as $property) { foreach ($properties as $property) {
if (false === $this->accessExtractor->isWritable($className, $property)) {
continue;
}
$types = $this->typeExtractor->getTypes($className, $property); $types = $this->typeExtractor->getTypes($className, $property);
if (null === $types) { if (null === $types) {
continue; continue;

View File

@ -46,4 +46,6 @@ class PropertyInfoLoaderEntity
* }) * })
*/ */
public $alreadyPartiallyMappedCollection; public $alreadyPartiallyMappedCollection;
public $readOnly;
} }

View File

@ -45,6 +45,7 @@ class PropertyInfoLoaderTest extends TestCase
'alreadyMappedNotNull', 'alreadyMappedNotNull',
'alreadyMappedNotBlank', 'alreadyMappedNotBlank',
'alreadyPartiallyMappedCollection', 'alreadyPartiallyMappedCollection',
'readOnly',
]) ])
; ;
$propertyInfoStub $propertyInfoStub
@ -58,11 +59,27 @@ class PropertyInfoLoaderTest extends TestCase
[new Type(Type::BUILTIN_TYPE_FLOAT, true)], // The existing constraint is float [new Type(Type::BUILTIN_TYPE_FLOAT, true)], // The existing constraint is float
[new Type(Type::BUILTIN_TYPE_STRING, true)], [new Type(Type::BUILTIN_TYPE_STRING, true)],
[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_ARRAY, true, null, true, null, new Type(Type::BUILTIN_TYPE_FLOAT))],
[new Type(Type::BUILTIN_TYPE_STRING)]
))
;
$propertyInfoStub
->method('isWritable')
->will($this->onConsecutiveCalls(
true,
true,
true,
true,
true,
true,
true,
true,
true,
false
)) ))
; ;
$propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub); $propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub, $propertyInfoStub);
$validator = Validation::createValidatorBuilder() $validator = Validation::createValidatorBuilder()
->enableAnnotationMapping() ->enableAnnotationMapping()
@ -137,6 +154,9 @@ class PropertyInfoLoaderTest extends TestCase
$this->assertSame('string', $alreadyPartiallyMappedCollectionConstraints[0]->constraints[0]->type); $this->assertSame('string', $alreadyPartiallyMappedCollectionConstraints[0]->constraints[0]->type);
$this->assertInstanceOf(Iban::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[1]); $this->assertInstanceOf(Iban::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[1]);
$this->assertInstanceOf(NotNull::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[2]); $this->assertInstanceOf(NotNull::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[2]);
$readOnlyMetadata = $classMetadata->getPropertyMetadata('readOnly');
$this->assertEmpty($readOnlyMetadata);
} }
/** /**
@ -154,7 +174,7 @@ class PropertyInfoLoaderTest extends TestCase
->willReturn([new Type(Type::BUILTIN_TYPE_STRING)]) ->willReturn([new Type(Type::BUILTIN_TYPE_STRING)])
; ;
$propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub, $classValidatorRegexp); $propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub, $propertyInfoStub, $classValidatorRegexp);
$classMetadata = new ClassMetadata(PropertyInfoLoaderEntity::class); $classMetadata = new ClassMetadata(PropertyInfoLoaderEntity::class);
$this->assertSame($expected, $propertyInfoLoader->loadClassMetadata($classMetadata)); $this->assertSame($expected, $propertyInfoLoader->loadClassMetadata($classMetadata));