4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Validator\Tests\Validator;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Validator\Constraints\Callback;
16 use Symfony\Component\Validator\Constraints\GroupSequence;
17 use Symfony\Component\Validator\Constraints\Valid;
18 use Symfony\Component\Validator\ConstraintViolationInterface;
19 use Symfony\Component\Validator\ExecutionContextInterface;
20 use Symfony\Component\Validator\Mapping\ClassMetadata;
21 use Symfony\Component\Validator\Tests\Fixtures\Entity;
22 use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
23 use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity;
24 use Symfony\Component\Validator\Tests\Fixtures\Reference;
27 * @author Bernhard Schussek <bschussek@gmail.com>
29 abstract class AbstractValidatorTest extends TestCase
31 const ENTITY_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Entity';
33 const REFERENCE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\Reference';
36 * @var FakeMetadataFactory
38 public $metadataFactory;
48 public $referenceMetadata;
50 protected function setUp()
52 $this->metadataFactory = new FakeMetadataFactory();
53 $this->metadata = new ClassMetadata(self::ENTITY_CLASS);
54 $this->referenceMetadata = new ClassMetadata(self::REFERENCE_CLASS);
55 $this->metadataFactory->addMetadata($this->metadata);
56 $this->metadataFactory->addMetadata($this->referenceMetadata);
59 protected function tearDown()
61 $this->metadataFactory = null;
62 $this->metadata = null;
63 $this->referenceMetadata = null;
66 abstract protected function validate($value, $constraints = null, $groups = null);
68 abstract protected function validateProperty($object, $propertyName, $groups = null);
70 abstract protected function validatePropertyValue($object, $propertyName, $value, $groups = null);
72 public function testValidate()
76 $callback = function ($value, ExecutionContextInterface $context) use ($test) {
77 $test->assertNull($context->getClassName());
78 $test->assertNull($context->getPropertyName());
79 $test->assertSame('', $context->getPropertyPath());
80 $test->assertSame('Group', $context->getGroup());
81 $test->assertSame('Bernhard', $context->getRoot());
82 $test->assertSame('Bernhard', $context->getValue());
83 $test->assertSame('Bernhard', $value);
85 $context->addViolation('Message %param%', array('%param%' => 'value'));
88 $constraint = new Callback(array(
89 'callback' => $callback,
93 $violations = $this->validate('Bernhard', $constraint, 'Group');
95 /* @var ConstraintViolationInterface[] $violations */
96 $this->assertCount(1, $violations);
97 $this->assertSame('Message value', $violations[0]->getMessage());
98 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
99 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
100 $this->assertSame('', $violations[0]->getPropertyPath());
101 $this->assertSame('Bernhard', $violations[0]->getRoot());
102 $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
103 $this->assertNull($violations[0]->getPlural());
104 $this->assertNull($violations[0]->getCode());
107 public function testClassConstraint()
110 $entity = new Entity();
112 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
113 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
114 $test->assertNull($context->getPropertyName());
115 $test->assertSame('', $context->getPropertyPath());
116 $test->assertSame('Group', $context->getGroup());
117 $test->assertSame($test->metadata, $context->getMetadata());
118 $test->assertSame($entity, $context->getRoot());
119 $test->assertSame($entity, $context->getValue());
120 $test->assertSame($entity, $value);
122 $context->addViolation('Message %param%', array('%param%' => 'value'));
125 $this->metadata->addConstraint(new Callback(array(
126 'callback' => $callback,
130 $violations = $this->validate($entity, null, 'Group');
132 /* @var ConstraintViolationInterface[] $violations */
133 $this->assertCount(1, $violations);
134 $this->assertSame('Message value', $violations[0]->getMessage());
135 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
136 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
137 $this->assertSame('', $violations[0]->getPropertyPath());
138 $this->assertSame($entity, $violations[0]->getRoot());
139 $this->assertSame($entity, $violations[0]->getInvalidValue());
140 $this->assertNull($violations[0]->getPlural());
141 $this->assertNull($violations[0]->getCode());
144 public function testPropertyConstraint()
147 $entity = new Entity();
148 $entity->firstName = 'Bernhard';
150 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
151 $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
153 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
154 $test->assertSame('firstName', $context->getPropertyName());
155 $test->assertSame('firstName', $context->getPropertyPath());
156 $test->assertSame('Group', $context->getGroup());
157 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
158 $test->assertSame($entity, $context->getRoot());
159 $test->assertSame('Bernhard', $context->getValue());
160 $test->assertSame('Bernhard', $value);
162 $context->addViolation('Message %param%', array('%param%' => 'value'));
165 $this->metadata->addPropertyConstraint('firstName', new Callback(array(
166 'callback' => $callback,
170 $violations = $this->validate($entity, null, 'Group');
172 /* @var ConstraintViolationInterface[] $violations */
173 $this->assertCount(1, $violations);
174 $this->assertSame('Message value', $violations[0]->getMessage());
175 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
176 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
177 $this->assertSame('firstName', $violations[0]->getPropertyPath());
178 $this->assertSame($entity, $violations[0]->getRoot());
179 $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
180 $this->assertNull($violations[0]->getPlural());
181 $this->assertNull($violations[0]->getCode());
184 public function testGetterConstraint()
187 $entity = new Entity();
188 $entity->setLastName('Schussek');
190 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
191 $propertyMetadatas = $test->metadata->getPropertyMetadata('lastName');
193 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
194 $test->assertSame('lastName', $context->getPropertyName());
195 $test->assertSame('lastName', $context->getPropertyPath());
196 $test->assertSame('Group', $context->getGroup());
197 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
198 $test->assertSame($entity, $context->getRoot());
199 $test->assertSame('Schussek', $context->getValue());
200 $test->assertSame('Schussek', $value);
202 $context->addViolation('Message %param%', array('%param%' => 'value'));
205 $this->metadata->addGetterConstraint('lastName', new Callback(array(
206 'callback' => $callback,
210 $violations = $this->validate($entity, null, 'Group');
212 /* @var ConstraintViolationInterface[] $violations */
213 $this->assertCount(1, $violations);
214 $this->assertSame('Message value', $violations[0]->getMessage());
215 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
216 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
217 $this->assertSame('lastName', $violations[0]->getPropertyPath());
218 $this->assertSame($entity, $violations[0]->getRoot());
219 $this->assertSame('Schussek', $violations[0]->getInvalidValue());
220 $this->assertNull($violations[0]->getPlural());
221 $this->assertNull($violations[0]->getCode());
224 public function testArray()
227 $entity = new Entity();
228 $array = array('key' => $entity);
230 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $array) {
231 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
232 $test->assertNull($context->getPropertyName());
233 $test->assertSame('[key]', $context->getPropertyPath());
234 $test->assertSame('Group', $context->getGroup());
235 $test->assertSame($test->metadata, $context->getMetadata());
236 $test->assertSame($array, $context->getRoot());
237 $test->assertSame($entity, $context->getValue());
238 $test->assertSame($entity, $value);
240 $context->addViolation('Message %param%', array('%param%' => 'value'));
243 $this->metadata->addConstraint(new Callback(array(
244 'callback' => $callback,
248 $violations = $this->validate($array, null, 'Group');
250 /* @var ConstraintViolationInterface[] $violations */
251 $this->assertCount(1, $violations);
252 $this->assertSame('Message value', $violations[0]->getMessage());
253 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
254 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
255 $this->assertSame('[key]', $violations[0]->getPropertyPath());
256 $this->assertSame($array, $violations[0]->getRoot());
257 $this->assertSame($entity, $violations[0]->getInvalidValue());
258 $this->assertNull($violations[0]->getPlural());
259 $this->assertNull($violations[0]->getCode());
262 public function testRecursiveArray()
265 $entity = new Entity();
266 $array = array(2 => array('key' => $entity));
268 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $array) {
269 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
270 $test->assertNull($context->getPropertyName());
271 $test->assertSame('[2][key]', $context->getPropertyPath());
272 $test->assertSame('Group', $context->getGroup());
273 $test->assertSame($test->metadata, $context->getMetadata());
274 $test->assertSame($array, $context->getRoot());
275 $test->assertSame($entity, $context->getValue());
276 $test->assertSame($entity, $value);
278 $context->addViolation('Message %param%', array('%param%' => 'value'));
281 $this->metadata->addConstraint(new Callback(array(
282 'callback' => $callback,
286 $violations = $this->validate($array, null, 'Group');
288 /* @var ConstraintViolationInterface[] $violations */
289 $this->assertCount(1, $violations);
290 $this->assertSame('Message value', $violations[0]->getMessage());
291 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
292 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
293 $this->assertSame('[2][key]', $violations[0]->getPropertyPath());
294 $this->assertSame($array, $violations[0]->getRoot());
295 $this->assertSame($entity, $violations[0]->getInvalidValue());
296 $this->assertNull($violations[0]->getPlural());
297 $this->assertNull($violations[0]->getCode());
300 public function testTraversable()
303 $entity = new Entity();
304 $traversable = new \ArrayIterator(array('key' => $entity));
306 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
307 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
308 $test->assertNull($context->getPropertyName());
309 $test->assertSame('[key]', $context->getPropertyPath());
310 $test->assertSame('Group', $context->getGroup());
311 $test->assertSame($test->metadata, $context->getMetadata());
312 $test->assertSame($traversable, $context->getRoot());
313 $test->assertSame($entity, $context->getValue());
314 $test->assertSame($entity, $value);
316 $context->addViolation('Message %param%', array('%param%' => 'value'));
319 $this->metadata->addConstraint(new Callback(array(
320 'callback' => $callback,
324 $violations = $this->validate($traversable, null, 'Group');
326 /* @var ConstraintViolationInterface[] $violations */
327 $this->assertCount(1, $violations);
328 $this->assertSame('Message value', $violations[0]->getMessage());
329 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
330 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
331 $this->assertSame('[key]', $violations[0]->getPropertyPath());
332 $this->assertSame($traversable, $violations[0]->getRoot());
333 $this->assertSame($entity, $violations[0]->getInvalidValue());
334 $this->assertNull($violations[0]->getPlural());
335 $this->assertNull($violations[0]->getCode());
338 public function testRecursiveTraversable()
341 $entity = new Entity();
342 $traversable = new \ArrayIterator(array(
343 2 => new \ArrayIterator(array('key' => $entity)),
346 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
347 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
348 $test->assertNull($context->getPropertyName());
349 $test->assertSame('[2][key]', $context->getPropertyPath());
350 $test->assertSame('Group', $context->getGroup());
351 $test->assertSame($test->metadata, $context->getMetadata());
352 $test->assertSame($traversable, $context->getRoot());
353 $test->assertSame($entity, $context->getValue());
354 $test->assertSame($entity, $value);
356 $context->addViolation('Message %param%', array('%param%' => 'value'));
359 $this->metadata->addConstraint(new Callback(array(
360 'callback' => $callback,
364 $violations = $this->validate($traversable, null, 'Group');
366 /* @var ConstraintViolationInterface[] $violations */
367 $this->assertCount(1, $violations);
368 $this->assertSame('Message value', $violations[0]->getMessage());
369 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
370 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
371 $this->assertSame('[2][key]', $violations[0]->getPropertyPath());
372 $this->assertSame($traversable, $violations[0]->getRoot());
373 $this->assertSame($entity, $violations[0]->getInvalidValue());
374 $this->assertNull($violations[0]->getPlural());
375 $this->assertNull($violations[0]->getCode());
378 public function testReferenceClassConstraint()
381 $entity = new Entity();
382 $entity->reference = new Reference();
384 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
385 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
386 $test->assertNull($context->getPropertyName());
387 $test->assertSame('reference', $context->getPropertyPath());
388 $test->assertSame('Group', $context->getGroup());
389 $test->assertSame($test->referenceMetadata, $context->getMetadata());
390 $test->assertSame($entity, $context->getRoot());
391 $test->assertSame($entity->reference, $context->getValue());
392 $test->assertSame($entity->reference, $value);
394 $context->addViolation('Message %param%', array('%param%' => 'value'));
397 $this->metadata->addPropertyConstraint('reference', new Valid());
398 $this->referenceMetadata->addConstraint(new Callback(array(
399 'callback' => $callback,
403 $violations = $this->validate($entity, null, 'Group');
405 /* @var ConstraintViolationInterface[] $violations */
406 $this->assertCount(1, $violations);
407 $this->assertSame('Message value', $violations[0]->getMessage());
408 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
409 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
410 $this->assertSame('reference', $violations[0]->getPropertyPath());
411 $this->assertSame($entity, $violations[0]->getRoot());
412 $this->assertSame($entity->reference, $violations[0]->getInvalidValue());
413 $this->assertNull($violations[0]->getPlural());
414 $this->assertNull($violations[0]->getCode());
417 public function testReferencePropertyConstraint()
420 $entity = new Entity();
421 $entity->reference = new Reference();
422 $entity->reference->value = 'Foobar';
424 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
425 $propertyMetadatas = $test->referenceMetadata->getPropertyMetadata('value');
427 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
428 $test->assertSame('value', $context->getPropertyName());
429 $test->assertSame('reference.value', $context->getPropertyPath());
430 $test->assertSame('Group', $context->getGroup());
431 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
432 $test->assertSame($entity, $context->getRoot());
433 $test->assertSame('Foobar', $context->getValue());
434 $test->assertSame('Foobar', $value);
436 $context->addViolation('Message %param%', array('%param%' => 'value'));
439 $this->metadata->addPropertyConstraint('reference', new Valid());
440 $this->referenceMetadata->addPropertyConstraint('value', new Callback(array(
441 'callback' => $callback,
445 $violations = $this->validate($entity, null, 'Group');
447 /* @var ConstraintViolationInterface[] $violations */
448 $this->assertCount(1, $violations);
449 $this->assertSame('Message value', $violations[0]->getMessage());
450 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
451 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
452 $this->assertSame('reference.value', $violations[0]->getPropertyPath());
453 $this->assertSame($entity, $violations[0]->getRoot());
454 $this->assertSame('Foobar', $violations[0]->getInvalidValue());
455 $this->assertNull($violations[0]->getPlural());
456 $this->assertNull($violations[0]->getCode());
459 public function testReferenceGetterConstraint()
462 $entity = new Entity();
463 $entity->reference = new Reference();
464 $entity->reference->setPrivateValue('Bamboo');
466 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
467 $propertyMetadatas = $test->referenceMetadata->getPropertyMetadata('privateValue');
469 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
470 $test->assertSame('privateValue', $context->getPropertyName());
471 $test->assertSame('reference.privateValue', $context->getPropertyPath());
472 $test->assertSame('Group', $context->getGroup());
473 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
474 $test->assertSame($entity, $context->getRoot());
475 $test->assertSame('Bamboo', $context->getValue());
476 $test->assertSame('Bamboo', $value);
478 $context->addViolation('Message %param%', array('%param%' => 'value'));
481 $this->metadata->addPropertyConstraint('reference', new Valid());
482 $this->referenceMetadata->addPropertyConstraint('privateValue', new Callback(array(
483 'callback' => $callback,
487 $violations = $this->validate($entity, null, 'Group');
489 /* @var ConstraintViolationInterface[] $violations */
490 $this->assertCount(1, $violations);
491 $this->assertSame('Message value', $violations[0]->getMessage());
492 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
493 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
494 $this->assertSame('reference.privateValue', $violations[0]->getPropertyPath());
495 $this->assertSame($entity, $violations[0]->getRoot());
496 $this->assertSame('Bamboo', $violations[0]->getInvalidValue());
497 $this->assertNull($violations[0]->getPlural());
498 $this->assertNull($violations[0]->getCode());
501 public function testsIgnoreNullReference()
503 $entity = new Entity();
504 $entity->reference = null;
506 $this->metadata->addPropertyConstraint('reference', new Valid());
508 $violations = $this->validate($entity);
510 /* @var ConstraintViolationInterface[] $violations */
511 $this->assertCount(0, $violations);
515 * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
517 public function testFailOnScalarReferences()
519 $entity = new Entity();
520 $entity->reference = 'string';
522 $this->metadata->addPropertyConstraint('reference', new Valid());
524 $this->validate($entity);
527 public function testArrayReference()
530 $entity = new Entity();
531 $entity->reference = array('key' => new Reference());
533 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
534 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
535 $test->assertNull($context->getPropertyName());
536 $test->assertSame('reference[key]', $context->getPropertyPath());
537 $test->assertSame('Group', $context->getGroup());
538 $test->assertSame($test->referenceMetadata, $context->getMetadata());
539 $test->assertSame($entity, $context->getRoot());
540 $test->assertSame($entity->reference['key'], $context->getValue());
541 $test->assertSame($entity->reference['key'], $value);
543 $context->addViolation('Message %param%', array('%param%' => 'value'));
546 $this->metadata->addPropertyConstraint('reference', new Valid());
547 $this->referenceMetadata->addConstraint(new Callback(array(
548 'callback' => $callback,
552 $violations = $this->validate($entity, null, 'Group');
554 /* @var ConstraintViolationInterface[] $violations */
555 $this->assertCount(1, $violations);
556 $this->assertSame('Message value', $violations[0]->getMessage());
557 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
558 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
559 $this->assertSame('reference[key]', $violations[0]->getPropertyPath());
560 $this->assertSame($entity, $violations[0]->getRoot());
561 $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue());
562 $this->assertNull($violations[0]->getPlural());
563 $this->assertNull($violations[0]->getCode());
566 // https://github.com/symfony/symfony/issues/6246
567 public function testRecursiveArrayReference()
570 $entity = new Entity();
571 $entity->reference = array(2 => array('key' => new Reference()));
573 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
574 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
575 $test->assertNull($context->getPropertyName());
576 $test->assertSame('reference[2][key]', $context->getPropertyPath());
577 $test->assertSame('Group', $context->getGroup());
578 $test->assertSame($test->referenceMetadata, $context->getMetadata());
579 $test->assertSame($entity, $context->getRoot());
580 $test->assertSame($entity->reference[2]['key'], $context->getValue());
581 $test->assertSame($entity->reference[2]['key'], $value);
583 $context->addViolation('Message %param%', array('%param%' => 'value'));
586 $this->metadata->addPropertyConstraint('reference', new Valid());
587 $this->referenceMetadata->addConstraint(new Callback(array(
588 'callback' => $callback,
592 $violations = $this->validate($entity, null, 'Group');
594 /* @var ConstraintViolationInterface[] $violations */
595 $this->assertCount(1, $violations);
596 $this->assertSame('Message value', $violations[0]->getMessage());
597 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
598 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
599 $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath());
600 $this->assertSame($entity, $violations[0]->getRoot());
601 $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue());
602 $this->assertNull($violations[0]->getPlural());
603 $this->assertNull($violations[0]->getCode());
606 public function testArrayTraversalCannotBeDisabled()
608 $entity = new Entity();
609 $entity->reference = array('key' => new Reference());
611 $callback = function ($value, ExecutionContextInterface $context) {
612 $context->addViolation('Message %param%', array('%param%' => 'value'));
615 $this->metadata->addPropertyConstraint('reference', new Valid(array(
618 $this->referenceMetadata->addConstraint(new Callback($callback));
620 $violations = $this->validate($entity);
622 /* @var ConstraintViolationInterface[] $violations */
623 $this->assertCount(1, $violations);
626 public function testRecursiveArrayTraversalCannotBeDisabled()
628 $entity = new Entity();
629 $entity->reference = array(2 => array('key' => new Reference()));
631 $callback = function ($value, ExecutionContextInterface $context) {
632 $context->addViolation('Message %param%', array('%param%' => 'value'));
635 $this->metadata->addPropertyConstraint('reference', new Valid(array(
638 $this->referenceMetadata->addConstraint(new Callback($callback));
640 $violations = $this->validate($entity);
642 /* @var ConstraintViolationInterface[] $violations */
643 $this->assertCount(1, $violations);
646 public function testIgnoreScalarsDuringArrayTraversal()
648 $entity = new Entity();
649 $entity->reference = array('string', 1234);
651 $this->metadata->addPropertyConstraint('reference', new Valid());
653 $violations = $this->validate($entity);
655 /* @var ConstraintViolationInterface[] $violations */
656 $this->assertCount(0, $violations);
659 public function testIgnoreNullDuringArrayTraversal()
661 $entity = new Entity();
662 $entity->reference = array(null);
664 $this->metadata->addPropertyConstraint('reference', new Valid());
666 $violations = $this->validate($entity);
668 /* @var ConstraintViolationInterface[] $violations */
669 $this->assertCount(0, $violations);
672 public function testTraversableReference()
675 $entity = new Entity();
676 $entity->reference = new \ArrayIterator(array('key' => new Reference()));
678 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
679 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
680 $test->assertNull($context->getPropertyName());
681 $test->assertSame('reference[key]', $context->getPropertyPath());
682 $test->assertSame('Group', $context->getGroup());
683 $test->assertSame($test->referenceMetadata, $context->getMetadata());
684 $test->assertSame($entity, $context->getRoot());
685 $test->assertSame($entity->reference['key'], $context->getValue());
686 $test->assertSame($entity->reference['key'], $value);
688 $context->addViolation('Message %param%', array('%param%' => 'value'));
691 $this->metadata->addPropertyConstraint('reference', new Valid());
692 $this->referenceMetadata->addConstraint(new Callback(array(
693 'callback' => $callback,
697 $violations = $this->validate($entity, null, 'Group');
699 /* @var ConstraintViolationInterface[] $violations */
700 $this->assertCount(1, $violations);
701 $this->assertSame('Message value', $violations[0]->getMessage());
702 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
703 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
704 $this->assertSame('reference[key]', $violations[0]->getPropertyPath());
705 $this->assertSame($entity, $violations[0]->getRoot());
706 $this->assertSame($entity->reference['key'], $violations[0]->getInvalidValue());
707 $this->assertNull($violations[0]->getPlural());
708 $this->assertNull($violations[0]->getCode());
711 public function testDisableTraversableTraversal()
713 $entity = new Entity();
714 $entity->reference = new \ArrayIterator(array('key' => new Reference()));
716 $callback = function ($value, ExecutionContextInterface $context) {
717 $context->addViolation('Message %param%', array('%param%' => 'value'));
720 $this->metadataFactory->addMetadata(new ClassMetadata('ArrayIterator'));
721 $this->metadata->addPropertyConstraint('reference', new Valid(array(
724 $this->referenceMetadata->addConstraint(new Callback($callback));
726 $violations = $this->validate($entity);
728 /* @var ConstraintViolationInterface[] $violations */
729 $this->assertCount(0, $violations);
733 * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
735 public function testMetadataMustExistIfTraversalIsDisabled()
737 $entity = new Entity();
738 $entity->reference = new \ArrayIterator();
740 $this->metadata->addPropertyConstraint('reference', new Valid(array(
744 $this->validate($entity);
747 public function testEnableRecursiveTraversableTraversal()
750 $entity = new Entity();
751 $entity->reference = new \ArrayIterator(array(
752 2 => new \ArrayIterator(array('key' => new Reference())),
755 $callback = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
756 $test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
757 $test->assertNull($context->getPropertyName());
758 $test->assertSame('reference[2][key]', $context->getPropertyPath());
759 $test->assertSame('Group', $context->getGroup());
760 $test->assertSame($test->referenceMetadata, $context->getMetadata());
761 $test->assertSame($entity, $context->getRoot());
762 $test->assertSame($entity->reference[2]['key'], $context->getValue());
763 $test->assertSame($entity->reference[2]['key'], $value);
765 $context->addViolation('Message %param%', array('%param%' => 'value'));
768 $this->metadata->addPropertyConstraint('reference', new Valid(array(
771 $this->referenceMetadata->addConstraint(new Callback(array(
772 'callback' => $callback,
776 $violations = $this->validate($entity, null, 'Group');
778 /* @var ConstraintViolationInterface[] $violations */
779 $this->assertCount(1, $violations);
780 $this->assertSame('Message value', $violations[0]->getMessage());
781 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
782 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
783 $this->assertSame('reference[2][key]', $violations[0]->getPropertyPath());
784 $this->assertSame($entity, $violations[0]->getRoot());
785 $this->assertSame($entity->reference[2]['key'], $violations[0]->getInvalidValue());
786 $this->assertNull($violations[0]->getPlural());
787 $this->assertNull($violations[0]->getCode());
790 public function testValidateProperty()
793 $entity = new Entity();
794 $entity->firstName = 'Bernhard';
795 $entity->setLastName('Schussek');
797 $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
798 $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
800 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
801 $test->assertSame('firstName', $context->getPropertyName());
802 $test->assertSame('firstName', $context->getPropertyPath());
803 $test->assertSame('Group', $context->getGroup());
804 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
805 $test->assertSame($entity, $context->getRoot());
806 $test->assertSame('Bernhard', $context->getValue());
807 $test->assertSame('Bernhard', $value);
809 $context->addViolation('Message %param%', array('%param%' => 'value'));
812 $callback2 = function ($value, ExecutionContextInterface $context) {
813 $context->addViolation('Other violation');
816 $this->metadata->addPropertyConstraint('firstName', new Callback(array(
817 'callback' => $callback1,
820 $this->metadata->addPropertyConstraint('lastName', new Callback(array(
821 'callback' => $callback2,
825 $violations = $this->validateProperty($entity, 'firstName', 'Group');
827 /* @var ConstraintViolationInterface[] $violations */
828 $this->assertCount(1, $violations);
829 $this->assertSame('Message value', $violations[0]->getMessage());
830 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
831 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
832 $this->assertSame('firstName', $violations[0]->getPropertyPath());
833 $this->assertSame($entity, $violations[0]->getRoot());
834 $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
835 $this->assertNull($violations[0]->getPlural());
836 $this->assertNull($violations[0]->getCode());
840 * Cannot be UnsupportedMetadataException for BC with Symfony < 2.5.
842 * @expectedException \Symfony\Component\Validator\Exception\ValidatorException
845 public function testLegacyValidatePropertyFailsIfPropertiesNotSupported()
847 // $metadata does not implement PropertyMetadataContainerInterface
848 $metadata = $this->getMockBuilder('Symfony\Component\Validator\MetadataInterface')->getMock();
850 $this->metadataFactory->addMetadataForValue('VALUE', $metadata);
852 $this->validateProperty('VALUE', 'someProperty');
856 * https://github.com/symfony/symfony/issues/11604.
858 public function testValidatePropertyWithoutConstraints()
860 $entity = new Entity();
861 $violations = $this->validateProperty($entity, 'lastName');
863 $this->assertCount(0, $violations, '->validateProperty() returns no violations if no constraints have been configured for the property being validated');
866 public function testValidatePropertyValue()
869 $entity = new Entity();
870 $entity->setLastName('Schussek');
872 $callback1 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
873 $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
875 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
876 $test->assertSame('firstName', $context->getPropertyName());
877 $test->assertSame('firstName', $context->getPropertyPath());
878 $test->assertSame('Group', $context->getGroup());
879 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
880 $test->assertSame($entity, $context->getRoot());
881 $test->assertSame('Bernhard', $context->getValue());
882 $test->assertSame('Bernhard', $value);
884 $context->addViolation('Message %param%', array('%param%' => 'value'));
887 $callback2 = function ($value, ExecutionContextInterface $context) {
888 $context->addViolation('Other violation');
891 $this->metadata->addPropertyConstraint('firstName', new Callback(array(
892 'callback' => $callback1,
895 $this->metadata->addPropertyConstraint('lastName', new Callback(array(
896 'callback' => $callback2,
900 $violations = $this->validatePropertyValue(
907 /* @var ConstraintViolationInterface[] $violations */
908 $this->assertCount(1, $violations);
909 $this->assertSame('Message value', $violations[0]->getMessage());
910 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
911 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
912 $this->assertSame('firstName', $violations[0]->getPropertyPath());
913 $this->assertSame($entity, $violations[0]->getRoot());
914 $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
915 $this->assertNull($violations[0]->getPlural());
916 $this->assertNull($violations[0]->getCode());
919 public function testValidatePropertyValueWithClassName()
923 $callback1 = function ($value, ExecutionContextInterface $context) use ($test) {
924 $propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
926 $test->assertSame($test::ENTITY_CLASS, $context->getClassName());
927 $test->assertSame('firstName', $context->getPropertyName());
928 $test->assertSame('', $context->getPropertyPath());
929 $test->assertSame('Group', $context->getGroup());
930 $test->assertSame($propertyMetadatas[0], $context->getMetadata());
931 $test->assertSame('Bernhard', $context->getRoot());
932 $test->assertSame('Bernhard', $context->getValue());
933 $test->assertSame('Bernhard', $value);
935 $context->addViolation('Message %param%', array('%param%' => 'value'));
938 $callback2 = function ($value, ExecutionContextInterface $context) {
939 $context->addViolation('Other violation');
942 $this->metadata->addPropertyConstraint('firstName', new Callback(array(
943 'callback' => $callback1,
946 $this->metadata->addPropertyConstraint('lastName', new Callback(array(
947 'callback' => $callback2,
951 $violations = $this->validatePropertyValue(
958 /* @var ConstraintViolationInterface[] $violations */
959 $this->assertCount(1, $violations);
960 $this->assertSame('Message value', $violations[0]->getMessage());
961 $this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
962 $this->assertSame(array('%param%' => 'value'), $violations[0]->getParameters());
963 $this->assertSame('', $violations[0]->getPropertyPath());
964 $this->assertSame('Bernhard', $violations[0]->getRoot());
965 $this->assertSame('Bernhard', $violations[0]->getInvalidValue());
966 $this->assertNull($violations[0]->getPlural());
967 $this->assertNull($violations[0]->getCode());
971 * Cannot be UnsupportedMetadataException for BC with Symfony < 2.5.
973 * @expectedException \Symfony\Component\Validator\Exception\ValidatorException
976 public function testLegacyValidatePropertyValueFailsIfPropertiesNotSupported()
978 // $metadata does not implement PropertyMetadataContainerInterface
979 $metadata = $this->getMockBuilder('Symfony\Component\Validator\MetadataInterface')->getMock();
981 $this->metadataFactory->addMetadataForValue('VALUE', $metadata);
983 $this->validatePropertyValue('VALUE', 'someProperty', 'someValue');
987 * https://github.com/symfony/symfony/issues/11604.
989 public function testValidatePropertyValueWithoutConstraints()
991 $entity = new Entity();
992 $violations = $this->validatePropertyValue($entity, 'lastName', 'foo');
994 $this->assertCount(0, $violations, '->validatePropertyValue() returns no violations if no constraints have been configured for the property being validated');
997 public function testValidateObjectOnlyOncePerGroup()
999 $entity = new Entity();
1000 $entity->reference = new Reference();
1001 $entity->reference2 = $entity->reference;
1003 $callback = function ($value, ExecutionContextInterface $context) {
1004 $context->addViolation('Message');
1007 $this->metadata->addPropertyConstraint('reference', new Valid());
1008 $this->metadata->addPropertyConstraint('reference2', new Valid());
1009 $this->referenceMetadata->addConstraint(new Callback($callback));
1011 $violations = $this->validate($entity);
1013 /* @var ConstraintViolationInterface[] $violations */
1014 $this->assertCount(1, $violations);
1017 public function testValidateDifferentObjectsSeparately()
1019 $entity = new Entity();
1020 $entity->reference = new Reference();
1021 $entity->reference2 = new Reference();
1023 $callback = function ($value, ExecutionContextInterface $context) {
1024 $context->addViolation('Message');
1027 $this->metadata->addPropertyConstraint('reference', new Valid());
1028 $this->metadata->addPropertyConstraint('reference2', new Valid());
1029 $this->referenceMetadata->addConstraint(new Callback($callback));
1031 $violations = $this->validate($entity);
1033 /* @var ConstraintViolationInterface[] $violations */
1034 $this->assertCount(2, $violations);
1037 public function testValidateSingleGroup()
1039 $entity = new Entity();
1041 $callback = function ($value, ExecutionContextInterface $context) {
1042 $context->addViolation('Message');
1045 $this->metadata->addConstraint(new Callback(array(
1046 'callback' => $callback,
1047 'groups' => 'Group 1',
1049 $this->metadata->addConstraint(new Callback(array(
1050 'callback' => $callback,
1051 'groups' => 'Group 2',
1054 $violations = $this->validate($entity, null, 'Group 2');
1056 /* @var ConstraintViolationInterface[] $violations */
1057 $this->assertCount(1, $violations);
1060 public function testValidateMultipleGroups()
1062 $entity = new Entity();
1064 $callback = function ($value, ExecutionContextInterface $context) {
1065 $context->addViolation('Message');
1068 $this->metadata->addConstraint(new Callback(array(
1069 'callback' => $callback,
1070 'groups' => 'Group 1',
1072 $this->metadata->addConstraint(new Callback(array(
1073 'callback' => $callback,
1074 'groups' => 'Group 2',
1077 $violations = $this->validate($entity, null, array('Group 1', 'Group 2'));
1079 /* @var ConstraintViolationInterface[] $violations */
1080 $this->assertCount(2, $violations);
1083 public function testReplaceDefaultGroupByGroupSequenceObject()
1085 $entity = new Entity();
1087 $callback1 = function ($value, ExecutionContextInterface $context) {
1088 $context->addViolation('Violation in Group 2');
1090 $callback2 = function ($value, ExecutionContextInterface $context) {
1091 $context->addViolation('Violation in Group 3');
1094 $this->metadata->addConstraint(new Callback(array(
1095 'callback' => function () {},
1096 'groups' => 'Group 1',
1098 $this->metadata->addConstraint(new Callback(array(
1099 'callback' => $callback1,
1100 'groups' => 'Group 2',
1102 $this->metadata->addConstraint(new Callback(array(
1103 'callback' => $callback2,
1104 'groups' => 'Group 3',
1107 $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3', 'Entity'));
1108 $this->metadata->setGroupSequence($sequence);
1110 $violations = $this->validate($entity, null, 'Default');
1112 /* @var ConstraintViolationInterface[] $violations */
1113 $this->assertCount(1, $violations);
1114 $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1117 public function testReplaceDefaultGroupByGroupSequenceArray()
1119 $entity = new Entity();
1121 $callback1 = function ($value, ExecutionContextInterface $context) {
1122 $context->addViolation('Violation in Group 2');
1124 $callback2 = function ($value, ExecutionContextInterface $context) {
1125 $context->addViolation('Violation in Group 3');
1128 $this->metadata->addConstraint(new Callback(array(
1129 'callback' => function () {},
1130 'groups' => 'Group 1',
1132 $this->metadata->addConstraint(new Callback(array(
1133 'callback' => $callback1,
1134 'groups' => 'Group 2',
1136 $this->metadata->addConstraint(new Callback(array(
1137 'callback' => $callback2,
1138 'groups' => 'Group 3',
1141 $sequence = array('Group 1', 'Group 2', 'Group 3', 'Entity');
1142 $this->metadata->setGroupSequence($sequence);
1144 $violations = $this->validate($entity, null, 'Default');
1146 /* @var ConstraintViolationInterface[] $violations */
1147 $this->assertCount(1, $violations);
1148 $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1151 public function testPropagateDefaultGroupToReferenceWhenReplacingDefaultGroup()
1153 $entity = new Entity();
1154 $entity->reference = new Reference();
1156 $callback1 = function ($value, ExecutionContextInterface $context) {
1157 $context->addViolation('Violation in Default group');
1159 $callback2 = function ($value, ExecutionContextInterface $context) {
1160 $context->addViolation('Violation in group sequence');
1163 $this->metadata->addPropertyConstraint('reference', new Valid());
1164 $this->referenceMetadata->addConstraint(new Callback(array(
1165 'callback' => $callback1,
1166 'groups' => 'Default',
1168 $this->referenceMetadata->addConstraint(new Callback(array(
1169 'callback' => $callback2,
1170 'groups' => 'Group 1',
1173 $sequence = new GroupSequence(array('Group 1', 'Entity'));
1174 $this->metadata->setGroupSequence($sequence);
1176 $violations = $this->validate($entity, null, 'Default');
1178 /* @var ConstraintViolationInterface[] $violations */
1179 $this->assertCount(1, $violations);
1180 $this->assertSame('Violation in Default group', $violations[0]->getMessage());
1183 public function testValidateCustomGroupWhenDefaultGroupWasReplaced()
1185 $entity = new Entity();
1187 $callback1 = function ($value, ExecutionContextInterface $context) {
1188 $context->addViolation('Violation in other group');
1190 $callback2 = function ($value, ExecutionContextInterface $context) {
1191 $context->addViolation('Violation in group sequence');
1194 $this->metadata->addConstraint(new Callback(array(
1195 'callback' => $callback1,
1196 'groups' => 'Other Group',
1198 $this->metadata->addConstraint(new Callback(array(
1199 'callback' => $callback2,
1200 'groups' => 'Group 1',
1203 $sequence = new GroupSequence(array('Group 1', 'Entity'));
1204 $this->metadata->setGroupSequence($sequence);
1206 $violations = $this->validate($entity, null, 'Other Group');
1208 /* @var ConstraintViolationInterface[] $violations */
1209 $this->assertCount(1, $violations);
1210 $this->assertSame('Violation in other group', $violations[0]->getMessage());
1213 public function testReplaceDefaultGroupWithObjectFromGroupSequenceProvider()
1215 $sequence = new GroupSequence(array('Group 1', 'Group 2', 'Group 3', 'Entity'));
1216 $entity = new GroupSequenceProviderEntity($sequence);
1218 $callback1 = function ($value, ExecutionContextInterface $context) {
1219 $context->addViolation('Violation in Group 2');
1221 $callback2 = function ($value, ExecutionContextInterface $context) {
1222 $context->addViolation('Violation in Group 3');
1225 $metadata = new ClassMetadata(get_class($entity));
1226 $metadata->addConstraint(new Callback(array(
1227 'callback' => function () {},
1228 'groups' => 'Group 1',
1230 $metadata->addConstraint(new Callback(array(
1231 'callback' => $callback1,
1232 'groups' => 'Group 2',
1234 $metadata->addConstraint(new Callback(array(
1235 'callback' => $callback2,
1236 'groups' => 'Group 3',
1238 $metadata->setGroupSequenceProvider(true);
1240 $this->metadataFactory->addMetadata($metadata);
1242 $violations = $this->validate($entity, null, 'Default');
1244 /* @var ConstraintViolationInterface[] $violations */
1245 $this->assertCount(1, $violations);
1246 $this->assertSame('Violation in Group 2', $violations[0]->getMessage());
1249 public function testReplaceDefaultGroupWithArrayFromGroupSequenceProvider()
1251 $sequence = array('Group 1', 'Group 2', 'Group 3', 'Entity');
1252 $entity = new GroupSequenceProviderEntity($sequence);
1254 $callback1 = function ($value, ExecutionContextInterface $context) {
1255 $context->addViolation('Violation in Group 2');
1257 $callback2 = function ($value, ExecutionContextInterface $context) {
1258 $context->addViolation('Violation in Group 3');
1261 $metadata = new ClassMetadata(get_class($entity));
1262 $metadata->addConstraint(new Callback(array(
1263 'callback' => function () {},
1264 'groups' => 'Group 1',
1266 $metadata->addConstraint(new Callback(array(
1267 'callback' => $callback1,
1268 'groups' => 'Group 2',
1270 $metadata->addConstraint(new Callback(array(
1271 'callback' => $callback2,
1272 'groups' => 'Group 3',
1274 $metadata->setGroupSequenceProvider(true);
1276 $this->metadataFactory->addMetadata($metadata);
1278 $violations = $this->validate($entity, null, 'Default');
1280 /* @var ConstraintViolationInterface[] $violations */
1281 $this->assertCount(1, $violations);
1282 $this->assertSame('Violation in Group 2', $violations[0]->getMessage());