Skip to content

Commit 09f744b

Browse files
committed
[Validator] Implemented BC traversal of traversables through validate()
1 parent 297ba4f commit 09f744b

File tree

3 files changed

+175
-22
lines changed

3 files changed

+175
-22
lines changed

src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,169 @@ public function testArray()
238238
$this->assertNull($violations[0]->getCode());
239239
}
240240

241+
public function testRecursiveArray()
242+
{
243+
$test = $this;
244+
$entity = new Entity();
245+
$array = array(2 => array('key' => $entity));
246+
247+
$callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $array) {
248+
$test->assertSame($test::ENTITY_CLASS, $context->getClassName());
249+
$test->assertNull($context->getPropertyName());
250+
$test->assertSame('[2][key]', $context->getPropertyPath());
251+
$test->assertSame('Group', $context->getGroup());
252+
$test->assertSame($test->metadata, $context->getMetadata());
253+
$test->assertSame($test->metadataFactory, $context->getMetadataFactory());
254+
$test->assertSame($array, $context->getRoot());
255+
$test->assertSame($entity, $context->getValue());
256+
$test->assertSame($entity, $value);
257+
258+
$context->addViolation('Message %param%', array('%param%' => 'value'));
259+
};
260+
261+
$this->metadata->addConstraint(new Callback(array(
262+
'callback' => $callback,
263+
'groups' => 'Group',
264+
)));
265+
266+
$violations = $this->validator->validate($array, 'Group');
267+
268+
/** @var ConstraintViolationInterface[] $violations */
269+
$this->assertCount(1, $violations);
270+
$this->assertSame('Message value', $violations[0]->getMessage());
271+
$this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
272+
$this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters());
273+
$this->assertSame('[2][key]', $violations[0]->getPropertyPath());
274+
$this->assertSame($array, $violations[0]->getRoot());
275+
$this->assertSame($entity, $violations[0]->getInvalidValue());
276+
$this->assertNull($violations[0]->getMessagePluralization());
277+
$this->assertNull($violations[0]->getCode());
278+
}
279+
280+
/**
281+
* @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
282+
*/
283+
public function testTraversableTraverseDisabled()
284+
{
285+
$test = $this;
286+
$entity = new Entity();
287+
$traversable = new \ArrayIterator(array('key' => $entity));
288+
289+
$callback = function () use ($test) {
290+
$test->fail('Should not be called');
291+
};
292+
293+
$this->metadata->addConstraint(new Callback(array(
294+
'callback' => $callback,
295+
'groups' => 'Group',
296+
)));
297+
298+
$this->validator->validate($traversable, 'Group');
299+
}
300+
301+
public function testTraversableTraverseEnabled()
302+
{
303+
$test = $this;
304+
$entity = new Entity();
305+
$traversable = new \ArrayIterator(array('key' => $entity));
306+
307+
$callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
308+
$test->assertSame($test::ENTITY_CLASS, $context->getClassName());
309+
$test->assertNull($context->getPropertyName());
310+
$test->assertSame('[key]', $context->getPropertyPath());
311+
$test->assertSame('Group', $context->getGroup());
312+
$test->assertSame($test->metadata, $context->getMetadata());
313+
$test->assertSame($test->metadataFactory, $context->getMetadataFactory());
314+
$test->assertSame($traversable, $context->getRoot());
315+
$test->assertSame($entity, $context->getValue());
316+
$test->assertSame($entity, $value);
317+
318+
$context->addViolation('Message %param%', array('%param%' => 'value'));
319+
};
320+
321+
$this->metadata->addConstraint(new Callback(array(
322+
'callback' => $callback,
323+
'groups' => 'Group',
324+
)));
325+
326+
$violations = $this->validator->validate($traversable, 'Group', true);
327+
328+
/** @var ConstraintViolationInterface[] $violations */
329+
$this->assertCount(1, $violations);
330+
$this->assertSame('Message value', $violations[0]->getMessage());
331+
$this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
332+
$this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters());
333+
$this->assertSame('[key]', $violations[0]->getPropertyPath());
334+
$this->assertSame($traversable, $violations[0]->getRoot());
335+
$this->assertSame($entity, $violations[0]->getInvalidValue());
336+
$this->assertNull($violations[0]->getMessagePluralization());
337+
$this->assertNull($violations[0]->getCode());
338+
}
339+
340+
/**
341+
* @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
342+
*/
343+
public function testRecursiveTraversableRecursiveTraversalDisabled()
344+
{
345+
$test = $this;
346+
$entity = new Entity();
347+
$traversable = new \ArrayIterator(array(
348+
2 => new \ArrayIterator(array('key' => $entity)),
349+
));
350+
351+
$callback = function () use ($test) {
352+
$test->fail('Should not be called');
353+
};
354+
355+
$this->metadata->addConstraint(new Callback(array(
356+
'callback' => $callback,
357+
'groups' => 'Group',
358+
)));
359+
360+
$this->validator->validate($traversable, 'Group', true);
361+
}
362+
363+
public function testRecursiveTraversableRecursiveTraversalEnabled()
364+
{
365+
$test = $this;
366+
$entity = new Entity();
367+
$traversable = new \ArrayIterator(array(
368+
2 => new \ArrayIterator(array('key' => $entity)),
369+
));
370+
371+
$callback = function ($value, ExecutionContextInterface $context) use ($test, $entity, $traversable) {
372+
$test->assertSame($test::ENTITY_CLASS, $context->getClassName());
373+
$test->assertNull($context->getPropertyName());
374+
$test->assertSame('[2][key]', $context->getPropertyPath());
375+
$test->assertSame('Group', $context->getGroup());
376+
$test->assertSame($test->metadata, $context->getMetadata());
377+
$test->assertSame($test->metadataFactory, $context->getMetadataFactory());
378+
$test->assertSame($traversable, $context->getRoot());
379+
$test->assertSame($entity, $context->getValue());
380+
$test->assertSame($entity, $value);
381+
382+
$context->addViolation('Message %param%', array('%param%' => 'value'));
383+
};
384+
385+
$this->metadata->addConstraint(new Callback(array(
386+
'callback' => $callback,
387+
'groups' => 'Group',
388+
)));
389+
390+
$violations = $this->validator->validate($traversable, 'Group', true, true);
391+
392+
/** @var ConstraintViolationInterface[] $violations */
393+
$this->assertCount(1, $violations);
394+
$this->assertSame('Message value', $violations[0]->getMessage());
395+
$this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
396+
$this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters());
397+
$this->assertSame('[2][key]', $violations[0]->getPropertyPath());
398+
$this->assertSame($traversable, $violations[0]->getRoot());
399+
$this->assertSame($entity, $violations[0]->getInvalidValue());
400+
$this->assertNull($violations[0]->getMessagePluralization());
401+
$this->assertNull($violations[0]->getCode());
402+
}
403+
241404
public function testReferenceClassConstraint()
242405
{
243406
$test = $this;

src/Symfony/Component/Validator/Validator/AbstractValidator.php

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,24 +98,6 @@ protected function traverseObject($object, $groups = null)
9898
)));
9999
}
100100

