From 6822774d37e335e259c5d88e9911340482403efe Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 31 Oct 2020 23:59:36 +0100 Subject: [PATCH 1/8] [Validator] Merge RecursiveValidatorTest with its parents. --- .../Tests/Validator/AbstractTest.php | 722 ------ .../Tests/Validator/AbstractValidatorTest.php | 1281 ----------- .../Validator/RecursiveValidatorTest.php | 1935 ++++++++++++++++- 3 files changed, 1934 insertions(+), 2004 deletions(-) delete mode 100644 src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php delete mode 100644 src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php deleted file mode 100644 index 06f7e85775..0000000000 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php +++ /dev/null @@ -1,722 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Tests\Validator; - -use Symfony\Component\Validator\Constraints\Callback; -use Symfony\Component\Validator\Constraints\Collection; -use Symfony\Component\Validator\Constraints\Expression; -use Symfony\Component\Validator\Constraints\GroupSequence; -use Symfony\Component\Validator\Constraints\NotBlank; -use Symfony\Component\Validator\Constraints\NotNull; -use Symfony\Component\Validator\Constraints\Traverse; -use Symfony\Component\Validator\Constraints\Valid; -use Symfony\Component\Validator\ConstraintViolationInterface; -use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Component\Validator\Mapping\ClassMetadata; -use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; -use Symfony\Component\Validator\Tests\Fixtures\Entity; -use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; -use Symfony\Component\Validator\Tests\Fixtures\Reference; -use Symfony\Component\Validator\Validator\ValidatorInterface; - -/** - * @author Bernhard Schussek - */ -abstract class AbstractTest extends AbstractValidatorTest -{ - /** - * @var ValidatorInterface - */ - protected $validator; - - abstract protected function createValidator(MetadataFactoryInterface $metadataFactory, array $objectInitializers = []): ValidatorInterface; - - protected function setUp(): void - { - parent::setUp(); - - $this->validator = $this->createValidator($this->metadataFactory); - } - - protected function validate($value, $constraints = null, $groups = null) - { - return $this->validator->validate($value, $constraints, $groups); - } - - protected function validateProperty($object, $propertyName, $groups = null) - { - return $this->validator->validateProperty($object, $propertyName, $groups); - } - - protected function validatePropertyValue($object, $propertyName, $value, $groups = null) - { - return $this->validator->validatePropertyValue($object, $propertyName, $value, $groups); - } - - public function testValidateConstraintWithoutGroup() - { - $violations = $this->validator->validate(null, new NotNull()); - - $this->assertCount(1, $violations); - } - - public function testValidateWithEmptyArrayAsConstraint() - { - $violations = $this->validator->validate('value', []); - $this->assertCount(0, $violations); - } - - public function testGroupSequenceAbortsAfterFailedGroup() - { - $entity = new Entity(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message 1'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message 2'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => function () {}, - 'groups' => 'Group 1', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group 2', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 3', - ])); - - $sequence = new GroupSequence(['Group 1', 'Group 2', 'Group 3']); - $violations = $this->validator->validate($entity, new Valid(), $sequence); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message 1', $violations[0]->getMessage()); - } - - public function testGroupSequenceIncludesReferences() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Reference violation 1'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Reference violation 2'); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group 1', - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 2', - ])); - - $sequence = new GroupSequence(['Group 1', 'Entity']); - $violations = $this->validator->validate($entity, new Valid(), $sequence); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Reference violation 1', $violations[0]->getMessage()); - } - - public function testValidateInSeparateContext() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $callback1 = function ($value, ExecutionContextInterface $context) use ($entity) { - $violations = $context - ->getValidator() - // Since the validator is not context aware, the group must - // be passed explicitly - ->validate($value->reference, new Valid(), 'Group') - ; - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('', $violations[0]->getPropertyPath()); - - // The root is different as we're in a new context - $this->assertSame($entity->reference, $violations[0]->getRoot()); - $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - - // Verify that this method is called - $context->addViolation('Separate violation'); - }; - - $callback2 = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity->reference, $context->getRoot()); - $this->assertSame($entity->reference, $context->getValue()); - $this->assertSame($entity->reference, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group', - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group', - ])); - - $violations = $this->validator->validate($entity, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Separate violation', $violations[0]->getMessage()); - } - - public function testValidateInContext() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $previousValue = $context->getValue(); - $previousObject = $context->getObject(); - $previousMetadata = $context->getMetadata(); - $previousPath = $context->getPropertyPath(); - $previousGroup = $context->getGroup(); - - $context - ->getValidator() - ->inContext($context) - ->atPath('subpath') - ->validate($value->reference) - ; - - // context changes shouldn't leak out of the validate() call - $this->assertSame($previousValue, $context->getValue()); - $this->assertSame($previousObject, $context->getObject()); - $this->assertSame($previousMetadata, $context->getMetadata()); - $this->assertSame($previousPath, $context->getPropertyPath()); - $this->assertSame($previousGroup, $context->getGroup()); - }; - - $callback2 = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('subpath', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference, $context->getValue()); - $this->assertSame($entity->reference, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group', - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group', - ])); - - $violations = $this->validator->validate($entity, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('subpath', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testValidateArrayInContext() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $previousValue = $context->getValue(); - $previousObject = $context->getObject(); - $previousMetadata = $context->getMetadata(); - $previousPath = $context->getPropertyPath(); - $previousGroup = $context->getGroup(); - - $context - ->getValidator() - ->inContext($context) - ->atPath('subpath') - ->validate(['key' => $value->reference]) - ; - - // context changes shouldn't leak out of the validate() call - $this->assertSame($previousValue, $context->getValue()); - $this->assertSame($previousObject, $context->getObject()); - $this->assertSame($previousMetadata, $context->getMetadata()); - $this->assertSame($previousPath, $context->getPropertyPath()); - $this->assertSame($previousGroup, $context->getGroup()); - }; - - $callback2 = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('subpath[key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference, $context->getValue()); - $this->assertSame($entity->reference, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group', - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group', - ])); - - $violations = $this->validator->validate($entity, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('subpath[key]', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testTraverseTraversableByDefault() - { - $entity = new Entity(); - $traversable = new \ArrayIterator(['key' => $entity]); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity, $traversable) { - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('[key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->metadata, $context->getMetadata()); - $this->assertSame($traversable, $context->getRoot()); - $this->assertSame($entity, $context->getValue()); - $this->assertSame($entity, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($traversable, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('[key]', $violations[0]->getPropertyPath()); - $this->assertSame($traversable, $violations[0]->getRoot()); - $this->assertSame($entity, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testTraversalEnabledOnClass() - { - $entity = new Entity(); - $traversable = new \ArrayIterator(['key' => $entity]); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $traversableMetadata = new ClassMetadata('ArrayIterator'); - $traversableMetadata->addConstraint(new Traverse(true)); - - $this->metadataFactory->addMetadata($traversableMetadata); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($traversable, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - public function testTraversalDisabledOnClass() - { - $entity = new Entity(); - $traversable = new \ArrayIterator(['key' => $entity]); - - $callback = function ($value, ExecutionContextInterface $context) { - $this->fail('Should not be called'); - }; - - $traversableMetadata = new ClassMetadata('ArrayIterator'); - $traversableMetadata->addConstraint(new Traverse(false)); - - $this->metadataFactory->addMetadata($traversableMetadata); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($traversable, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testExpectTraversableIfTraversalEnabledOnClass() - { - $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); - $entity = new Entity(); - - $this->metadata->addConstraint(new Traverse(true)); - - $this->validator->validate($entity); - } - - public function testReferenceTraversalDisabledOnClass() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(['key' => new Reference()]); - - $callback = function ($value, ExecutionContextInterface $context) { - $this->fail('Should not be called'); - }; - - $traversableMetadata = new ClassMetadata('ArrayIterator'); - $traversableMetadata->addConstraint(new Traverse(false)); - - $this->metadataFactory->addMetadata($traversableMetadata); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $violations = $this->validate($entity, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testReferenceTraversalEnabledOnReferenceDisabledOnClass() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(['key' => new Reference()]); - - $callback = function ($value, ExecutionContextInterface $context) { - $this->fail('Should not be called'); - }; - - $traversableMetadata = new ClassMetadata('ArrayIterator'); - $traversableMetadata->addConstraint(new Traverse(false)); - - $this->metadataFactory->addMetadata($traversableMetadata); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - $this->metadata->addPropertyConstraint('reference', new Valid([ - 'traverse' => true, - ])); - - $violations = $this->validate($entity, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testReferenceTraversalDisabledOnReferenceEnabledOnClass() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(['key' => new Reference()]); - - $callback = function ($value, ExecutionContextInterface $context) { - $this->fail('Should not be called'); - }; - - $traversableMetadata = new ClassMetadata('ArrayIterator'); - $traversableMetadata->addConstraint(new Traverse(true)); - - $this->metadataFactory->addMetadata($traversableMetadata); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - $this->metadata->addPropertyConstraint('reference', new Valid([ - 'traverse' => false, - ])); - - $violations = $this->validate($entity, new Valid(), 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testAddCustomizedViolation() - { - $entity = new Entity(); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->buildViolation('Message %param%') - ->setParameter('%param%', 'value') - ->setInvalidValue('Invalid value') - ->setPlural(2) - ->setCode('42') - ->addViolation(); - }; - - $this->metadata->addConstraint(new Callback($callback)); - - $violations = $this->validator->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Invalid value', $violations[0]->getInvalidValue()); - $this->assertSame(2, $violations[0]->getPlural()); - $this->assertSame('42', $violations[0]->getCode()); - } - - public function testNoDuplicateValidationIfClassConstraintInMultipleGroups() - { - $entity = new Entity(); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => ['Group 1', 'Group 2'], - ])); - - $violations = $this->validator->validate($entity, new Valid(), ['Group 1', 'Group 2']); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - public function testNoDuplicateValidationIfPropertyConstraintInMultipleGroups() - { - $entity = new Entity(); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $this->metadata->addPropertyConstraint('firstName', new Callback([ - 'callback' => $callback, - 'groups' => ['Group 1', 'Group 2'], - ])); - - $violations = $this->validator->validate($entity, new Valid(), ['Group 1', 'Group 2']); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - public function testValidateFailsIfNoConstraintsAndNoObjectOrArray() - { - $this->expectException('Symfony\Component\Validator\Exception\RuntimeException'); - $this->validate('Foobar'); - } - - public function testAccessCurrentObject() - { - $called = false; - $entity = new Entity(); - $entity->firstName = 'Bernhard'; - $entity->data = ['firstName' => 'Bernhard']; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity, &$called) { - $called = true; - $this->assertSame($entity, $context->getObject()); - }; - - $this->metadata->addConstraint(new Callback($callback)); - $this->metadata->addPropertyConstraint('firstName', new Callback($callback)); - $this->metadata->addPropertyConstraint('data', new Collection(['firstName' => new Expression('value == this.firstName')])); - - $this->validator->validate($entity); - - $this->assertTrue($called); - } - - public function testInitializeObjectsOnFirstValidation() - { - $entity = new Entity(); - $entity->initialized = false; - - // prepare initializers that set "initialized" to true - $initializer1 = $this->getMockBuilder('Symfony\\Component\\Validator\\ObjectInitializerInterface')->getMock(); - $initializer2 = $this->getMockBuilder('Symfony\\Component\\Validator\\ObjectInitializerInterface')->getMock(); - - $initializer1->expects($this->once()) - ->method('initialize') - ->with($entity) - ->willReturnCallback(function ($object) { - $object->initialized = true; - }); - - $initializer2->expects($this->once()) - ->method('initialize') - ->with($entity); - - $this->validator = $this->createValidator($this->metadataFactory, [ - $initializer1, - $initializer2, - ]); - - // prepare constraint which - // * checks that "initialized" is set to true - // * validates the object again - $callback = function ($object, ExecutionContextInterface $context) { - $this->assertTrue($object->initialized); - - // validate again in same group - $validator = $context->getValidator()->inContext($context); - - $validator->validate($object); - - // validate again in other group - $validator->validate($object, null, 'SomeGroup'); - }; - - $this->metadata->addConstraint(new Callback($callback)); - - $this->validate($entity); - - $this->assertTrue($entity->initialized); - } - - public function testPassConstraintToViolation() - { - $constraint = new FailingConstraint(); - $violations = $this->validate('Foobar', $constraint); - - $this->assertCount(1, $violations); - $this->assertSame($constraint, $violations[0]->getConstraint()); - } - - public function testCollectionConstraitViolationHasCorrectContext() - { - $data = [ - 'foo' => 'fooValue', - ]; - - // Missing field must not be the first in the collection validation - $constraint = new Collection([ - 'foo' => new NotNull(), - 'bar' => new NotNull(), - ]); - - $violations = $this->validate($data, $constraint); - - $this->assertCount(1, $violations); - $this->assertSame($constraint, $violations[0]->getConstraint()); - } - - public function testNestedObjectIsNotValidatedIfGroupInValidConstraintIsNotValidated() - { - $entity = new Entity(); - $entity->firstName = ''; - $reference = new Reference(); - $reference->value = ''; - $entity->childA = $reference; - - $this->metadata->addPropertyConstraint('firstName', new NotBlank(['groups' => 'group1'])); - $this->metadata->addPropertyConstraint('childA', new Valid(['groups' => 'group1'])); - $this->referenceMetadata->addPropertyConstraint('value', new NotBlank()); - - $violations = $this->validator->validate($entity, null, []); - - $this->assertCount(0, $violations); - } - - public function testNestedObjectIsValidatedIfGroupInValidConstraintIsValidated() - { - $entity = new Entity(); - $entity->firstName = ''; - $reference = new Reference(); - $reference->value = ''; - $entity->childA = $reference; - - $this->metadata->addPropertyConstraint('firstName', new NotBlank(['groups' => 'group1'])); - $this->metadata->addPropertyConstraint('childA', new Valid(['groups' => 'group1'])); - $this->referenceMetadata->addPropertyConstraint('value', new NotBlank(['groups' => 'group1'])); - - $violations = $this->validator->validate($entity, null, ['Default', 'group1']); - - $this->assertCount(2, $violations); - } - - public function testNestedObjectIsValidatedInMultipleGroupsIfGroupInValidConstraintIsValidated() - { - $entity = new Entity(); - $entity->firstName = null; - - $reference = new Reference(); - $reference->value = null; - - $entity->childA = $reference; - - $this->metadata->addPropertyConstraint('firstName', new NotBlank()); - $this->metadata->addPropertyConstraint('childA', new Valid(['groups' => ['group1', 'group2']])); - - $this->referenceMetadata->addPropertyConstraint('value', new NotBlank(['groups' => 'group1'])); - $this->referenceMetadata->addPropertyConstraint('value', new NotNull(['groups' => 'group2'])); - - $violations = $this->validator->validate($entity, null, ['Default', 'group1', 'group2']); - - $this->assertCount(3, $violations); - } -} diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php deleted file mode 100644 index e9bad07096..0000000000 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php +++ /dev/null @@ -1,1281 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Tests\Validator; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraints\Callback; -use Symfony\Component\Validator\Constraints\GroupSequence; -use Symfony\Component\Validator\Constraints\Valid; -use Symfony\Component\Validator\ConstraintViolationInterface; -use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Component\Validator\Mapping\ClassMetadata; -use Symfony\Component\Validator\Tests\Fixtures\Entity; -use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; -use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity; -use Symfony\Component\Validator\Tests\Fixtures\Reference; - -/** - * @author Bernhard Schussek - */ -abstract class AbstractValidatorTest extends TestCase -{ - const ENTITY_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Entity'; - - const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference'; - - const LAZY_PROPERTY = 'Symfony\Component\Validator\Validator\LazyProperty'; - - /** - * @var FakeMetadataFactory - */ - public $metadataFactory; - - /** - * @var ClassMetadata - */ - public $metadata; - - /** - * @var ClassMetadata - */ - public $referenceMetadata; - - protected function setUp(): void - { - $this->metadataFactory = new FakeMetadataFactory(); - $this->metadata = new ClassMetadata(self::ENTITY_CLASS); - $this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS); - $this->metadataFactory->addMetadata($this->metadata); - $this->metadataFactory->addMetadata($this->referenceMetadata); - $this->metadataFactory->addMetadata(new ClassMetadata(self::LAZY_PROPERTY)); - } - - protected function tearDown(): void - { - $this->metadataFactory = null; - $this->metadata = null; - $this->referenceMetadata = null; - } - - abstract protected function validate($value, $constraints = null, $groups = null); - - abstract protected function validateProperty($object, $propertyName, $groups = null); - - abstract protected function validatePropertyValue($object, $propertyName, $value, $groups = null); - - public function testValidate() - { - $callback = function ($value, ExecutionContextInterface $context) { - $this->assertNull($context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame('Bernhard', $context->getRoot()); - $this->assertSame('Bernhard', $context->getValue()); - $this->assertSame('Bernhard', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $constraint = new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ]); - - $violations = $this->validate('Bernhard', $constraint, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('', $violations[0]->getPropertyPath()); - $this->assertSame('Bernhard', $violations[0]->getRoot()); - $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testClassConstraint() - { - $entity = new Entity(); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->metadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity, $context->getValue()); - $this->assertSame($entity, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testPropertyConstraint() - { - $entity = new Entity(); - $entity->firstName = 'Bernhard'; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); - - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertSame('firstName', $context->getPropertyName()); - $this->assertSame('firstName', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame('Bernhard', $context->getValue()); - $this->assertSame('Bernhard', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('firstName', new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('firstName', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testGetterConstraint() - { - $entity = new Entity(); - $entity->setLastName('Schussek'); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $propertyMetadatas = $this->metadata->getPropertyMetadata('lastName'); - - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertSame('lastName', $context->getPropertyName()); - $this->assertSame('lastName', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame('Schussek', $context->getValue()); - $this->assertSame('Schussek', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addGetterConstraint('lastName', new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('lastName', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Schussek', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testArray() - { - $entity = new Entity(); - $array = ['key' => $entity]; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity, $array) { - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('[key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->metadata, $context->getMetadata()); - $this->assertSame($array, $context->getRoot()); - $this->assertSame($entity, $context->getValue()); - $this->assertSame($entity, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($array, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('[key]', $violations[0]->getPropertyPath()); - $this->assertSame($array, $violations[0]->getRoot()); - $this->assertSame($entity, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testRecursiveArray() - { - $entity = new Entity(); - $array = [2 => ['key' => $entity]]; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity, $array) { - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('[2][key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->metadata, $context->getMetadata()); - $this->assertSame($array, $context->getRoot()); - $this->assertSame($entity, $context->getValue()); - $this->assertSame($entity, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($array, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('[2][key]', $violations[0]->getPropertyPath()); - $this->assertSame($array, $violations[0]->getRoot()); - $this->assertSame($entity, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testTraversable() - { - $entity = new Entity(); - $traversable = new \ArrayIterator(['key' => $entity]); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity, $traversable) { - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('[key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->metadata, $context->getMetadata()); - $this->assertSame($traversable, $context->getRoot()); - $this->assertSame($entity, $context->getValue()); - $this->assertSame($entity, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($traversable, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('[key]', $violations[0]->getPropertyPath()); - $this->assertSame($traversable, $violations[0]->getRoot()); - $this->assertSame($entity, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testRecursiveTraversable() - { - $entity = new Entity(); - $traversable = new \ArrayIterator([ - 2 => new \ArrayIterator(['key' => $entity]), - ]); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity, $traversable) { - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('[2][key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->metadata, $context->getMetadata()); - $this->assertSame($traversable, $context->getRoot()); - $this->assertSame($entity, $context->getValue()); - $this->assertSame($entity, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($traversable, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('[2][key]', $violations[0]->getPropertyPath()); - $this->assertSame($traversable, $violations[0]->getRoot()); - $this->assertSame($entity, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testReferenceClassConstraint() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('reference', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference, $context->getValue()); - $this->assertSame($entity->reference, $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testReferencePropertyConstraint() - { - $entity = new Entity(); - $entity->reference = new Reference(); - $entity->reference->value = 'Foobar'; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $propertyMetadatas = $this->referenceMetadata->getPropertyMetadata('value'); - - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertSame('value', $context->getPropertyName()); - $this->assertSame('reference.value', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame('Foobar', $context->getValue()); - $this->assertSame('Foobar', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->referenceMetadata->addPropertyConstraint('value', new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference.value', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Foobar', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testReferenceGetterConstraint() - { - $entity = new Entity(); - $entity->reference = new Reference(); - $entity->reference->setPrivateValue('Bamboo'); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $propertyMetadatas = $this->referenceMetadata->getPropertyMetadata('privateValue'); - - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertSame('privateValue', $context->getPropertyName()); - $this->assertSame('reference.privateValue', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame('Bamboo', $context->getValue()); - $this->assertSame('Bamboo', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->referenceMetadata->addPropertyConstraint('privateValue', new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference.privateValue', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Bamboo', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testsIgnoreNullReference() - { - $entity = new Entity(); - $entity->reference = null; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testFailOnScalarReferences() - { - $this->expectException('Symfony\Component\Validator\Exception\NoSuchMetadataException'); - $entity = new Entity(); - $entity->reference = 'string'; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->validate($entity); - } - - /** - * @dataProvider getConstraintMethods - */ - public function testArrayReference($constraintMethod) - { - $entity = new Entity(); - $entity->reference = ['key' => new Reference()]; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('reference[key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference['key'], $context->getValue()); - $this->assertSame($entity->reference['key'], $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->$constraintMethod('reference', new Valid()); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference[key]', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - /** - * @dataProvider getConstraintMethods - */ - public function testRecursiveArrayReference($constraintMethod) - { - $entity = new Entity(); - $entity->reference = [2 => ['key' => new Reference()]]; - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('reference[2][key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference[2]['key'], $context->getValue()); - $this->assertSame($entity->reference[2]['key'], $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->$constraintMethod('reference', new Valid()); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testOnlyCascadedArraysAreTraversed() - { - $entity = new Entity(); - $entity->reference = ['key' => new Reference()]; - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('reference', new Callback([ - 'callback' => function () {}, - 'groups' => 'Group', - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - /** - * @dataProvider getConstraintMethods - */ - public function testArrayTraversalCannotBeDisabled($constraintMethod) - { - $entity = new Entity(); - $entity->reference = ['key' => new Reference()]; - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->$constraintMethod('reference', new Valid([ - 'traverse' => false, - ])); - $this->referenceMetadata->addConstraint(new Callback($callback)); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - /** - * @dataProvider getConstraintMethods - */ - public function testRecursiveArrayTraversalCannotBeDisabled($constraintMethod) - { - $entity = new Entity(); - $entity->reference = [2 => ['key' => new Reference()]]; - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->$constraintMethod('reference', new Valid([ - 'traverse' => false, - ])); - - $this->referenceMetadata->addConstraint(new Callback($callback)); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - /** - * @dataProvider getConstraintMethods - */ - public function testIgnoreScalarsDuringArrayTraversal($constraintMethod) - { - $entity = new Entity(); - $entity->reference = ['string', 1234]; - - $this->metadata->$constraintMethod('reference', new Valid()); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - /** - * @dataProvider getConstraintMethods - */ - public function testIgnoreNullDuringArrayTraversal($constraintMethod) - { - $entity = new Entity(); - $entity->reference = [null]; - - $this->metadata->$constraintMethod('reference', new Valid()); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testTraversableReference() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(['key' => new Reference()]); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('reference[key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference['key'], $context->getValue()); - $this->assertSame($entity->reference['key'], $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference[key]', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testDisableTraversableTraversal() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(['key' => new Reference()]); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); - $this->metadata->addPropertyConstraint('reference', new Valid([ - 'traverse' => false, - ])); - $this->referenceMetadata->addConstraint(new Callback($callback)); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(0, $violations); - } - - public function testMetadataMustExistIfTraversalIsDisabled() - { - $this->expectException('Symfony\Component\Validator\Exception\NoSuchMetadataException'); - $entity = new Entity(); - $entity->reference = new \ArrayIterator(); - - $this->metadata->addPropertyConstraint('reference', new Valid([ - 'traverse' => false, - ])); - - $this->validate($entity); - } - - public function testEnableRecursiveTraversableTraversal() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator([ - 2 => new \ArrayIterator(['key' => new Reference()]), - ]); - - $callback = function ($value, ExecutionContextInterface $context) use ($entity) { - $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); - $this->assertNull($context->getPropertyName()); - $this->assertSame('reference[2][key]', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($this->referenceMetadata, $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame($entity->reference[2]['key'], $context->getValue()); - $this->assertSame($entity->reference[2]['key'], $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid([ - 'traverse' => true, - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group', - ])); - - $violations = $this->validate($entity, null, 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testValidateProperty() - { - $entity = new Entity(); - $entity->firstName = 'Bernhard'; - $entity->setLastName('Schussek'); - - $callback1 = function ($value, ExecutionContextInterface $context) use ($entity) { - $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); - - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertSame('firstName', $context->getPropertyName()); - $this->assertSame('firstName', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame('Bernhard', $context->getValue()); - $this->assertSame('Bernhard', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Other violation'); - }; - - $this->metadata->addPropertyConstraint('firstName', new Callback([ - 'callback' => $callback1, - 'groups' => 'Group', - ])); - $this->metadata->addPropertyConstraint('lastName', new Callback([ - 'callback' => $callback2, - 'groups' => 'Group', - ])); - - $violations = $this->validateProperty($entity, 'firstName', 'Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('firstName', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - /** - * https://github.com/symfony/symfony/issues/11604. - */ - public function testValidatePropertyWithoutConstraints() - { - $entity = new Entity(); - $violations = $this->validateProperty($entity, 'lastName'); - - $this->assertCount(0, $violations, '->validateProperty() returns no violations if no constraints have been configured for the property being validated'); - } - - public function testValidatePropertyValue() - { - $entity = new Entity(); - $entity->setLastName('Schussek'); - - $callback1 = function ($value, ExecutionContextInterface $context) use ($entity) { - $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); - - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertSame('firstName', $context->getPropertyName()); - $this->assertSame('firstName', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame($entity, $context->getRoot()); - $this->assertSame('Bernhard', $context->getValue()); - $this->assertSame('Bernhard', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Other violation'); - }; - - $this->metadata->addPropertyConstraint('firstName', new Callback([ - 'callback' => $callback1, - 'groups' => 'Group', - ])); - $this->metadata->addPropertyConstraint('lastName', new Callback([ - 'callback' => $callback2, - 'groups' => 'Group', - ])); - - $violations = $this->validatePropertyValue( - $entity, - 'firstName', - 'Bernhard', - 'Group' - ); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('firstName', $violations[0]->getPropertyPath()); - $this->assertSame($entity, $violations[0]->getRoot()); - $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - public function testValidatePropertyValueWithClassName() - { - $callback1 = function ($value, ExecutionContextInterface $context) { - $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); - - $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); - $this->assertSame('firstName', $context->getPropertyName()); - $this->assertSame('', $context->getPropertyPath()); - $this->assertSame('Group', $context->getGroup()); - $this->assertSame($propertyMetadatas[0], $context->getMetadata()); - $this->assertSame('Bernhard', $context->getRoot()); - $this->assertSame('Bernhard', $context->getValue()); - $this->assertSame('Bernhard', $value); - - $context->addViolation('Message %param%', ['%param%' => 'value']); - }; - - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Other violation'); - }; - - $this->metadata->addPropertyConstraint('firstName', new Callback([ - 'callback' => $callback1, - 'groups' => 'Group', - ])); - $this->metadata->addPropertyConstraint('lastName', new Callback([ - 'callback' => $callback2, - 'groups' => 'Group', - ])); - - $violations = $this->validatePropertyValue( - self::ENTITY_CLASS, - 'firstName', - 'Bernhard', - 'Group' - ); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Message value', $violations[0]->getMessage()); - $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); - $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); - $this->assertSame('', $violations[0]->getPropertyPath()); - $this->assertSame('Bernhard', $violations[0]->getRoot()); - $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); - $this->assertNull($violations[0]->getPlural()); - $this->assertNull($violations[0]->getCode()); - } - - /** - * https://github.com/symfony/symfony/issues/11604. - */ - public function testValidatePropertyValueWithoutConstraints() - { - $entity = new Entity(); - $violations = $this->validatePropertyValue($entity, 'lastName', 'foo'); - - $this->assertCount(0, $violations, '->validatePropertyValue() returns no violations if no constraints have been configured for the property being validated'); - } - - public function testValidateObjectOnlyOncePerGroup() - { - $entity = new Entity(); - $entity->reference = new Reference(); - $entity->reference2 = $entity->reference; - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->metadata->addPropertyConstraint('reference2', new Valid()); - $this->referenceMetadata->addConstraint(new Callback($callback)); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - public function testValidateDifferentObjectsSeparately() - { - $entity = new Entity(); - $entity->reference = new Reference(); - $entity->reference2 = new Reference(); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->metadata->addPropertyConstraint('reference2', new Valid()); - $this->referenceMetadata->addConstraint(new Callback($callback)); - - $violations = $this->validate($entity); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(2, $violations); - } - - public function testValidateSingleGroup() - { - $entity = new Entity(); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group 1', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group 2', - ])); - - $violations = $this->validate($entity, null, 'Group 2'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - } - - public function testValidateMultipleGroups() - { - $entity = new Entity(); - - $callback = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Message'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group 1', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback, - 'groups' => 'Group 2', - ])); - - $violations = $this->validate($entity, null, ['Group 1', 'Group 2']); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(2, $violations); - } - - public function testReplaceDefaultGroupByGroupSequenceObject() - { - $entity = new Entity(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Group 2'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Group 3'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => function () {}, - 'groups' => 'Group 1', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group 2', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 3', - ])); - - $sequence = new GroupSequence(['Group 1', 'Group 2', 'Group 3', 'Entity']); - $this->metadata->setGroupSequence($sequence); - - $violations = $this->validate($entity, null, 'Default'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Violation in Group 2', $violations[0]->getMessage()); - } - - public function testReplaceDefaultGroupByGroupSequenceArray() - { - $entity = new Entity(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Group 2'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Group 3'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => function () {}, - 'groups' => 'Group 1', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group 2', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 3', - ])); - - $sequence = ['Group 1', 'Group 2', 'Group 3', 'Entity']; - $this->metadata->setGroupSequence($sequence); - - $violations = $this->validate($entity, null, 'Default'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Violation in Group 2', $violations[0]->getMessage()); - } - - public function testPropagateDefaultGroupToReferenceWhenReplacingDefaultGroup() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Default group'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in group sequence'); - }; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Default', - ])); - $this->referenceMetadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 1', - ])); - - $sequence = new GroupSequence(['Group 1', 'Entity']); - $this->metadata->setGroupSequence($sequence); - - $violations = $this->validate($entity, null, 'Default'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Violation in Default group', $violations[0]->getMessage()); - } - - public function testValidateCustomGroupWhenDefaultGroupWasReplaced() - { - $entity = new Entity(); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in other group'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in group sequence'); - }; - - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Other Group', - ])); - $this->metadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 1', - ])); - - $sequence = new GroupSequence(['Group 1', 'Entity']); - $this->metadata->setGroupSequence($sequence); - - $violations = $this->validate($entity, null, 'Other Group'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(1, $violations); - $this->assertSame('Violation in other group', $violations[0]->getMessage()); - } - - /** - * @dataProvider getTestReplaceDefaultGroup - */ - public function testReplaceDefaultGroup($sequence, array $assertViolations) - { - $entity = new GroupSequenceProviderEntity($sequence); - - $callback1 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Group 2'); - }; - $callback2 = function ($value, ExecutionContextInterface $context) { - $context->addViolation('Violation in Group 3'); - }; - - $metadata = new ClassMetadata(\get_class($entity)); - $metadata->addConstraint(new Callback([ - 'callback' => function () {}, - 'groups' => 'Group 1', - ])); - $metadata->addConstraint(new Callback([ - 'callback' => $callback1, - 'groups' => 'Group 2', - ])); - $metadata->addConstraint(new Callback([ - 'callback' => $callback2, - 'groups' => 'Group 3', - ])); - $metadata->setGroupSequenceProvider(true); - - $this->metadataFactory->addMetadata($metadata); - - $violations = $this->validate($entity, null, 'Default'); - - /* @var ConstraintViolationInterface[] $violations */ - $this->assertCount(\count($assertViolations), $violations); - foreach ($assertViolations as $key => $message) { - $this->assertSame($message, $violations[$key]->getMessage()); - } - } - - public function getConstraintMethods() - { - return [ - ['addPropertyConstraint'], - ['addGetterConstraint'], - ]; - } - - public function getTestReplaceDefaultGroup() - { - return [ - [ - 'sequence' => new GroupSequence(['Group 1', 'Group 2', 'Group 3', 'Entity']), - 'assertViolations' => [ - 'Violation in Group 2', - ], - ], - [ - 'sequence' => ['Group 1', 'Group 2', 'Group 3', 'Entity'], - 'assertViolations' => [ - 'Violation in Group 2', - ], - ], - [ - 'sequence' => new GroupSequence(['Group 1', ['Group 2', 'Group 3'], 'Entity']), - 'assertViolations' => [ - 'Violation in Group 2', - 'Violation in Group 3', - ], - ], - [ - 'sequence' => ['Group 1', ['Group 2', 'Group 3'], 'Entity'], - 'assertViolations' => [ - 'Violation in Group 2', - 'Violation in Group 3', - ], - ], - ]; - } -} diff --git a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php index 48de5820fc..1af4c9acfa 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php @@ -11,9 +11,12 @@ namespace Symfony\Component\Validator\Tests\Validator; +use PHPUnit\Framework\TestCase; use Symfony\Component\Translation\IdentityTranslator; use Symfony\Component\Validator\Constraints\All; +use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\Collection; +use Symfony\Component\Validator\Constraints\Expression; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\IsTrue; use Symfony\Component\Validator\Constraints\Length; @@ -21,9 +24,12 @@ use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Required; +use Symfony\Component\Validator\Constraints\Traverse; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\ConstraintValidatorFactory; +use Symfony\Component\Validator\ConstraintViolationInterface; use Symfony\Component\Validator\Context\ExecutionContextFactory; +use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildA; @@ -31,11 +37,1938 @@ use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildB; use Symfony\Component\Validator\Tests\Fixtures\Entity; use Symfony\Component\Validator\Tests\Fixtures\EntityParent; use Symfony\Component\Validator\Tests\Fixtures\EntityWithGroupedConstraintOnMethods; +use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; +use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; +use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity; +use Symfony\Component\Validator\Tests\Fixtures\Reference; +use Symfony\Component\Validator\Validator\LazyProperty; use Symfony\Component\Validator\Validator\RecursiveValidator; use Symfony\Component\Validator\Validator\ValidatorInterface; -class RecursiveValidatorTest extends AbstractTest +class RecursiveValidatorTest extends TestCase { + private const ENTITY_CLASS = Entity::class; + private const REFERENCE_CLASS = Reference::class; + + /** + * @var FakeMetadataFactory + */ + private $metadataFactory; + + /** + * @var ClassMetadata + */ + private $metadata; + + /** + * @var ClassMetadata + */ + private $referenceMetadata; + + /** + * @var ValidatorInterface + */ + private $validator; + + protected function setUp(): void + { + $this->metadataFactory = new FakeMetadataFactory(); + $this->metadata = new ClassMetadata(self::ENTITY_CLASS); + $this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS); + $this->metadataFactory->addMetadata($this->metadata); + $this->metadataFactory->addMetadata($this->referenceMetadata); + $this->metadataFactory->addMetadata(new ClassMetadata(LazyProperty::class)); + + $this->validator = $this->createValidator($this->metadataFactory); + } + + protected function tearDown(): void + { + $this->metadataFactory = null; + $this->metadata = null; + $this->referenceMetadata = null; + } + + protected function validate($value, $constraints = null, $groups = null) + { + return $this->validator->validate($value, $constraints, $groups); + } + + protected function validateProperty($object, $propertyName, $groups = null) + { + return $this->validator->validateProperty($object, $propertyName, $groups); + } + + protected function validatePropertyValue($object, $propertyName, $value, $groups = null) + { + return $this->validator->validatePropertyValue($object, $propertyName, $value, $groups); + } + + public function testValidate() + { + $callback = function ($value, ExecutionContextInterface $context) { + $this->assertNull($context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame('Bernhard', $context->getRoot()); + $this->assertSame('Bernhard', $context->getValue()); + $this->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $constraint = new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ]); + + $violations = $this->validate('Bernhard', $constraint, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame('Bernhard', $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testClassConstraint() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->metadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity, $context->getValue()); + $this->assertSame($entity, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testPropertyConstraint() + { + $entity = new Entity(); + $entity->firstName = 'Bernhard'; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); + + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertSame('firstName', $context->getPropertyName()); + $this->assertSame('firstName', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame('Bernhard', $context->getValue()); + $this->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('firstName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testGetterConstraint() + { + $entity = new Entity(); + $entity->setLastName('Schussek'); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $propertyMetadatas = $this->metadata->getPropertyMetadata('lastName'); + + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertSame('lastName', $context->getPropertyName()); + $this->assertSame('lastName', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame('Schussek', $context->getValue()); + $this->assertSame('Schussek', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addGetterConstraint('lastName', new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('lastName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Schussek', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testArray() + { + $entity = new Entity(); + $array = ['key' => $entity]; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity, $array) { + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('[key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->metadata, $context->getMetadata()); + $this->assertSame($array, $context->getRoot()); + $this->assertSame($entity, $context->getValue()); + $this->assertSame($entity, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($array, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('[key]', $violations[0]->getPropertyPath()); + $this->assertSame($array, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testRecursiveArray() + { + $entity = new Entity(); + $array = [2 => ['key' => $entity]]; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity, $array) { + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('[2][key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->metadata, $context->getMetadata()); + $this->assertSame($array, $context->getRoot()); + $this->assertSame($entity, $context->getValue()); + $this->assertSame($entity, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($array, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('[2][key]', $violations[0]->getPropertyPath()); + $this->assertSame($array, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testTraversable() + { + $entity = new Entity(); + $traversable = new \ArrayIterator(['key' => $entity]); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity, $traversable) { + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('[key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->metadata, $context->getMetadata()); + $this->assertSame($traversable, $context->getRoot()); + $this->assertSame($entity, $context->getValue()); + $this->assertSame($entity, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($traversable, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('[key]', $violations[0]->getPropertyPath()); + $this->assertSame($traversable, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testRecursiveTraversable() + { + $entity = new Entity(); + $traversable = new \ArrayIterator([ + 2 => new \ArrayIterator(['key' => $entity]), + ]); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity, $traversable) { + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('[2][key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->metadata, $context->getMetadata()); + $this->assertSame($traversable, $context->getRoot()); + $this->assertSame($entity, $context->getValue()); + $this->assertSame($entity, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($traversable, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('[2][key]', $violations[0]->getPropertyPath()); + $this->assertSame($traversable, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testReferenceClassConstraint() + { + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('reference', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference, $context->getValue()); + $this->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testReferencePropertyConstraint() + { + $entity = new Entity(); + $entity->reference = new Reference(); + $entity->reference->value = 'Foobar'; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $propertyMetadatas = $this->referenceMetadata->getPropertyMetadata('value'); + + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertSame('value', $context->getPropertyName()); + $this->assertSame('reference.value', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame('Foobar', $context->getValue()); + $this->assertSame('Foobar', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addPropertyConstraint('value', new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference.value', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Foobar', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testReferenceGetterConstraint() + { + $entity = new Entity(); + $entity->reference = new Reference(); + $entity->reference->setPrivateValue('Bamboo'); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $propertyMetadatas = $this->referenceMetadata->getPropertyMetadata('privateValue'); + + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertSame('privateValue', $context->getPropertyName()); + $this->assertSame('reference.privateValue', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame('Bamboo', $context->getValue()); + $this->assertSame('Bamboo', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addPropertyConstraint('privateValue', new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference.privateValue', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bamboo', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testsIgnoreNullReference() + { + $entity = new Entity(); + $entity->reference = null; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testFailOnScalarReferences() + { + $this->expectException('Symfony\Component\Validator\Exception\NoSuchMetadataException'); + $entity = new Entity(); + $entity->reference = 'string'; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $this->validate($entity); + } + + /** + * @dataProvider getConstraintMethods + */ + public function testArrayReference($constraintMethod) + { + $entity = new Entity(); + $entity->reference = ['key' => new Reference()]; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('reference[key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference['key'], $context->getValue()); + $this->assertSame($entity->reference['key'], $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->$constraintMethod('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference[key]', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + /** + * @dataProvider getConstraintMethods + */ + public function testRecursiveArrayReference($constraintMethod) + { + $entity = new Entity(); + $entity->reference = [2 => ['key' => new Reference()]]; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('reference[2][key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference[2]['key'], $context->getValue()); + $this->assertSame($entity->reference[2]['key'], $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->$constraintMethod('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testOnlyCascadedArraysAreTraversed() + { + $entity = new Entity(); + $entity->reference = ['key' => new Reference()]; + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('reference', new Callback([ + 'callback' => function () {}, + 'groups' => 'Group', + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + /** + * @dataProvider getConstraintMethods + */ + public function testArrayTraversalCannotBeDisabled($constraintMethod) + { + $entity = new Entity(); + $entity->reference = ['key' => new Reference()]; + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->$constraintMethod('reference', new Valid([ + 'traverse' => false, + ])); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + /** + * @dataProvider getConstraintMethods + */ + public function testRecursiveArrayTraversalCannotBeDisabled($constraintMethod) + { + $entity = new Entity(); + $entity->reference = [2 => ['key' => new Reference()]]; + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->$constraintMethod('reference', new Valid([ + 'traverse' => false, + ])); + + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + /** + * @dataProvider getConstraintMethods + */ + public function testIgnoreScalarsDuringArrayTraversal($constraintMethod) + { + $entity = new Entity(); + $entity->reference = ['string', 1234]; + + $this->metadata->$constraintMethod('reference', new Valid()); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + /** + * @dataProvider getConstraintMethods + */ + public function testIgnoreNullDuringArrayTraversal($constraintMethod) + { + $entity = new Entity(); + $entity->reference = [null]; + + $this->metadata->$constraintMethod('reference', new Valid()); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testTraversableReference() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(['key' => new Reference()]); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('reference[key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference['key'], $context->getValue()); + $this->assertSame($entity->reference['key'], $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference[key]', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testDisableTraversableTraversal() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(['key' => new Reference()]); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); + $this->metadata->addPropertyConstraint('reference', new Valid([ + 'traverse' => false, + ])); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testMetadataMustExistIfTraversalIsDisabled() + { + $this->expectException('Symfony\Component\Validator\Exception\NoSuchMetadataException'); + $entity = new Entity(); + $entity->reference = new \ArrayIterator(); + + $this->metadata->addPropertyConstraint('reference', new Valid([ + 'traverse' => false, + ])); + + $this->validate($entity); + } + + public function testEnableRecursiveTraversableTraversal() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator([ + 2 => new \ArrayIterator(['key' => new Reference()]), + ]); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('reference[2][key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference[2]['key'], $context->getValue()); + $this->assertSame($entity->reference[2]['key'], $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid([ + 'traverse' => true, + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($entity, null, 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testValidateProperty() + { + $entity = new Entity(); + $entity->firstName = 'Bernhard'; + $entity->setLastName('Schussek'); + + $callback1 = function ($value, ExecutionContextInterface $context) use ($entity) { + $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); + + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertSame('firstName', $context->getPropertyName()); + $this->assertSame('firstName', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame('Bernhard', $context->getValue()); + $this->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Other violation'); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback([ + 'callback' => $callback1, + 'groups' => 'Group', + ])); + $this->metadata->addPropertyConstraint('lastName', new Callback([ + 'callback' => $callback2, + 'groups' => 'Group', + ])); + + $violations = $this->validateProperty($entity, 'firstName', 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('firstName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + /** + * https://github.com/symfony/symfony/issues/11604. + */ + public function testValidatePropertyWithoutConstraints() + { + $entity = new Entity(); + $violations = $this->validateProperty($entity, 'lastName'); + + $this->assertCount(0, $violations, '->validateProperty() returns no violations if no constraints have been configured for the property being validated'); + } + + public function testValidatePropertyValue() + { + $entity = new Entity(); + $entity->setLastName('Schussek'); + + $callback1 = function ($value, ExecutionContextInterface $context) use ($entity) { + $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); + + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertSame('firstName', $context->getPropertyName()); + $this->assertSame('firstName', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame('Bernhard', $context->getValue()); + $this->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Other violation'); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback([ + 'callback' => $callback1, + 'groups' => 'Group', + ])); + $this->metadata->addPropertyConstraint('lastName', new Callback([ + 'callback' => $callback2, + 'groups' => 'Group', + ])); + + $violations = $this->validatePropertyValue( + $entity, + 'firstName', + 'Bernhard', + 'Group' + ); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('firstName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testValidatePropertyValueWithClassName() + { + $callback1 = function ($value, ExecutionContextInterface $context) { + $propertyMetadatas = $this->metadata->getPropertyMetadata('firstName'); + + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertSame('firstName', $context->getPropertyName()); + $this->assertSame('', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($propertyMetadatas[0], $context->getMetadata()); + $this->assertSame('Bernhard', $context->getRoot()); + $this->assertSame('Bernhard', $context->getValue()); + $this->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Other violation'); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback([ + 'callback' => $callback1, + 'groups' => 'Group', + ])); + $this->metadata->addPropertyConstraint('lastName', new Callback([ + 'callback' => $callback2, + 'groups' => 'Group', + ])); + + $violations = $this->validatePropertyValue( + self::ENTITY_CLASS, + 'firstName', + 'Bernhard', + 'Group' + ); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame('Bernhard', $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + /** + * https://github.com/symfony/symfony/issues/11604. + */ + public function testValidatePropertyValueWithoutConstraints() + { + $entity = new Entity(); + $violations = $this->validatePropertyValue($entity, 'lastName', 'foo'); + + $this->assertCount(0, $violations, '->validatePropertyValue() returns no violations if no constraints have been configured for the property being validated'); + } + + public function testValidateObjectOnlyOncePerGroup() + { + $entity = new Entity(); + $entity->reference = new Reference(); + $entity->reference2 = $entity->reference; + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->metadata->addPropertyConstraint('reference2', new Valid()); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testValidateDifferentObjectsSeparately() + { + $entity = new Entity(); + $entity->reference = new Reference(); + $entity->reference2 = new Reference(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->metadata->addPropertyConstraint('reference2', new Valid()); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(2, $violations); + } + + public function testValidateSingleGroup() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group 1', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group 2', + ])); + + $violations = $this->validate($entity, null, 'Group 2'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testValidateMultipleGroups() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group 1', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group 2', + ])); + + $violations = $this->validate($entity, null, ['Group 1', 'Group 2']); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(2, $violations); + } + + public function testReplaceDefaultGroupByGroupSequenceObject() + { + $entity = new Entity(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Group 2'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Group 3'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => function () {}, + 'groups' => 'Group 1', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group 2', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 3', + ])); + + $sequence = new GroupSequence(['Group 1', 'Group 2', 'Group 3', 'Entity']); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validate($entity, null, 'Default'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in Group 2', $violations[0]->getMessage()); + } + + public function testReplaceDefaultGroupByGroupSequenceArray() + { + $entity = new Entity(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Group 2'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Group 3'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => function () {}, + 'groups' => 'Group 1', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group 2', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 3', + ])); + + $sequence = ['Group 1', 'Group 2', 'Group 3', 'Entity']; + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validate($entity, null, 'Default'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in Group 2', $violations[0]->getMessage()); + } + + public function testPropagateDefaultGroupToReferenceWhenReplacingDefaultGroup() + { + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Default group'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in group sequence'); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Default', + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 1', + ])); + + $sequence = new GroupSequence(['Group 1', 'Entity']); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validate($entity, null, 'Default'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in Default group', $violations[0]->getMessage()); + } + + public function testValidateCustomGroupWhenDefaultGroupWasReplaced() + { + $entity = new Entity(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in other group'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in group sequence'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Other Group', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 1', + ])); + + $sequence = new GroupSequence(['Group 1', 'Entity']); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validate($entity, null, 'Other Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in other group', $violations[0]->getMessage()); + } + + /** + * @dataProvider getTestReplaceDefaultGroup + */ + public function testReplaceDefaultGroup($sequence, array $assertViolations) + { + $entity = new GroupSequenceProviderEntity($sequence); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Group 2'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Violation in Group 3'); + }; + + $metadata = new ClassMetadata(\get_class($entity)); + $metadata->addConstraint(new Callback([ + 'callback' => function () {}, + 'groups' => 'Group 1', + ])); + $metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group 2', + ])); + $metadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 3', + ])); + $metadata->setGroupSequenceProvider(true); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validate($entity, null, 'Default'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(\count($assertViolations), $violations); + foreach ($assertViolations as $key => $message) { + $this->assertSame($message, $violations[$key]->getMessage()); + } + } + + public function getConstraintMethods() + { + return [ + ['addPropertyConstraint'], + ['addGetterConstraint'], + ]; + } + + public function getTestReplaceDefaultGroup() + { + return [ + [ + 'sequence' => new GroupSequence(['Group 1', 'Group 2', 'Group 3', 'Entity']), + 'assertViolations' => [ + 'Violation in Group 2', + ], + ], + [ + 'sequence' => ['Group 1', 'Group 2', 'Group 3', 'Entity'], + 'assertViolations' => [ + 'Violation in Group 2', + ], + ], + [ + 'sequence' => new GroupSequence(['Group 1', ['Group 2', 'Group 3'], 'Entity']), + 'assertViolations' => [ + 'Violation in Group 2', + 'Violation in Group 3', + ], + ], + [ + 'sequence' => ['Group 1', ['Group 2', 'Group 3'], 'Entity'], + 'assertViolations' => [ + 'Violation in Group 2', + 'Violation in Group 3', + ], + ], + ]; + } + + public function testValidateConstraintWithoutGroup() + { + $violations = $this->validator->validate(null, new NotNull()); + + $this->assertCount(1, $violations); + } + + public function testValidateWithEmptyArrayAsConstraint() + { + $violations = $this->validator->validate('value', []); + $this->assertCount(0, $violations); + } + + public function testGroupSequenceAbortsAfterFailedGroup() + { + $entity = new Entity(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message 1'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message 2'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => function () {}, + 'groups' => 'Group 1', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group 2', + ])); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 3', + ])); + + $sequence = new GroupSequence(['Group 1', 'Group 2', 'Group 3']); + $violations = $this->validator->validate($entity, new Valid(), $sequence); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message 1', $violations[0]->getMessage()); + } + + public function testGroupSequenceIncludesReferences() + { + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Reference violation 1'); + }; + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Reference violation 2'); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group 1', + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group 2', + ])); + + $sequence = new GroupSequence(['Group 1', 'Entity']); + $violations = $this->validator->validate($entity, new Valid(), $sequence); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Reference violation 1', $violations[0]->getMessage()); + } + + public function testValidateInSeparateContext() + { + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback1 = function ($value, ExecutionContextInterface $context) use ($entity) { + $violations = $context + ->getValidator() + // Since the validator is not context aware, the group must + // be passed explicitly + ->validate($value->reference, new Valid(), 'Group') + ; + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + + // The root is different as we're in a new context + $this->assertSame($entity->reference, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + + // Verify that this method is called + $context->addViolation('Separate violation'); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity->reference, $context->getRoot()); + $this->assertSame($entity->reference, $context->getValue()); + $this->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group', + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group', + ])); + + $violations = $this->validator->validate($entity, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Separate violation', $violations[0]->getMessage()); + } + + public function testValidateInContext() + { + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $previousValue = $context->getValue(); + $previousObject = $context->getObject(); + $previousMetadata = $context->getMetadata(); + $previousPath = $context->getPropertyPath(); + $previousGroup = $context->getGroup(); + + $context + ->getValidator() + ->inContext($context) + ->atPath('subpath') + ->validate($value->reference) + ; + + // context changes shouldn't leak out of the validate() call + $this->assertSame($previousValue, $context->getValue()); + $this->assertSame($previousObject, $context->getObject()); + $this->assertSame($previousMetadata, $context->getMetadata()); + $this->assertSame($previousPath, $context->getPropertyPath()); + $this->assertSame($previousGroup, $context->getGroup()); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('subpath', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference, $context->getValue()); + $this->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group', + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group', + ])); + + $violations = $this->validator->validate($entity, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('subpath', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testValidateArrayInContext() + { + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback1 = function ($value, ExecutionContextInterface $context) { + $previousValue = $context->getValue(); + $previousObject = $context->getObject(); + $previousMetadata = $context->getMetadata(); + $previousPath = $context->getPropertyPath(); + $previousGroup = $context->getGroup(); + + $context + ->getValidator() + ->inContext($context) + ->atPath('subpath') + ->validate(['key' => $value->reference]) + ; + + // context changes shouldn't leak out of the validate() call + $this->assertSame($previousValue, $context->getValue()); + $this->assertSame($previousObject, $context->getObject()); + $this->assertSame($previousMetadata, $context->getMetadata()); + $this->assertSame($previousPath, $context->getPropertyPath()); + $this->assertSame($previousGroup, $context->getGroup()); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) use ($entity) { + $this->assertSame($this::REFERENCE_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('subpath[key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->referenceMetadata, $context->getMetadata()); + $this->assertSame($entity, $context->getRoot()); + $this->assertSame($entity->reference, $context->getValue()); + $this->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback1, + 'groups' => 'Group', + ])); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback2, + 'groups' => 'Group', + ])); + + $violations = $this->validator->validate($entity, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('subpath[key]', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testTraverseTraversableByDefault() + { + $entity = new Entity(); + $traversable = new \ArrayIterator(['key' => $entity]); + + $callback = function ($value, ExecutionContextInterface $context) use ($entity, $traversable) { + $this->assertSame($this::ENTITY_CLASS, $context->getClassName()); + $this->assertNull($context->getPropertyName()); + $this->assertSame('[key]', $context->getPropertyPath()); + $this->assertSame('Group', $context->getGroup()); + $this->assertSame($this->metadata, $context->getMetadata()); + $this->assertSame($traversable, $context->getRoot()); + $this->assertSame($entity, $context->getValue()); + $this->assertSame($entity, $value); + + $context->addViolation('Message %param%', ['%param%' => 'value']); + }; + + $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($traversable, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('[key]', $violations[0]->getPropertyPath()); + $this->assertSame($traversable, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getPlural()); + $this->assertNull($violations[0]->getCode()); + } + + public function testTraversalEnabledOnClass() + { + $entity = new Entity(); + $traversable = new \ArrayIterator(['key' => $entity]); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $traversableMetadata = new ClassMetadata('ArrayIterator'); + $traversableMetadata->addConstraint(new Traverse(true)); + + $this->metadataFactory->addMetadata($traversableMetadata); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($traversable, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testTraversalDisabledOnClass() + { + $entity = new Entity(); + $traversable = new \ArrayIterator(['key' => $entity]); + + $callback = function ($value, ExecutionContextInterface $context) { + $this->fail('Should not be called'); + }; + + $traversableMetadata = new ClassMetadata('ArrayIterator'); + $traversableMetadata->addConstraint(new Traverse(false)); + + $this->metadataFactory->addMetadata($traversableMetadata); + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + + $violations = $this->validate($traversable, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testExpectTraversableIfTraversalEnabledOnClass() + { + $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); + $entity = new Entity(); + + $this->metadata->addConstraint(new Traverse(true)); + + $this->validator->validate($entity); + } + + public function testReferenceTraversalDisabledOnClass() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(['key' => new Reference()]); + + $callback = function ($value, ExecutionContextInterface $context) { + $this->fail('Should not be called'); + }; + + $traversableMetadata = new ClassMetadata('ArrayIterator'); + $traversableMetadata->addConstraint(new Traverse(false)); + + $this->metadataFactory->addMetadata($traversableMetadata); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $violations = $this->validate($entity, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testReferenceTraversalEnabledOnReferenceDisabledOnClass() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(['key' => new Reference()]); + + $callback = function ($value, ExecutionContextInterface $context) { + $this->fail('Should not be called'); + }; + + $traversableMetadata = new ClassMetadata('ArrayIterator'); + $traversableMetadata->addConstraint(new Traverse(false)); + + $this->metadataFactory->addMetadata($traversableMetadata); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + $this->metadata->addPropertyConstraint('reference', new Valid([ + 'traverse' => true, + ])); + + $violations = $this->validate($entity, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testReferenceTraversalDisabledOnReferenceEnabledOnClass() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(['key' => new Reference()]); + + $callback = function ($value, ExecutionContextInterface $context) { + $this->fail('Should not be called'); + }; + + $traversableMetadata = new ClassMetadata('ArrayIterator'); + $traversableMetadata->addConstraint(new Traverse(true)); + + $this->metadataFactory->addMetadata($traversableMetadata); + $this->referenceMetadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => 'Group', + ])); + $this->metadata->addPropertyConstraint('reference', new Valid([ + 'traverse' => false, + ])); + + $violations = $this->validate($entity, new Valid(), 'Group'); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testAddCustomizedViolation() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->buildViolation('Message %param%') + ->setParameter('%param%', 'value') + ->setInvalidValue('Invalid value') + ->setPlural(2) + ->setCode('42') + ->addViolation(); + }; + + $this->metadata->addConstraint(new Callback($callback)); + + $violations = $this->validator->validate($entity); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(['%param%' => 'value'], $violations[0]->getParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Invalid value', $violations[0]->getInvalidValue()); + $this->assertSame(2, $violations[0]->getPlural()); + $this->assertSame('42', $violations[0]->getCode()); + } + + public function testNoDuplicateValidationIfClassConstraintInMultipleGroups() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addConstraint(new Callback([ + 'callback' => $callback, + 'groups' => ['Group 1', 'Group 2'], + ])); + + $violations = $this->validator->validate($entity, new Valid(), ['Group 1', 'Group 2']); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testNoDuplicateValidationIfPropertyConstraintInMultipleGroups() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback([ + 'callback' => $callback, + 'groups' => ['Group 1', 'Group 2'], + ])); + + $violations = $this->validator->validate($entity, new Valid(), ['Group 1', 'Group 2']); + + /* @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testValidateFailsIfNoConstraintsAndNoObjectOrArray() + { + $this->expectException('Symfony\Component\Validator\Exception\RuntimeException'); + $this->validate('Foobar'); + } + + public function testAccessCurrentObject() + { + $called = false; + $entity = new Entity(); + $entity->firstName = 'Bernhard'; + $entity->data = ['firstName' => 'Bernhard']; + + $callback = function ($value, ExecutionContextInterface $context) use ($entity, &$called) { + $called = true; + $this->assertSame($entity, $context->getObject()); + }; + + $this->metadata->addConstraint(new Callback($callback)); + $this->metadata->addPropertyConstraint('firstName', new Callback($callback)); + $this->metadata->addPropertyConstraint('data', new Collection(['firstName' => new Expression('value == this.firstName')])); + + $this->validator->validate($entity); + + $this->assertTrue($called); + } + + public function testInitializeObjectsOnFirstValidation() + { + $entity = new Entity(); + $entity->initialized = false; + + // prepare initializers that set "initialized" to true + $initializer1 = $this->getMockBuilder('Symfony\\Component\\Validator\\ObjectInitializerInterface')->getMock(); + $initializer2 = $this->getMockBuilder('Symfony\\Component\\Validator\\ObjectInitializerInterface')->getMock(); + + $initializer1->expects($this->once()) + ->method('initialize') + ->with($entity) + ->willReturnCallback(function ($object) { + $object->initialized = true; + }); + + $initializer2->expects($this->once()) + ->method('initialize') + ->with($entity); + + $this->validator = $this->createValidator($this->metadataFactory, [ + $initializer1, + $initializer2, + ]); + + // prepare constraint which + // * checks that "initialized" is set to true + // * validates the object again + $callback = function ($object, ExecutionContextInterface $context) { + $this->assertTrue($object->initialized); + + // validate again in same group + $validator = $context->getValidator()->inContext($context); + + $validator->validate($object); + + // validate again in other group + $validator->validate($object, null, 'SomeGroup'); + }; + + $this->metadata->addConstraint(new Callback($callback)); + + $this->validate($entity); + + $this->assertTrue($entity->initialized); + } + + public function testPassConstraintToViolation() + { + $constraint = new FailingConstraint(); + $violations = $this->validate('Foobar', $constraint); + + $this->assertCount(1, $violations); + $this->assertSame($constraint, $violations[0]->getConstraint()); + } + + public function testCollectionConstraitViolationHasCorrectContext() + { + $data = [ + 'foo' => 'fooValue', + ]; + + // Missing field must not be the first in the collection validation + $constraint = new Collection([ + 'foo' => new NotNull(), + 'bar' => new NotNull(), + ]); + + $violations = $this->validate($data, $constraint); + + $this->assertCount(1, $violations); + $this->assertSame($constraint, $violations[0]->getConstraint()); + } + + public function testNestedObjectIsNotValidatedIfGroupInValidConstraintIsNotValidated() + { + $entity = new Entity(); + $entity->firstName = ''; + $reference = new Reference(); + $reference->value = ''; + $entity->childA = $reference; + + $this->metadata->addPropertyConstraint('firstName', new NotBlank(['groups' => 'group1'])); + $this->metadata->addPropertyConstraint('childA', new Valid(['groups' => 'group1'])); + $this->referenceMetadata->addPropertyConstraint('value', new NotBlank()); + + $violations = $this->validator->validate($entity, null, []); + + $this->assertCount(0, $violations); + } + + public function testNestedObjectIsValidatedIfGroupInValidConstraintIsValidated() + { + $entity = new Entity(); + $entity->firstName = ''; + $reference = new Reference(); + $reference->value = ''; + $entity->childA = $reference; + + $this->metadata->addPropertyConstraint('firstName', new NotBlank(['groups' => 'group1'])); + $this->metadata->addPropertyConstraint('childA', new Valid(['groups' => 'group1'])); + $this->referenceMetadata->addPropertyConstraint('value', new NotBlank(['groups' => 'group1'])); + + $violations = $this->validator->validate($entity, null, ['Default', 'group1']); + + $this->assertCount(2, $violations); + } + + public function testNestedObjectIsValidatedInMultipleGroupsIfGroupInValidConstraintIsValidated() + { + $entity = new Entity(); + $entity->firstName = null; + + $reference = new Reference(); + $reference->value = null; + + $entity->childA = $reference; + + $this->metadata->addPropertyConstraint('firstName', new NotBlank()); + $this->metadata->addPropertyConstraint('childA', new Valid(['groups' => ['group1', 'group2']])); + + $this->referenceMetadata->addPropertyConstraint('value', new NotBlank(['groups' => 'group1'])); + $this->referenceMetadata->addPropertyConstraint('value', new NotNull(['groups' => 'group2'])); + + $violations = $this->validator->validate($entity, null, ['Default', 'group1', 'group2']); + + $this->assertCount(3, $violations); + } + protected function createValidator(MetadataFactoryInterface $metadataFactory, array $objectInitializers = []): ValidatorInterface { $translator = new IdentityTranslator(); From c5ec51abdf68eb4bc02b9a7e3167e4070ac02c32 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 1 Nov 2020 18:27:51 +0100 Subject: [PATCH 2/8] [Finder] Force set access time in test --- .../Component/Finder/Tests/Iterator/SortableIteratorTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php index 5a47812bd3..add8e7df59 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php @@ -35,9 +35,10 @@ class SortableIteratorTest extends RealIteratorTestCase case SortableIterator::SORT_BY_ACCESSED_TIME: touch(self::toAbsolute('.git')); sleep(1); - file_get_contents(self::toAbsolute('.bar')); + touch(self::toAbsolute('.bar'), time()); break; case SortableIterator::SORT_BY_CHANGED_TIME: + sleep(1); file_put_contents(self::toAbsolute('test.php'), 'foo'); sleep(1); file_put_contents(self::toAbsolute('test.py'), 'foo'); From 317f17a2f310617b28fb8264cca2b7ad659a1961 Mon Sep 17 00:00:00 2001 From: Farhad Safarov Date: Sun, 1 Nov 2020 22:40:44 +0300 Subject: [PATCH 3/8] [Validator] Add missing Azerbaijani translation --- .../Resources/translations/validators.az.xlf | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf index c3420f3db2..59480874fd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf @@ -366,6 +366,26 @@ This value should be between {{ min }} and {{ max }}. Bu dəyər {{ min }} və {{ max }} arasında olmaldır. + + This value is not a valid hostname. + Bu dəyər doğru bir host adı deyil. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Bu kolleksiyadakı elementlerin sayı {{ compared_value }} tam bölünəni olmalıdır. + + + This value should satisfy at least one of the following constraints: + Bu dəyər aşağıdakı məcburiyyətlərdən birini qarşılamalıdır: + + + Each element of this collection should satisfy its own set of constraints. + Bu kolleksiyadakı hər element öz məcburiyyətlərini qarşılamalıdır. + + + This value is not a valid International Securities Identification Number (ISIN). + Bu dəyər doğru bir Qiymətli Kağızın Beynəlxalq İdentifikasiya Kodu (ISIN) deyil. + From 665b25cd1e18788006096d810c646fcd0a2212f2 Mon Sep 17 00:00:00 2001 From: Farhad Safarov Date: Sun, 1 Nov 2020 22:52:07 +0300 Subject: [PATCH 4/8] [Security] Add missing Azerbaijani translations --- .../Security/Core/Resources/translations/security.az.xlf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.az.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.az.xlf index a974ed0f02..cf19aaefc4 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.az.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.az.xlf @@ -66,6 +66,14 @@ Account is locked. Hesab kilitlənib. + + Too many failed login attempts, please try again later. + Çoxlu uğursuz giriş təşəbbüsü, zəhmət olmasa daha sonra yeniden yoxlayın. + + + Invalid or expired login link. + Yanlış və ya müddəti keçmiş giriş keçidi. + From 833029ca7e342b36a2cc3c4d3c7fd480c0580a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 28 Oct 2020 18:54:43 +0100 Subject: [PATCH 5/8] Fix transiant tests in 4.4 --- .../Cache/Tests/Adapter/AdapterTestCase.php | 4 ++-- .../ServiceRouterLoaderTest.php | 2 +- .../SimpleAuthenticationHandlerTest.php | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 57c355eaa4..d7fe3ebc60 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -118,9 +118,9 @@ abstract class AdapterTestCase extends CachePoolTest $metadata = $item->getMetadata(); $this->assertArrayHasKey(CacheItem::METADATA_CTIME, $metadata); - $this->assertEqualsWithDelta(1000, $metadata[CacheItem::METADATA_CTIME], 6); + $this->assertEqualsWithDelta(999, $metadata[CacheItem::METADATA_CTIME], 10); $this->assertArrayHasKey(CacheItem::METADATA_EXPIRY, $metadata); - $this->assertEqualsWithDelta(9.5 + time(), $metadata[CacheItem::METADATA_EXPIRY], 0.6); + $this->assertEqualsWithDelta(9 + time(), $metadata[CacheItem::METADATA_EXPIRY], 1); } public function testDefaultLifeTime() diff --git a/src/Symfony/Component/Routing/Tests/Loader/DependencyInjection/ServiceRouterLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/DependencyInjection/ServiceRouterLoaderTest.php index 497ce2f3b3..925e59901e 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/DependencyInjection/ServiceRouterLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/DependencyInjection/ServiceRouterLoaderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Routing\Tests\Loader; +namespace Symfony\Component\Routing\Tests\Loader\DependencyInjection; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Container; diff --git a/src/Symfony/Component/Security/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php index 9fbdd67740..fa4c07e0b8 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Http\Tests; +namespace Symfony\Component\Security\Http\Tests\Authentication; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Response; @@ -69,7 +69,7 @@ class SimpleAuthenticationHandlerTest extends TestCase $this->successHandler->expects($this->never()) ->method('onAuthenticationSuccess'); - $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface'); + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\Authentication\TestSuccessHandlerInterface'); $authenticator->expects($this->once()) ->method('onAuthenticationSuccess') ->with($this->request, $this->token) @@ -88,7 +88,7 @@ class SimpleAuthenticationHandlerTest extends TestCase $this->successHandler->expects($this->never()) ->method('onAuthenticationSuccess'); - $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface'); + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\Authentication\TestSuccessHandlerInterface'); $authenticator->expects($this->once()) ->method('onAuthenticationSuccess') ->with($this->request, $this->token) @@ -105,7 +105,7 @@ class SimpleAuthenticationHandlerTest extends TestCase ->with($this->request, $this->token) ->willReturn($this->response); - $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface'); + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\Authentication\TestSuccessHandlerInterface'); $authenticator->expects($this->once()) ->method('onAuthenticationSuccess') ->with($this->request, $this->token) @@ -137,7 +137,7 @@ class SimpleAuthenticationHandlerTest extends TestCase $this->failureHandler->expects($this->never()) ->method('onAuthenticationFailure'); - $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface'); + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\Authentication\TestFailureHandlerInterface'); $authenticator->expects($this->once()) ->method('onAuthenticationFailure') ->with($this->request, $this->authenticationException) @@ -156,7 +156,7 @@ class SimpleAuthenticationHandlerTest extends TestCase $this->failureHandler->expects($this->never()) ->method('onAuthenticationFailure'); - $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface'); + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\Authentication\TestFailureHandlerInterface'); $authenticator->expects($this->once()) ->method('onAuthenticationFailure') ->with($this->request, $this->authenticationException) @@ -173,7 +173,7 @@ class SimpleAuthenticationHandlerTest extends TestCase ->with($this->request, $this->authenticationException) ->willReturn($this->response); - $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface'); + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\Authentication\TestFailureHandlerInterface'); $authenticator->expects($this->once()) ->method('onAuthenticationFailure') ->with($this->request, $this->authenticationException) From b39ff818ca0b9162c0c8f0c3a37e062db00abc14 Mon Sep 17 00:00:00 2001 From: hugovms <38090843+hugovms@users.noreply.github.com> Date: Sat, 31 Oct 2020 14:26:12 -0300 Subject: [PATCH 6/8] fix: updating translation issues --- .../Component/Form/Resources/translations/validators.pt.xlf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Form/Resources/translations/validators.pt.xlf index 554a810c68..0108a660e4 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.pt.xlf @@ -4,15 +4,15 @@ This form should not contain extra fields. - Este formulário não deveria conter campos extra. + Este formulário não deveria possuir mais campos. The uploaded file was too large. Please try to upload a smaller file. - O arquivo enviado é muito grande. Por favor, tente enviar um ficheiro mais pequeno. + O arquivo enviado é muito grande. Por favor, tente enviar um arquivo menor. The CSRF token is invalid. Please try to resubmit the form. - O token CSRF é inválido. Por favor submeta o formulário novamente. + O token CSRF está inválido. Por favor, tente enviar o formulário novamente. From 6efa4ed7770afcb916626ab119b68cb937578b9d Mon Sep 17 00:00:00 2001 From: Roger Guasch Date: Sun, 1 Nov 2020 21:54:44 +0100 Subject: [PATCH 7/8] Missing translations for Catalan (ca) --- .../Resources/translations/validators.ca.xlf | 120 ++++++++++++++++++ .../Resources/translations/security.ca.xlf | 8 ++ .../Resources/translations/validators.ca.xlf | 56 ++++++++ 3 files changed, 184 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf index 3a2fa484f8..6937960804 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. El token CSRF no és vàlid. Per favor, provi d'enviar novament el formulari. + + This value is not a valid HTML5 color. + Aquest valor no és un color HTML5 valid. + + + Please enter a valid birthdate. + Per favor introdueix una data d'aniversari valida. + + + The selected choice is invalid. + L'opció escollida és invalida. + + + The collection is invalid. + La col·lecció és invalida. + + + Please select a valid color. + Per favor selecciona un color vàlid. + + + Please select a valid country. + Per favor selecciona una ciutat vàlida. + + + Please select a valid currency. + Per favor selecciona una moneda vàlida. + + + Please choose a valid date interval. + Per favor escull un interval de dates vàlides. + + + Please enter a valid date and time. + Per favor introdueix una data i temps vàlid. + + + Please enter a valid date. + Per favor introdueix una data vàlida. + + + Please select a valid file. + Per favor selecciona un arxiu vàlid. + + + The hidden field is invalid. + El camp ocult és invàlid. + + + Please enter an integer. + Per favor introdueix un enter. + + + Please select a valid language. + Per favor selecciona un idioma vàlid. + + + Please select a valid locale. + Per favor seleccioneu una configuració regional vàlida + + + Please enter a valid money amount. + Per favor introdueix una quantitat de diners vàlids. + + + Please enter a number. + Per favor introdueix un número. + + + The password is invalid. + La contrasenya es invàlida. + + + Please enter a percentage value. + Per favor introdueix un valor percentual. + + + The values do not match. + Els valors no coincideixen. + + + Please enter a valid time. + Per favor introdueix un temps vàlid. + + + Please select a valid timezone. + Per favor selecciona una zona horària vàlida. + + + Please enter a valid URL. + Per favor introdueix una URL vàlida. + + + Please enter a valid search term. + Per favor introdueix un concepte de cerca vàlid. + + + Please provide a valid phone number. + Per favor introdueix un número de telèfon vàlid. + + + The checkbox has an invalid value. + La casella de selecció te un valor invàlid. + + + Please enter a valid email address. + Per favor introdueix un correu electrònic vàlid. + + + Please select a valid option. + Per favor selecciona una opció vàlida. + + + Please select a valid range. + Per favor selecciona un rang vàlid. + + + Please enter a valid week. + Per favor introdueix una setmana vàlida. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf index b009c6205c..5a8d0c7d84 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf @@ -62,6 +62,14 @@ Account is locked. El compte està bloquejat. + + Too many failed login attempts, please try again later. + Massa intents d'inici de sessió fallits, torneu-ho a provar més tard. + + + Invalid or expired login link. + Enllaç d'inici de sessió no vàlid o caducat. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index d6ae6e91bc..80e5364c1d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -330,6 +330,62 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Aquest Codi d'identificació bancari (BIC) no està associat amb l'IBAN {{ iban }}. + + This value should be valid JSON. + Aquest valor hauria de ser JSON vàlid. + + + This collection should contain only unique elements. + Aquesta col·lecció només hauria de contenir elements únics. + + + This value should be positive. + Aquest valor hauria de ser positiu. + + + This value should be either positive or zero. + Aquest valor ha de ser positiu o zero. + + + This value should be negative. + Aquest valor ha de ser negatiu. + + + This value should be either negative or zero. + Aquest valor ha de ser negatiu o zero. + + + This value is not a valid timezone. + Aquest valor no és una zona horària vàlida. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Aquesta contrasenya s'ha filtrat en cas de violació de dades, no s'ha d'utilitzar. Utilitzeu una altra contrasenya. + + + This value should be between {{ min }} and {{ max }}. + Aquest valor ha d'estar entre {{ min }} i {{ max }}. + + + This value is not a valid hostname. + Aquest valor no és un nom d'amfitrió vàlid. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + El nombre d'elements d'aquesta col·lecció ha de ser múltiple de {{compared_value}}. + + + This value should satisfy at least one of the following constraints: + Aquest valor ha de satisfer almenys una de les restriccions següents: + + + Each element of this collection should satisfy its own set of constraints. + Cada element d'aquesta col·lecció hauria de satisfer el seu propi conjunt de restriccions. + + + This value is not a valid International Securities Identification Number (ISIN). + Aquest valor no és un número d'identificació de valors internacionals (ISIN) vàlid. + From 142cfeed55ccb7c46efb63ee71c20176e61931a2 Mon Sep 17 00:00:00 2001 From: Farhad Safarov Date: Sun, 1 Nov 2020 23:22:25 +0300 Subject: [PATCH 8/8] [Form] Add missing Azerbaijani translation --- .../Resources/translations/validators.az.xlf | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.az.xlf b/src/Symfony/Component/Form/Resources/translations/validators.az.xlf index 69e447385a..b9269706db 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.az.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.az.xlf @@ -14,6 +14,126 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF nişanı yanlışdır. Lütfen formanı yenidən göndərin. + + This value is not a valid HTML5 color. + Bu dəyər doğru bir HTML5 rəngi deyil. + + + Please enter a valid birthdate. + Zəhmət olmasa doğru bir doğum günü daxil edin. + + + The selected choice is invalid. + Seçilmiş seçim doğru deyil. + + + The collection is invalid. + Kolleksiya doğru deyil. + + + Please select a valid color. + Zəhmət olmasa doğru bir rəng seçin. + + + Please select a valid country. + Zəhmət olmasa doğru bir ölkə seçin. + + + Please select a valid currency. + Zəhmət olmasa doğru bir valyuta seçin. + + + Please choose a valid date interval. + Zəhmət olmasa doğru bir tarix aralığı seçin. + + + Please enter a valid date and time. + Zəhmət olmasa doğru bir tarix ve saat daxil edin. + + + Please enter a valid date. + Zəhmət olmasa doğru bir tarix daxil edin. + + + Please select a valid file. + Zəhmət olmasa doğru bir fayl seçin. + + + The hidden field is invalid. + Gizli sahə doğru deyil. + + + Please enter an integer. + Zəhmət olmasa bir tam ədəd daxil edin. + + + Please select a valid language. + Zəhmət olmasa doğru bir dil seçin. + + + Please select a valid locale. + Zəhmət olmasa doğru bir yer seçin. + + + Please enter a valid money amount. + Zəhmət olmasa doğru bir pul miqdarı daxil edin. + + + Please enter a number. + Zəhmət olmasa doğru bir rəqəm daxil edin. + + + The password is invalid. + Parol doğru deyil. + + + Please enter a percentage value. + Zəhmət olmasa doğru bir faiz dəyəri daxil edin. + + + The values do not match. + Dəyərlər örtüşmür. + + + Please enter a valid time. + Zəhmət olmasa doğru bir saat daxil edin. + + + Please select a valid timezone. + Zəhmət olmasa doğru bir saat qurşağı seçin. + + + Please enter a valid URL. + Zəhmət olmasa doğru bir URL daxil edin. + + + Please enter a valid search term. + Zəhmət olmasa doğru bir axtarış termini daxil edin. + + + Please provide a valid phone number. + Zəhmət olmasa doğru bir telefon nömrəsi seçin. + + + The checkbox has an invalid value. + Seçim qutusunda doğru olmayan dəyər var. + + + Please enter a valid email address. + Zəhmət olmasa doğru bir e-poçt seçin. + + + Please select a valid option. + Zəhmət olmasa doğru bir variant seçin. + + + Please select a valid range. + Zəhmət olmasa doğru bir aralıq seçin. + + + Please enter a valid week. + Zəhmət olmasa doğru bir həftə seçin. +