diff --git a/UPGRADE-2.5.md b/UPGRADE-2.5.md index e3b581b5b9..6ce3e86af5 100644 --- a/UPGRADE-2.5.md +++ b/UPGRADE-2.5.md @@ -56,10 +56,11 @@ Validator After: - Default email validation is now done via a simple regex which may cause invalid emails (not RFC compilant) to be + Default email validation is now done via a simple regex which may cause invalid emails (not RFC compilant) to be valid. This is the default behaviour. Strict email validation has to be explicitly activated in the configuration file by adding + ``` framework: //... @@ -68,7 +69,29 @@ Validator //... ``` + Also you have to add to your composer.json: + ``` "egulias/email-validator": "1.1.*" ``` + + * `ClassMetadata::getGroupSequence()` now returns `GroupSequence` instances + instead of an array. The sequence implements `\Traversable`, `\ArrayAccess` + and `\Countable`, so in most cases you should be fine. If you however use the + sequence with PHP's `array_*()` functions, you should cast it to an array + first using `iterator_to_array()`: + + Before: + + ``` + $sequence = $metadata->getGroupSequence(); + $result = array_map($callback, $sequence); + ``` + + After: + + ``` + $sequence = iterator_to_array($metadata->getGroupSequence()); + $result = array_map($callback, $sequence); + ``` diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 3eba52930f..ecdf0cf366 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * deprecated `ApcCache` in favor of `DoctrineCache` * added `DoctrineCache` to adapt any Doctrine cache + * `GroupSequence` now implements `ArrayAccess`, `Countable` and `Traversable` + * changed `ClassMetadata::getGroupSequence()` to return a `GroupSequence` instance instead of an array 2.4.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Callback.php b/src/Symfony/Component/Validator/Constraints/Callback.php index 01aeb6ddb7..18cd7b3e92 100644 --- a/src/Symfony/Component/Validator/Constraints/Callback.php +++ b/src/Symfony/Component/Validator/Constraints/Callback.php @@ -71,6 +71,6 @@ class Callback extends Constraint */ public function getTargets() { - return self::CLASS_CONSTRAINT; + return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT); } } diff --git a/src/Symfony/Component/Validator/Constraints/GroupSequence.php b/src/Symfony/Component/Validator/Constraints/GroupSequence.php index 304fab8c94..61f72c6231 100644 --- a/src/Symfony/Component/Validator/Constraints/GroupSequence.php +++ b/src/Symfony/Component/Validator/Constraints/GroupSequence.php @@ -20,7 +20,7 @@ namespace Symfony\Component\Validator\Constraints; * * @api */ -class GroupSequence +class GroupSequence implements \ArrayAccess, \IteratorAggregate, \Countable { /** * The members of the sequence @@ -30,6 +30,43 @@ class GroupSequence public function __construct(array $groups) { - $this->groups = $groups['value']; + // Support for Doctrine annotations + $this->groups = isset($groups['value']) ? $groups['value'] : $groups; + } + + public function getIterator() + { + return new \ArrayIterator($this->groups); + } + + public function offsetExists($offset) + { + return isset($this->groups[$offset]); + } + + public function offsetGet($offset) + { + return $this->groups[$offset]; + } + + public function offsetSet($offset, $value) + { + if (null !== $offset) { + $this->groups[$offset] = $value; + + return; + } + + $this->groups[] = $value; + } + + public function offsetUnset($offset) + { + unset($this->groups[$offset]); + } + + public function count() + { + return count($this->groups); } } diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php index b7e003ec3d..8bba73a01f 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Validator\Mapping; +use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\ValidationVisitorInterface; use Symfony\Component\Validator\PropertyMetadataContainerInterface; use Symfony\Component\Validator\ClassBasedInterface; @@ -330,27 +331,31 @@ class ClassMetadata extends ElementMetadata implements MetadataInterface, ClassB /** * Sets the default group sequence for this class. * - * @param array $groups An array of group names + * @param array $groupSequence An array of group names * * @return ClassMetadata * * @throws GroupDefinitionException */ - public function setGroupSequence(array $groups) + public function setGroupSequence($groupSequence) { if ($this->isGroupSequenceProvider()) { throw new GroupDefinitionException('Defining a static group sequence is not allowed with a group sequence provider'); } - if (in_array(Constraint::DEFAULT_GROUP, $groups, true)) { + if (is_array($groupSequence)) { + $groupSequence = new GroupSequence($groupSequence); + } + + if (in_array(Constraint::DEFAULT_GROUP, $groupSequence->groups, true)) { throw new GroupDefinitionException(sprintf('The group "%s" is not allowed in group sequences', Constraint::DEFAULT_GROUP)); } - if (!in_array($this->getDefaultGroup(), $groups, true)) { + if (!in_array($this->getDefaultGroup(), $groupSequence->groups, true)) { throw new GroupDefinitionException(sprintf('The group "%s" is missing in the group sequence', $this->getDefaultGroup())); } - $this->groupSequence = $groups; + $this->groupSequence = $groupSequence; return $this; } @@ -368,7 +373,7 @@ class ClassMetadata extends ElementMetadata implements MetadataInterface, ClassB /** * Returns the default group sequence for this class. * - * @return array An array of group names + * @return GroupSequence The group sequence or null */ public function getGroupSequence() { diff --git a/src/Symfony/Component/Validator/Tests/AbstractValidatorTest.php b/src/Symfony/Component/Validator/Tests/AbstractValidatorTest.php new file mode 100644 index 0000000000..33e39c5345 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/AbstractValidatorTest.php @@ -0,0 +1,1236 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Constraints\GroupSequence; +use Symfony\Component\Validator\ConstraintViolationInterface; +use Symfony\Component\Validator\ExecutionContextInterface; +use Symfony\Component\Validator\MetadataFactoryInterface; +use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; +use Symfony\Component\Validator\Constraints\Valid; +use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity; +use Symfony\Component\Validator\Tests\Fixtures\Reference; +use Symfony\Component\Validator\ConstraintViolation; +use Symfony\Component\Validator\ConstraintViolationList; +use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; +use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Tests\Fixtures\ConstraintA; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\ValidatorInterface; + +/** + * @since 2.5 + * @author Bernhard Schussek + */ +abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase +{ + const ENTITY_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Entity'; + + const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference'; + + /** + * @var ValidatorInterface + */ + private $validator; + + /** + * @var FakeMetadataFactory + */ + public $metadataFactory; + + /** + * @var ClassMetadata + */ + public $metadata; + + /** + * @var ClassMetadata + */ + public $referenceMetadata; + + protected function setUp() + { + $this->metadataFactory = new FakeMetadataFactory(); + $this->validator = $this->createValidator($this->metadataFactory); + $this->metadata = new ClassMetadata(self::ENTITY_CLASS); + $this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS); + $this->metadataFactory->addMetadata($this->metadata); + $this->metadataFactory->addMetadata($this->referenceMetadata); + } + + protected function tearDown() + { + $this->metadataFactory = null; + $this->validator = null; + $this->metadata = null; + $this->referenceMetadata = null; + } + + abstract protected function createValidator(MetadataFactoryInterface $metadataFactory); + + public function testClassConstraint() + { + $test = $this; + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::ENTITY_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->metadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity, $context->getValue()); + $test->assertSame($entity, $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testPropertyConstraint() + { + $test = $this; + $entity = new Entity(); + $entity->firstName = 'Bernhard'; + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName'); + + $test->assertSame($test::ENTITY_CLASS, $context->getClassName()); + $test->assertSame('firstName', $context->getPropertyName()); + $test->assertSame('firstName', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($propertyMetadatas[0], $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame('Bernhard', $context->getValue()); + $test->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('firstName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testGetterConstraint() + { + $test = $this; + $entity = new Entity(); + $entity->setLastName('Schussek'); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $propertyMetadatas = $test->metadata->getPropertyMetadata('lastName'); + + $test->assertSame($test::ENTITY_CLASS, $context->getClassName()); + $test->assertSame('lastName', $context->getPropertyName()); + $test->assertSame('lastName', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($propertyMetadatas[0], $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame('Schussek', $context->getValue()); + $test->assertSame('Schussek', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addGetterConstraint('lastName', new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('lastName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Schussek', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testReferenceClassConstraint() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new Reference(); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('reference', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference, $context->getValue()); + $test->assertSame($entity->reference, $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('reference', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame($entity->reference, $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testReferencePropertyConstraint() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new Reference(); + $entity->reference->value = 'Foobar'; + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $propertyMetadatas = $test->referenceMetadata->getPropertyMetadata('value'); + + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertSame('value', $context->getPropertyName()); + $test->assertSame('reference.value', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($propertyMetadatas[0], $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame('Foobar', $context->getValue()); + $test->assertSame('Foobar', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addPropertyConstraint('value', new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('reference.value', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Foobar', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testReferenceGetterConstraint() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new Reference(); + $entity->reference->setPrivateValue('Bamboo'); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $propertyMetadatas = $test->referenceMetadata->getPropertyMetadata('privateValue'); + + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertSame('privateValue', $context->getPropertyName()); + $test->assertSame('reference.privateValue', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($propertyMetadatas[0], $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame('Bamboo', $context->getValue()); + $test->assertSame('Bamboo', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addPropertyConstraint('privateValue', new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('reference.privateValue', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bamboo', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testsIgnoreNullReference() + { + $entity = new Entity(); + $entity->reference = null; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException + */ + public function testFailOnScalarReferences() + { + $entity = new Entity(); + $entity->reference = 'string'; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $this->validator->validate($entity); + } + + public function testArrayReference() + { + $test = $this; + $entity = new Entity(); + $entity->reference = array('key' => new Reference()); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('reference[key]', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference['key'], $context->getValue()); + $test->assertSame($entity->reference['key'], $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $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]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + // https://github.com/symfony/symfony/issues/6246 + public function testRecursiveArrayReference() + { + $test = $this; + $entity = new Entity(); + $entity->reference = array(2 => array('key' => new Reference())); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('reference[2][key]', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference[2]['key'], $context->getValue()); + $test->assertSame($entity->reference[2]['key'], $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $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]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testArrayTraversalCannotBeDisabled() + { + $entity = new Entity(); + $entity->reference = array('key' => new Reference()); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid(array( + 'traverse' => false, + ))); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testRecursiveArrayTraversalCannotBeDisabled() + { + $entity = new Entity(); + $entity->reference = array(2 => array('key' => new Reference())); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid(array( + 'traverse' => false, + ))); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testIgnoreScalarsDuringArrayTraversal() + { + $entity = new Entity(); + $entity->reference = array('string', 1234); + + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testIgnoreNullDuringArrayTraversal() + { + $entity = new Entity(); + $entity->reference = array(null); + + $this->metadata->addPropertyConstraint('reference', new Valid()); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testTraversableReference() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new \ArrayIterator(array('key' => new Reference())); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('reference[key]', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference['key'], $context->getValue()); + $test->assertSame($entity->reference['key'], $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $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]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testDisableTraversableTraversal() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(array('key' => new Reference())); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); + $this->metadata->addPropertyConstraint('reference', new Valid(array( + 'traverse' => false, + ))); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException + */ + public function testMetadataMustExistIfTraversalIsDisabled() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(); + + $this->metadata->addPropertyConstraint('reference', new Valid(array( + 'traverse' => false, + ))); + + $this->validator->validate($entity, 'Default', ''); + } + + public function testNoRecursiveTraversableTraversal() + { + $entity = new Entity(); + $entity->reference = new \ArrayIterator(array( + 2 => new \ArrayIterator(array('key' => new Reference())), + )); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); + $this->metadata->addPropertyConstraint('reference', new Valid()); + $this->referenceMetadata->addConstraint(new Callback($callback)); + + $violations = $this->validator->validate($entity); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(0, $violations); + } + + public function testEnableRecursiveTraversableTraversal() + { + $test = $this; + $entity = new Entity(); + $entity->reference = new \ArrayIterator(array( + 2 => new \ArrayIterator(array('key' => new Reference())), + )); + + $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $test->assertSame($test::REFERENCE_CLASS, $context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('reference[2][key]', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($test->referenceMetadata, $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame($entity->reference[2]['key'], $context->getValue()); + $test->assertSame($entity->reference[2]['key'], $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $this->metadata->addPropertyConstraint('reference', new Valid(array( + 'deep' => true, + ))); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + ))); + + $violations = $this->validator->validate($entity, 'Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message value', $violations[0]->getMessage()); + $this->assertSame('Message %param%', $violations[0]->getMessageTemplate()); + $this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $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]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + public function testValidateProperty() + { + $test = $this; + $entity = new Entity(); + $entity->firstName = 'Bernhard'; + $entity->setLastName('Schussek'); + + $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName'); + + $test->assertSame($test::ENTITY_CLASS, $context->getClassName()); + $test->assertSame('firstName', $context->getPropertyName()); + $test->assertSame('firstName', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($propertyMetadatas[0], $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame('Bernhard', $context->getValue()); + $test->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Other violation'); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group', + ))); + $this->metadata->addPropertyConstraint('lastName', new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group', + ))); + + $violations = $this->validator->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(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('firstName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ValidatorException + */ + public function testValidatePropertyFailsIfPropertiesNotSupported() + { + // $metadata does not implement PropertyMetadataContainerInterface + $metadata = $this->getMock('Symfony\Component\Validator\MetadataInterface'); + + $metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface'); + $metadataFactory->expects($this->any()) + ->method('getMetadataFor') + ->with('VALUE') + ->will($this->returnValue($metadata)); + $validator = $this->createValidator($metadataFactory); + + $validator->validateProperty('VALUE', 'someProperty'); + } + + public function testValidatePropertyValue() + { + $test = $this; + $entity = new Entity(); + $entity->setLastName('Schussek'); + + $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { + $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName'); + + $test->assertSame($test::ENTITY_CLASS, $context->getClassName()); + $test->assertSame('firstName', $context->getPropertyName()); + $test->assertSame('firstName', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertSame($propertyMetadatas[0], $context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame($entity, $context->getRoot()); + $test->assertSame('Bernhard', $context->getValue()); + $test->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $callback2 = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Other violation'); + }; + + $this->metadata->addPropertyConstraint('firstName', new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group', + ))); + $this->metadata->addPropertyConstraint('lastName', new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group', + ))); + + $violations = $this->validator->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(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('firstName', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ValidatorException + */ + public function testValidatePropertyValueFailsIfPropertiesNotSupported() + { + // $metadata does not implement PropertyMetadataContainerInterface + $metadata = $this->getMock('Symfony\Component\Validator\MetadataInterface'); + + $metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface'); + $metadataFactory->expects($this->any()) + ->method('getMetadataFor') + ->with('VALUE') + ->will($this->returnValue($metadata)); + $validator = $this->createValidator($metadataFactory); + + $validator->validatePropertyValue('VALUE', 'someProperty', 'someValue'); + } + + public function testValidateValue() + { + $test = $this; + + $callback = function ($value, ExecutionContextInterface $context) use ($test) { + $test->assertNull($context->getClassName()); + $test->assertNull($context->getPropertyName()); + $test->assertSame('', $context->getPropertyPath()); + $test->assertSame('Group', $context->getGroup()); + $test->assertNull($context->getMetadata()); + $test->assertSame($test->metadataFactory, $context->getMetadataFactory()); + $test->assertSame('Bernhard', $context->getRoot()); + $test->assertSame('Bernhard', $context->getValue()); + $test->assertSame('Bernhard', $value); + + $context->addViolation('Message %param%', array('%param%' => 'value')); + }; + + $constraint = new Callback(array( + 'callback' => $callback, + 'groups' => 'Group', + )); + + $violations = $this->validator->validateValue('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(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame('Bernhard', $violations[0]->getRoot()); + $this->assertSame('Bernhard', $violations[0]->getInvalidValue()); + $this->assertNull($violations[0]->getMessagePluralization()); + $this->assertNull($violations[0]->getCode()); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ValidatorException + */ + public function testValidateValueRejectsValid() + { + $this->validator->validateValue(new Entity(), new Valid()); + } + + public function testAddCustomizedViolation() + { + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation( + 'Message %param%', + array('%param%' => 'value'), + 'Invalid value', + 2, + 'Code' + ); + }; + + $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(array('%param%' => 'value'), $violations[0]->getMessageParameters()); + $this->assertSame('', $violations[0]->getPropertyPath()); + $this->assertSame($entity, $violations[0]->getRoot()); + $this->assertSame('Invalid value', $violations[0]->getInvalidValue()); + $this->assertSame(2, $violations[0]->getMessagePluralization()); + $this->assertSame('Code', $violations[0]->getCode()); + } + + 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->validator->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->validator->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(array( + 'callback' => $callback, + 'groups' => 'Group 1', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group 2', + ))); + + $violations = $this->validator->validate($entity, '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(array( + 'callback' => $callback, + 'groups' => 'Group 1', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => 'Group 2', + ))); + + $violations = $this->validator->validate($entity, array('Group 1', 'Group 2')); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(2, $violations); + } + + public function testNoDuplicateValidationIfConstraintInMultipleGroups() + { + $this->markTestSkipped('Currently not supported'); + + $entity = new Entity(); + + $callback = function ($value, ExecutionContextInterface $context) { + $context->addViolation('Message'); + }; + + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback, + 'groups' => array('Group 1', 'Group 2'), + ))); + + $violations = $this->validator->validate($entity, array('Group 1', 'Group 2')); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + } + + public function testGroupSequenceAbortsAfterFailedGroup() + { + $this->markTestSkipped('Currently not supported'); + + $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(array( + 'callback' => function () {}, + 'groups' => 'Group 1', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group 2', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 3', + ))); + + $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3')); + $violations = $this->validator->validate($entity, $sequence); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Message 1', $violations[0]->getMessage()); + } + + public function testGroupSequenceIncludesReferences() + { + $this->markTestSkipped('Currently not supported'); + + $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(array( + 'callback' => $callback1, + 'groups' => 'Group 1', + ))); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 2', + ))); + + $sequence = new GroupSequence(array('Group 1', 'Entity')); + $violations = $this->validator->validate($entity, $sequence); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Reference violation 1', $violations[0]->getMessage()); + } + + 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(array( + 'callback' => function () {}, + 'groups' => 'Group 1', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group 2', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 3', + ))); + + $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3', 'Entity')); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validator->validate($entity, '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(array( + 'callback' => function () {}, + 'groups' => 'Group 1', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group 2', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 3', + ))); + + $sequence = array('Group 1', 'Group 2', 'Group 3', 'Entity'); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validator->validate($entity, '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(array( + 'callback' => $callback1, + 'groups' => 'Default', + ))); + $this->referenceMetadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 1', + ))); + + $sequence = new GroupSequence(array('Group 1', 'Entity')); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validator->validate($entity, '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(array( + 'callback' => $callback1, + 'groups' => 'Other Group', + ))); + $this->metadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 1', + ))); + + $sequence = new GroupSequence(array('Group 1', 'Entity')); + $this->metadata->setGroupSequence($sequence); + + $violations = $this->validator->validate($entity, 'Other Group'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in other group', $violations[0]->getMessage()); + } + + public function testReplaceDefaultGroupWithObjectFromGroupSequenceProvider() + { + $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3', 'Entity')); + $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(array( + 'callback' => function () {}, + 'groups' => 'Group 1', + ))); + $metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group 2', + ))); + $metadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 3', + ))); + $metadata->setGroupSequenceProvider(true); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validator->validate($entity, 'Default'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in Group 2', $violations[0]->getMessage()); + } + + public function testReplaceDefaultGroupWithArrayFromGroupSequenceProvider() + { + $sequence = array('Group 1', 'Group 2', 'Group 3', 'Entity'); + $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(array( + 'callback' => function () {}, + 'groups' => 'Group 1', + ))); + $metadata->addConstraint(new Callback(array( + 'callback' => $callback1, + 'groups' => 'Group 2', + ))); + $metadata->addConstraint(new Callback(array( + 'callback' => $callback2, + 'groups' => 'Group 3', + ))); + $metadata->setGroupSequenceProvider(true); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validator->validate($entity, 'Default'); + + /** @var ConstraintViolationInterface[] $violations */ + $this->assertCount(1, $violations); + $this->assertSame('Violation in Group 2', $violations[0]->getMessage()); + } + + public function testGetMetadataFactory() + { + $this->assertSame($this->metadataFactory, $this->validator->getMetadataFactory()); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php index cdcd49bb58..e0317823d5 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Validator\Tests\Constraints; +use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ExecutionContext; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\CallbackValidator; @@ -320,8 +321,9 @@ class CallbackValidatorTest extends \PHPUnit_Framework_TestCase public function testConstraintGetTargets() { $constraint = new Callback(array('foo')); + $targets = array(Constraint::CLASS_CONSTRAINT, Constraint::PROPERTY_CONSTRAINT); - $this->assertEquals('class', $constraint->getTargets()); + $this->assertEquals($targets, $constraint->getTargets()); } // Should succeed. Needed when defining constraints as annotations. diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php new file mode 100644 index 0000000000..83275d1c72 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\GroupSequence; + +/** + * @author Bernhard Schussek + */ +class GroupSequenceTest extends \PHPUnit_Framework_TestCase +{ + public function testCreate() + { + $sequence = new GroupSequence(array('Group 1', 'Group 2')); + + $this->assertSame(array('Group 1', 'Group 2'), $sequence->groups); + } + + public function testCreateDoctrineStyle() + { + $sequence = new GroupSequence(array('value' => array('Group 1', 'Group 2'))); + + $this->assertSame(array('Group 1', 'Group 2'), $sequence->groups); + } + + public function testIterate() + { + $sequence = new GroupSequence(array('Group 1', 'Group 2')); + + $this->assertSame(array('Group 1', 'Group 2'), iterator_to_array($sequence)); + } + + public function testCount() + { + $sequence = new GroupSequence(array('Group 1', 'Group 2')); + + $this->assertCount(2, $sequence); + } + + public function testArrayAccess() + { + $sequence = new GroupSequence(array('Group 1', 'Group 2')); + + $this->assertSame('Group 1', $sequence[0]); + $this->assertSame('Group 2', $sequence[1]); + $this->assertTrue(isset($sequence[0])); + $this->assertFalse(isset($sequence[2])); + unset($sequence[0]); + $this->assertFalse(isset($sequence[0])); + $sequence[] = 'Group 3'; + $this->assertTrue(isset($sequence[2])); + $this->assertSame('Group 3', $sequence[2]); + $sequence[0] = 'Group 1'; + $this->assertTrue(isset($sequence[0])); + $this->assertSame('Group 1', $sequence[0]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php b/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php index fbd879a94e..d841f5dc9d 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php @@ -32,9 +32,10 @@ class Entity extends EntityParent implements EntityInterface * }) * @Assert\Choice(choices={"A", "B"}, message="Must be one of %choices%") */ - protected $firstName; + public $firstName; protected $lastName; public $reference; + public $reference2; private $internal; public $data = 'Overridden data'; @@ -48,6 +49,11 @@ class Entity extends EntityParent implements EntityInterface return $this->internal.' from getter'; } + public function setLastName($lastName) + { + $this->lastName = $lastName; + } + /** * @Assert\NotNull */ diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderEntity.php b/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderEntity.php index ef3711104a..2b0beaf9ad 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderEntity.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderEntity.php @@ -22,15 +22,15 @@ class GroupSequenceProviderEntity implements GroupSequenceProviderInterface public $firstName; public $lastName; - protected $groups = array(); + protected $sequence = array(); - public function setGroups($groups) + public function __construct($sequence) { - $this->groups = $groups; + $this->sequence = $sequence; } public function getGroupSequence() { - return $this->groups; + return $this->sequence; } } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/Reference.php b/src/Symfony/Component/Validator/Tests/Fixtures/Reference.php index f8ea173e01..af29735924 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/Reference.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/Reference.php @@ -13,4 +13,17 @@ namespace Symfony\Component\Validator\Tests\Fixtures; class Reference { + public $value; + + private $privateValue; + + public function setPrivateValue($privateValue) + { + $this->privateValue = $privateValue; + } + + public function getPrivateValue() + { + return $this->privateValue; + } } diff --git a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php deleted file mode 100644 index 2868f57a82..0000000000 --- a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php +++ /dev/null @@ -1,564 +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; - -use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; -use Symfony\Component\Validator\Constraints\Valid; -use Symfony\Component\Validator\Tests\Fixtures\Reference; -use Symfony\Component\Validator\DefaultTranslator; -use Symfony\Component\Validator\ConstraintViolation; -use Symfony\Component\Validator\ConstraintViolationList; -use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; -use Symfony\Component\Validator\Tests\Fixtures\ConstraintAValidator; -use Symfony\Component\Validator\Tests\Fixtures\Entity; -use Symfony\Component\Validator\Tests\Fixtures\ConstraintA; -use Symfony\Component\Validator\Mapping\ClassMetadata; -use Symfony\Component\Validator\ConstraintValidatorFactory; -use Symfony\Component\Validator\ValidationVisitor; - -/** - * @author Bernhard Schussek - */ -class ValidationVisitorTest extends \PHPUnit_Framework_TestCase -{ - const CLASS_NAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity'; - - /** - * @var ValidationVisitor - */ - private $visitor; - - /** - * @var FakeMetadataFactory - */ - private $metadataFactory; - - /** - * @var ClassMetadata - */ - private $metadata; - - protected function setUp() - { - $this->metadataFactory = new FakeMetadataFactory(); - $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); - $this->metadata = new ClassMetadata(self::CLASS_NAME); - $this->metadataFactory->addMetadata($this->metadata); - } - - protected function tearDown() - { - $this->metadataFactory = null; - $this->visitor = null; - $this->metadata = null; - } - - public function testValidatePassesCorrectClassAndProperty() - { - $this->metadata->addConstraint(new ConstraintA()); - - $entity = new Entity(); - $this->visitor->validate($entity, 'Default', ''); - - $context = ConstraintAValidator::$passedContext; - - $this->assertEquals('Symfony\Component\Validator\Tests\Fixtures\Entity', $context->getClassName()); - $this->assertNull($context->getPropertyName()); - } - - public function testValidateConstraints() - { - $this->metadata->addConstraint(new ConstraintA()); - - $this->visitor->validate(new Entity(), 'Default', ''); - - $this->assertCount(1, $this->visitor->getViolations()); - } - - public function testValidateTwiceValidatesConstraintsOnce() - { - $this->metadata->addConstraint(new ConstraintA()); - - $entity = new Entity(); - - $this->visitor->validate($entity, 'Default', ''); - $this->visitor->validate($entity, 'Default', ''); - - $this->assertCount(1, $this->visitor->getViolations()); - } - - public function testValidateDifferentObjectsValidatesTwice() - { - $this->metadata->addConstraint(new ConstraintA()); - - $this->visitor->validate(new Entity(), 'Default', ''); - $this->visitor->validate(new Entity(), 'Default', ''); - - $this->assertCount(2, $this->visitor->getViolations()); - } - - public function testValidateTwiceInDifferentGroupsValidatesTwice() - { - $this->metadata->addConstraint(new ConstraintA()); - $this->metadata->addConstraint(new ConstraintA(array('groups' => 'Custom'))); - - $entity = new Entity(); - - $this->visitor->validate($entity, 'Default', ''); - $this->visitor->validate($entity, 'Custom', ''); - - $this->assertCount(2, $this->visitor->getViolations()); - } - - public function testValidatePropertyConstraints() - { - $this->metadata->addPropertyConstraint('firstName', new ConstraintA()); - - $this->visitor->validate(new Entity(), 'Default', ''); - - $this->assertCount(1, $this->visitor->getViolations()); - } - - public function testValidateGetterConstraints() - { - $this->metadata->addGetterConstraint('lastName', new ConstraintA()); - - $this->visitor->validate(new Entity(), 'Default', ''); - - $this->assertCount(1, $this->visitor->getViolations()); - } - - public function testValidateInDefaultGroupTraversesGroupSequence() - { - $entity = new Entity(); - - $this->metadata->addPropertyConstraint('firstName', new FailingConstraint(array( - 'groups' => 'First', - ))); - $this->metadata->addGetterConstraint('lastName', new FailingConstraint(array( - 'groups' => 'Default', - ))); - $this->metadata->setGroupSequence(array('First', $this->metadata->getDefaultGroup())); - - $this->visitor->validate($entity, 'Default', ''); - - // After validation of group "First" failed, no more group was - // validated - $violations = new ConstraintViolationList(array( - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'firstName', - '' - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateInGroupSequencePropagatesDefaultGroup() - { - $entity = new Entity(); - $entity->reference = new Reference(); - - $this->metadata->addPropertyConstraint('reference', new Valid()); - $this->metadata->setGroupSequence(array($this->metadata->getDefaultGroup())); - - $referenceMetadata = new ClassMetadata(get_class($entity->reference)); - $referenceMetadata->addConstraint(new FailingConstraint(array( - // this constraint is only evaluated if group "Default" is - // propagated to the reference - 'groups' => 'Default', - ))); - $this->metadataFactory->addMetadata($referenceMetadata); - - $this->visitor->validate($entity, 'Default', ''); - - // The validation of the reference's FailingConstraint in group - // "Default" was launched - $violations = new ConstraintViolationList(array( - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'reference', - $entity->reference - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateInOtherGroupTraversesNoGroupSequence() - { - $entity = new Entity(); - - $this->metadata->addPropertyConstraint('firstName', new FailingConstraint(array( - 'groups' => 'First', - ))); - $this->metadata->addGetterConstraint('lastName', new FailingConstraint(array( - 'groups' => $this->metadata->getDefaultGroup(), - ))); - $this->metadata->setGroupSequence(array('First', $this->metadata->getDefaultGroup())); - - $this->visitor->validate($entity, $this->metadata->getDefaultGroup(), ''); - - // Only group "Second" was validated - $violations = new ConstraintViolationList(array( - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'lastName', - '' - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyValidatesReferences() - { - $entity = new Entity(); - $entity->reference = new Entity(); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate entity when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid()); - - // invoke validation on an object - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // generated by the reference - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'reference', - $entity->reference - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyValidatesArraysByDefault() - { - $entity = new Entity(); - $entity->reference = array('key' => new Entity()); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate array when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // generated by the reference - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'reference[key]', - $entity->reference['key'] - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyValidatesTraversableByDefault() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(array('key' => new Entity())); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate array when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // generated by the reference - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'reference[key]', - $entity->reference['key'] - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyDoesNotValidateTraversableIfDisabled() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(array('key' => new Entity())); - - $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate array when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid(array( - 'traverse' => false, - ))); - - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // nothing generated by the reference! - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testMetadataMayNotExistIfTraversalIsEnabled() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(); - - $this->metadata->addPropertyConstraint('reference', new Valid(array( - 'traverse' => true, - ))); - - $this->visitor->validate($entity, 'Default', ''); - } - - /** - * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException - */ - public function testMetadataMustExistIfTraversalIsDisabled() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(); - - $this->metadata->addPropertyConstraint('reference', new Valid(array( - 'traverse' => false, - ))); - - $this->visitor->validate($entity, 'Default', ''); - } - - public function testValidateCascadedPropertyDoesNotRecurseByDefault() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(array( - // The inner iterator should not be traversed by default - 'key' => new \ArrayIterator(array( - 'nested' => new Entity(), - )), - )); - - $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator')); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate iterator when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // nothing generated by the reference! - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - // https://github.com/symfony/symfony/issues/6246 - public function testValidateCascadedPropertyRecursesArraysByDefault() - { - $entity = new Entity(); - $entity->reference = array( - 'key' => array( - 'nested' => new Entity(), - ), - ); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate iterator when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // nothing generated by the reference! - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'reference[key][nested]', - $entity->reference['key']['nested'] - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyRecursesIfDeepIsSet() - { - $entity = new Entity(); - $entity->reference = new \ArrayIterator(array( - // The inner iterator should now be traversed - 'key' => new \ArrayIterator(array( - 'nested' => new Entity(), - )), - )); - - // add a constraint for the entity that always fails - $this->metadata->addConstraint(new FailingConstraint()); - - // validate iterator when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid(array( - 'deep' => true, - ))); - - $this->visitor->validate($entity, 'Default', ''); - - $violations = new ConstraintViolationList(array( - // generated by the root object - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - '', - $entity - ), - // nothing generated by the reference! - new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Root', - 'reference[key][nested]', - $entity->reference['key']['nested'] - ), - )); - - $this->assertEquals($violations, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyDoesNotValidateNestedScalarValues() - { - $entity = new Entity(); - $entity->reference = array('scalar', 'values'); - - // validate array when validating the property "reference" - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - - $this->assertCount(0, $this->visitor->getViolations()); - } - - public function testValidateCascadedPropertyDoesNotValidateNullValues() - { - $entity = new Entity(); - $entity->reference = null; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - - $this->assertCount(0, $this->visitor->getViolations()); - } - - /** - * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException - */ - public function testValidateCascadedPropertyRequiresObjectOrArray() - { - $entity = new Entity(); - $entity->reference = 'no object'; - - $this->metadata->addPropertyConstraint('reference', new Valid()); - - $this->visitor->validate($entity, 'Default', ''); - } -} diff --git a/src/Symfony/Component/Validator/Tests/ValidatorTest.php b/src/Symfony/Component/Validator/Tests/ValidatorTest.php index 85a61e4816..52bdbea519 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorTest.php @@ -11,266 +11,15 @@ namespace Symfony\Component\Validator\Tests; -use Symfony\Component\Validator\Tests\Fixtures\Entity; -use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity; -use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; -use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; +use Symfony\Component\Validator\MetadataFactoryInterface; use Symfony\Component\Validator\Validator; use Symfony\Component\Validator\DefaultTranslator; -use Symfony\Component\Validator\ConstraintViolation; -use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\ConstraintValidatorFactory; -use Symfony\Component\Validator\Constraints\Valid; -use Symfony\Component\Validator\Mapping\ClassMetadata; -class ValidatorTest extends \PHPUnit_Framework_TestCase +class ValidatorTest extends AbstractValidatorTest { - /** - * @var FakeMetadataFactory - */ - private $metadataFactory; - - /** - * @var Validator - */ - private $validator; - - protected function setUp() + protected function createValidator(MetadataFactoryInterface $metadataFactory) { - $this->metadataFactory = new FakeMetadataFactory(); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); - } - - protected function tearDown() - { - $this->metadataFactory = null; - $this->validator = null; - } - - public function testValidateDefaultGroup() - { - $entity = new Entity(); - $metadata = new ClassMetadata(get_class($entity)); - $metadata->addPropertyConstraint('firstName', new FailingConstraint()); - $metadata->addPropertyConstraint('lastName', new FailingConstraint(array( - 'groups' => 'Custom', - ))); - $this->metadataFactory->addMetadata($metadata); - - // Only the constraint of group "Default" failed - $violations = new ConstraintViolationList(); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - $entity, - 'firstName', - '' - )); - - $this->assertEquals($violations, $this->validator->validate($entity)); - } - - public function testValidateOneGroup() - { - $entity = new Entity(); - $metadata = new ClassMetadata(get_class($entity)); - $metadata->addPropertyConstraint('firstName', new FailingConstraint()); - $metadata->addPropertyConstraint('lastName', new FailingConstraint(array( - 'groups' => 'Custom', - ))); - $this->metadataFactory->addMetadata($metadata); - - // Only the constraint of group "Custom" failed - $violations = new ConstraintViolationList(); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - $entity, - 'lastName', - '' - )); - - $this->assertEquals($violations, $this->validator->validate($entity, 'Custom')); - } - - public function testValidateMultipleGroups() - { - $entity = new Entity(); - $metadata = new ClassMetadata(get_class($entity)); - $metadata->addPropertyConstraint('firstName', new FailingConstraint(array( - 'groups' => 'First', - ))); - $metadata->addPropertyConstraint('lastName', new FailingConstraint(array( - 'groups' => 'Second', - ))); - $this->metadataFactory->addMetadata($metadata); - - // The constraints of both groups failed - $violations = new ConstraintViolationList(); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - $entity, - 'firstName', - '' - )); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - $entity, - 'lastName', - '' - )); - - $result = $this->validator->validate($entity, array('First', 'Second')); - - $this->assertEquals($violations, $result); - } - - public function testValidateGroupSequenceProvider() - { - $entity = new GroupSequenceProviderEntity(); - $metadata = new ClassMetadata(get_class($entity)); - $metadata->addPropertyConstraint('firstName', new FailingConstraint(array( - 'groups' => 'First', - ))); - $metadata->addPropertyConstraint('lastName', new FailingConstraint(array( - 'groups' => 'Second', - ))); - $metadata->setGroupSequenceProvider(true); - $this->metadataFactory->addMetadata($metadata); - - $violations = new ConstraintViolationList(); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - $entity, - 'firstName', - '' - )); - - $entity->setGroups(array('First')); - $result = $this->validator->validate($entity); - $this->assertEquals($violations, $result); - - $violations = new ConstraintViolationList(); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - $entity, - 'lastName', - '' - )); - - $entity->setGroups(array('Second')); - $result = $this->validator->validate($entity); - $this->assertEquals($violations, $result); - - $entity->setGroups(array()); - $result = $this->validator->validate($entity); - $this->assertEquals(new ConstraintViolationList(), $result); - } - - public function testValidateProperty() - { - $entity = new Entity(); - $metadata = new ClassMetadata(get_class($entity)); - $metadata->addPropertyConstraint('firstName', new FailingConstraint()); - $this->metadataFactory->addMetadata($metadata); - - $result = $this->validator->validateProperty($entity, 'firstName'); - - $this->assertCount(1, $result); - - $result = $this->validator->validateProperty($entity, 'lastName'); - - $this->assertCount(0, $result); - } - - public function testValidatePropertyValue() - { - $entity = new Entity(); - $metadata = new ClassMetadata(get_class($entity)); - $metadata->addPropertyConstraint('firstName', new FailingConstraint()); - $this->metadataFactory->addMetadata($metadata); - - $result = $this->validator->validatePropertyValue(get_class($entity), 'firstName', 'Bernhard'); - - $this->assertCount(1, $result); - } - - public function testValidateValue() - { - $violations = new ConstraintViolationList(); - $violations->add(new ConstraintViolation( - 'Failed', - 'Failed', - array(), - 'Bernhard', - '', - 'Bernhard' - )); - - $this->assertEquals($violations, $this->validator->validateValue('Bernhard', new FailingConstraint())); - } - - /** - * @expectedException \Symfony\Component\Validator\Exception\ValidatorException - */ - public function testValidateValueRejectsValid() - { - $entity = new Entity(); - $metadata = new ClassMetadata(get_class($entity)); - $this->metadataFactory->addMetadata($metadata); - - $this->validator->validateValue($entity, new Valid()); - } - - /** - * @expectedException \Symfony\Component\Validator\Exception\ValidatorException - */ - public function testValidatePropertyFailsIfPropertiesNotSupported() - { - // $metadata does not implement PropertyMetadataContainerInterface - $metadata = $this->getMock('Symfony\Component\Validator\MetadataInterface'); - $this->metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface'); - $this->metadataFactory->expects($this->any()) - ->method('getMetadataFor') - ->with('VALUE') - ->will($this->returnValue($metadata)); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); - - $this->validator->validateProperty('VALUE', 'someProperty'); - } - - /** - * @expectedException \Symfony\Component\Validator\Exception\ValidatorException - */ - public function testValidatePropertyValueFailsIfPropertiesNotSupported() - { - // $metadata does not implement PropertyMetadataContainerInterface - $metadata = $this->getMock('Symfony\Component\Validator\MetadataInterface'); - $this->metadataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface'); - $this->metadataFactory->expects($this->any()) - ->method('getMetadataFor') - ->with('VALUE') - ->will($this->returnValue($metadata)); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); - - $this->validator->validatePropertyValue('VALUE', 'someProperty', 'propertyValue'); - } - - public function testGetMetadataFactory() - { - $this->assertInstanceOf( - 'Symfony\Component\Validator\MetadataFactoryInterface', - $this->validator->getMetadataFactory() - ); + return new Validator($metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); } }