diff --git a/src/Symfony/Component/Validator/Context/ExecutionContext.php b/src/Symfony/Component/Validator/Context/ExecutionContext.php index 542ea33658..4096a345bd 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContext.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContext.php @@ -147,7 +147,7 @@ class ExecutionContext implements ExecutionContextInterface /** * {@inheritdoc} */ - public function setNode($value, $object, MetadataInterface $metadata, $propertyPath) + public function setNode($value, $object, MetadataInterface $metadata = null, $propertyPath) { $this->value = $value; $this->object = $object; diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index 37518fdf7a..ee78cce183 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -124,7 +124,7 @@ interface ExecutionContextInterface extends LegacyExecutionContextInterface * @internal Used by the validator engine. Should not be called by user * code. */ - public function setNode($value, $object, MetadataInterface $metadata, $propertyPath); + public function setNode($value, $object, MetadataInterface $metadata = null, $propertyPath); /** * Sets the currently validated group. diff --git a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php index 02fefda5f0..e920da9a72 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php @@ -193,13 +193,26 @@ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest $entity = new Entity(); $entity->reference = new Reference(); - $callback1 = function ($value, ExecutionContextInterface $context) { + $callback1 = function ($value, ExecutionContextInterface $context) use ($test) { + $previousValue = $context->getValue(); + $previousObject = $context->getObject(); + $previousMetadata = $context->getMetadata(); + $previousPath = $context->getPropertyPath(); + $previousGroup = $context->getGroup(); + $context ->getValidator() ->inContext($context) ->atPath('subpath') ->validate($value->reference) ; + + // context changes shouldn't leak out of the validate() call + $test->assertSame($previousValue, $context->getValue()); + $test->assertSame($previousObject, $context->getObject()); + $test->assertSame($previousMetadata, $context->getMetadata()); + $test->assertSame($previousPath, $context->getPropertyPath()); + $test->assertSame($previousGroup, $context->getGroup()); }; $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { @@ -244,13 +257,26 @@ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest $entity = new Entity(); $entity->reference = new Reference(); - $callback1 = function ($value, ExecutionContextInterface $context) { + $callback1 = function ($value, ExecutionContextInterface $context) use ($test) { + $previousValue = $context->getValue(); + $previousObject = $context->getObject(); + $previousMetadata = $context->getMetadata(); + $previousPath = $context->getPropertyPath(); + $previousGroup = $context->getGroup(); + $context ->getValidator() ->inContext($context) ->atPath('subpath') ->validate(array('key' => $value->reference)) ; + + // context changes shouldn't leak out of the validate() call + $test->assertSame($previousValue, $context->getValue()); + $test->assertSame($previousObject, $context->getObject()); + $test->assertSame($previousMetadata, $context->getMetadata()); + $test->assertSame($previousPath, $context->getPropertyPath()); + $test->assertSame($previousGroup, $context->getGroup()); }; $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php index 56e94313be..53b935f5c3 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php @@ -120,8 +120,19 @@ abstract class AbstractLegacyApiTest extends AbstractValidatorTest $entity = new Entity(); $entity->reference = new Reference(); - $callback1 = function ($value, ExecutionContextInterface $context) { + $callback1 = function ($value, ExecutionContextInterface $context) use ($test) { + $previousValue = $context->getValue(); + $previousMetadata = $context->getMetadata(); + $previousPath = $context->getPropertyPath(); + $previousGroup = $context->getGroup(); + $context->validate($value->reference, 'subpath'); + + // context changes shouldn't leak out of the validate() call + $test->assertSame($previousValue, $context->getValue()); + $test->assertSame($previousMetadata, $context->getMetadata()); + $test->assertSame($previousPath, $context->getPropertyPath()); + $test->assertSame($previousGroup, $context->getGroup()); }; $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { @@ -167,8 +178,19 @@ abstract class AbstractLegacyApiTest extends AbstractValidatorTest $entity = new Entity(); $entity->reference = new Reference(); - $callback1 = function ($value, ExecutionContextInterface $context) { + $callback1 = function ($value, ExecutionContextInterface $context) use ($test) { + $previousValue = $context->getValue(); + $previousMetadata = $context->getMetadata(); + $previousPath = $context->getPropertyPath(); + $previousGroup = $context->getGroup(); + $context->validate(array('key' => $value->reference), 'subpath'); + + // context changes shouldn't leak out of the validate() call + $test->assertSame($previousValue, $context->getValue()); + $test->assertSame($previousMetadata, $context->getMetadata()); + $test->assertSame($previousPath, $context->getPropertyPath()); + $test->assertSame($previousGroup, $context->getGroup()); }; $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) { diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index 3738dab069..581b2f17f5 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -96,6 +96,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface { $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; + $previousValue = $this->context->getValue(); + $previousObject = $this->context->getObject(); + $previousMetadata = $this->context->getMetadata(); + $previousPath = $this->context->getPropertyPath(); + $previousGroup = $this->context->getGroup(); + // If explicit constraints are passed, validate the value against // those constraints if (null !== $constraints) { @@ -120,6 +126,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $this->context ); + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -134,6 +143,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $this->context ); + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -148,6 +160,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $this->context ); + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -180,6 +195,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; $cacheKey = spl_object_hash($object); + $previousValue = $this->context->getValue(); + $previousObject = $this->context->getObject(); + $previousMetadata = $this->context->getMetadata(); + $previousPath = $this->context->getPropertyPath(); + $previousGroup = $this->context->getGroup(); + foreach ($propertyMetadatas as $propertyMetadata) { $propertyValue = $propertyMetadata->getPropertyValue($object); @@ -196,6 +217,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface ); } + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -221,6 +245,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; $cacheKey = spl_object_hash($object); + $previousValue = $this->context->getValue(); + $previousObject = $this->context->getObject(); + $previousMetadata = $this->context->getMetadata(); + $previousPath = $this->context->getPropertyPath(); + $previousGroup = $this->context->getGroup(); + foreach ($propertyMetadatas as $propertyMetadata) { $this->validateGenericNode( $value, @@ -235,6 +265,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface ); } + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; }