Browse files

[Validator] Backported #11410 to 2.3: Object initializers are called …

…only once per object
  • Loading branch information...
1 parent 91e32f8 commit 291cbf9efa14460a2c77a6d6ca9bbcc2603db639 @webmozart webmozart committed Jul 17, 2014
View
1 src/Symfony/Component/Validator/Tests/Fixtures/Entity.php
@@ -35,6 +35,7 @@ class Entity extends EntityParent implements EntityInterface
public $reference;
private $internal;
public $data = 'Overridden data';
+ public $initialized = false;
public function __construct($internal = null)
{
View
48 src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Validator\Tests;
+use Symfony\Component\Validator\Constraints\Callback;
+use Symfony\Component\Validator\ExecutionContextInterface;
use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Tests\Fixtures\Reference;
@@ -561,4 +563,50 @@ public function testValidateCascadedPropertyRequiresObjectOrArray()
$this->visitor->validate($entity, 'Default', '');
}
+
+ public function testInitializeObjectsOnFirstValidation()
+ {
+ $test = $this;
+ $entity = new Entity();
+ $entity->initialized = false;
+
+ // prepare initializers that set "initialized" to true
+ $initializer1 = $this->getMock('Symfony\\Component\\Validator\\ObjectInitializerInterface');
+ $initializer2 = $this->getMock('Symfony\\Component\\Validator\\ObjectInitializerInterface');
+
+ $initializer1->expects($this->once())
+ ->method('initialize')
+ ->with($entity)
+ ->will($this->returnCallback(function ($object) {
+ $object->initialized = true;
+ }));
+
+ $initializer2->expects($this->once())
+ ->method('initialize')
+ ->with($entity);
+
+ $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator(), null, array(
+ $initializer1,
+ $initializer2
+ ));
+
+ // prepare constraint which
+ // * checks that "initialized" is set to true
+ // * validates the object again
+ $callback = function ($object, ExecutionContextInterface $context) use ($test) {
+ $test->assertTrue($object->initialized);
+
+ // validate again in same group
+ $context->validate($object);
+
+ // validate again in other group
+ $context->validate($object, '', 'SomeGroup');
+ };
+
+ $this->metadata->addConstraint(new Callback(array($callback)));
+
+ $this->visitor->validate($entity, 'Default', '');
+
+ $this->assertTrue($entity->initialized);
+ }
}
View
17 src/Symfony/Component/Validator/ValidationVisitor.php
@@ -127,16 +127,19 @@ public function validate($value, $group, $propertyPath, $traverse = false, $deep
return;
}
+ // Initialize if the object wasn't initialized before
+ if (!isset($this->validatedObjects[$hash])) {
+ foreach ($this->objectInitializers as $initializer) {
+ if (!$initializer instanceof ObjectInitializerInterface) {
+ throw new \LogicException('Validator initializers must implement ObjectInitializerInterface.');
+ }
+ $initializer->initialize($value);
+ }
+ }
+
// Remember validating this object before starting and possibly
// traversing the object graph
$this->validatedObjects[$hash][$group] = true;
-
- foreach ($this->objectInitializers as $initializer) {
- if (!$initializer instanceof ObjectInitializerInterface) {
- throw new \LogicException('Validator initializers must implement ObjectInitializerInterface.');
- }
- $initializer->initialize($value);
- }
}
// Validate arrays recursively by default, otherwise every driver needs

0 comments on commit 291cbf9

Please sign in to comment.