[Validator] Add target guards for Composite nested constraints
This commit is contained in:
parent
a8b5b15c25
commit
a08ddf7636
@ -136,6 +136,17 @@ abstract class Composite extends Constraint
|
||||
*/
|
||||
abstract protected function getCompositeOption();
|
||||
|
||||
/**
|
||||
* @internal Used by metadata
|
||||
*
|
||||
* @return Constraint[]
|
||||
*/
|
||||
public function getNestedContraints()
|
||||
{
|
||||
/* @var Constraint[] $nestedConstraints */
|
||||
return $this->{$this->getCompositeOption()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the nested constraints.
|
||||
*
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Validator\Mapping;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
use Symfony\Component\Validator\Constraints\Traverse;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
@ -178,9 +179,7 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
|
||||
*/
|
||||
public function addConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets())) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', \get_class($constraint)));
|
||||
}
|
||||
$this->checkConstraint($constraint);
|
||||
|
||||
if ($constraint instanceof Traverse) {
|
||||
if ($constraint->traverse) {
|
||||
@ -495,4 +494,17 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
|
||||
|
||||
$this->members[$property][] = $metadata;
|
||||
}
|
||||
|
||||
private function checkConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets(), true)) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', \get_class($constraint)));
|
||||
}
|
||||
|
||||
if ($constraint instanceof Composite) {
|
||||
foreach ($constraint->getNestedContraints() as $nestedContraint) {
|
||||
$this->checkConstraint($nestedContraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Validator\Mapping;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
|
||||
/**
|
||||
@ -71,9 +72,7 @@ abstract class MemberMetadata extends GenericMetadata implements PropertyMetadat
|
||||
*/
|
||||
public function addConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets())) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', \get_class($constraint)));
|
||||
}
|
||||
$this->checkConstraint($constraint);
|
||||
|
||||
parent::addConstraint($constraint);
|
||||
|
||||
@ -181,4 +180,17 @@ abstract class MemberMetadata extends GenericMetadata implements PropertyMetadat
|
||||
* @return \ReflectionMethod|\ReflectionProperty The reflection instance
|
||||
*/
|
||||
abstract protected function newReflectionMember($objectOrClassName);
|
||||
|
||||
private function checkConstraint(Constraint $constraint)
|
||||
{
|
||||
if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets(), true)) {
|
||||
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', \get_class($constraint)));
|
||||
}
|
||||
|
||||
if ($constraint instanceof Composite) {
|
||||
foreach ($constraint->getNestedContraints() as $nestedContraint) {
|
||||
$this->checkConstraint($nestedContraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ namespace Symfony\Component\Validator\Tests\Mapping;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint;
|
||||
@ -52,6 +55,20 @@ class ClassMetadataTest extends TestCase
|
||||
$this->metadata->addConstraint(new PropertyConstraint());
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintRejectsNestedPropertyConstraints()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint" cannot be put on classes.');
|
||||
|
||||
$this->metadata->addConstraint(new ClassCompositeConstraint([new PropertyConstraint()]));
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintAcceptsNestedClassConstraints()
|
||||
{
|
||||
$this->metadata->addConstraint($constraint = new ClassCompositeConstraint([new ClassConstraint()]));
|
||||
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
|
||||
}
|
||||
|
||||
public function testAddPropertyConstraints()
|
||||
{
|
||||
$this->metadata->addPropertyConstraint('firstName', new ConstraintA());
|
||||
@ -311,3 +328,23 @@ class ClassMetadataTest extends TestCase
|
||||
$this->assertCount(0, $this->metadata->getPropertyMetadata('foo'), '->getPropertyMetadata() returns an empty collection if no metadata is configured for the given property');
|
||||
}
|
||||
}
|
||||
|
||||
class ClassCompositeConstraint extends Composite
|
||||
{
|
||||
public $nested;
|
||||
|
||||
public function getDefaultOption()
|
||||
{
|
||||
return $this->getCompositeOption();
|
||||
}
|
||||
|
||||
protected function getCompositeOption()
|
||||
{
|
||||
return 'nested';
|
||||
}
|
||||
|
||||
public function getTargets()
|
||||
{
|
||||
return [self::CLASS_CONSTRAINT];
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,16 @@
|
||||
namespace Symfony\Component\Validator\Tests\Mapping;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Constraints\Collection;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\Required;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\Mapping\MemberMetadata;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\ConstraintB;
|
||||
use Symfony\Component\Validator\Tests\Fixtures\PropertyConstraint;
|
||||
|
||||
class MemberMetadataTest extends TestCase
|
||||
{
|
||||
@ -43,6 +48,34 @@ class MemberMetadataTest extends TestCase
|
||||
$this->metadata->addConstraint(new ClassConstraint());
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintRejectsNestedClassConstraints()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\ClassConstraint" cannot be put on properties or getters.');
|
||||
|
||||
$this->metadata->addConstraint(new PropertyCompositeConstraint([new ClassConstraint()]));
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintRejectsDeepNestedClassConstraints()
|
||||
{
|
||||
$this->expectException(ConstraintDefinitionException::class);
|
||||
$this->expectExceptionMessage('The constraint "Symfony\Component\Validator\Tests\Fixtures\ClassConstraint" cannot be put on properties or getters.');
|
||||
|
||||
$this->metadata->addConstraint(new Collection(['field1' => new Required([new ClassConstraint()])]));
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintAcceptsNestedPropertyConstraints()
|
||||
{
|
||||
$this->metadata->addConstraint($constraint = new PropertyCompositeConstraint([new PropertyConstraint()]));
|
||||
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
|
||||
}
|
||||
|
||||
public function testAddCompositeConstraintAcceptsDeepNestedPropertyConstraints()
|
||||
{
|
||||
$this->metadata->addConstraint($constraint = new Collection(['field1' => new Required([new PropertyConstraint()])]));
|
||||
$this->assertSame($this->metadata->getConstraints(), [$constraint]);
|
||||
}
|
||||
|
||||
public function testSerialize()
|
||||
{
|
||||
$this->metadata->addConstraint(new ConstraintA(['property1' => 'A']));
|
||||
@ -82,3 +115,18 @@ class TestMemberMetadata extends MemberMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyCompositeConstraint extends Composite
|
||||
{
|
||||
public $nested;
|
||||
|
||||
public function getDefaultOption()
|
||||
{
|
||||
return $this->getCompositeOption();
|
||||
}
|
||||
|
||||
protected function getCompositeOption()
|
||||
{
|
||||
return 'nested';
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user