101-
protected function traverseCollection($collection, $groups = null, $deep = false)
102-
{
103-
$metadata = new GenericMetadata();
104-
$metadata->addConstraint(new Traverse(array(
105-
'traverse' => true,
106-
'deep' => $deep,
107-
)));
108-
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
109-
110-
$this->nodeTraverser->traverse(array(new GenericNode(
111-
$collection,
112-
$metadata,
113-
$this->defaultPropertyPath,
114-
$groups,
115-
$groups
116-
)));
117-
}
118-
119101
protected function traverseProperty($object, $propertyName, $groups = null)
120102
{
121103
$classMetadata = $this->metadataFactory->getMetadataFor($object);

src/Symfony/Component/Validator/Validator/LegacyValidator.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Validator\Validator;
1313

14+
use Symfony\Component\Validator\Constraints\Traverse;
15+
use Symfony\Component\Validator\Constraints\Valid;
1416
use Symfony\Component\Validator\ValidatorInterface as LegacyValidatorInterface;
1517

1618
/**
@@ -22,11 +24,17 @@ class LegacyValidator extends Validator implements LegacyValidatorInterface
2224
public function validate($value, $groups = null, $traverse = false, $deep = false)
2325
{
2426
if (is_array($value)) {
25-
$this->contextManager->startContext($value);
26-
27-
$this->traverseCollection($value, $groups, $deep);
27+
return $this->validateValue($value, new Traverse(array(
28+
'traverse' => true,
29+
'deep' => $deep,
30+
)), $groups);
31+
}
2832

29-
return $this->contextManager->stopContext()->getViolations();
33+
if ($traverse && $value instanceof \Traversable) {
34+
return $this->validateValue($value, array(
35+
new Valid(),
36+
new Traverse(array('traverse' => true, 'deep' => $deep)),
37+
), $groups);
3038
}
3139

3240
return $this->validateObject($value, $groups);

0 commit comments

Comments
 (0)