diff --git a/src/Symfony/Component/Validator/Context/ExecutionContext.php b/src/Symfony/Component/Validator/Context/ExecutionContext.php index 542ea336585f..3bd423fb6590 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContext.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContext.php @@ -18,7 +18,6 @@ use Symfony\Component\Validator\Exception\BadMethodCallException; use Symfony\Component\Validator\Mapping\MetadataInterface; use Symfony\Component\Validator\Mapping\PropertyMetadataInterface; -use Symfony\Component\Validator\ObjectInitializerInterface; use Symfony\Component\Validator\Util\PropertyPath; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Validator\Violation\ConstraintViolationBuilder; @@ -147,7 +146,7 @@ public function __construct(ValidatorInterface $validator, $root, TranslatorInte /** * {@inheritdoc} */ - public function setNode($value, $object, MetadataInterface $metadata, $propertyPath) + public function setNode($value, $object, MetadataInterface $metadata = null, $propertyPath) { $this->value = $value; $this->object = $object; @@ -370,14 +369,7 @@ public function isConstraintValidated($cacheKey, $constraintHash) } /** - * Marks that an object was initialized. - * - * @param string $cacheKey The hash of the object - * - * @internal Used by the validator engine. Should not be called by user - * code. - * - * @see ObjectInitializerInterface + * {@inheritdoc} */ public function markObjectAsInitialized($cacheKey) { @@ -385,16 +377,7 @@ public function markObjectAsInitialized($cacheKey) } /** - * Returns whether an object was initialized. - * - * @param string $cacheKey The hash of the object - * - * @return bool Whether the object was already initialized - * - * @internal Used by the validator engine. Should not be called by user - * code. - * - * @see ObjectInitializerInterface + * {@inheritdoc} */ public function isObjectInitialized($cacheKey) { diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index 37518fdf7a68..d2527f4694ee 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -116,15 +116,15 @@ public function getObject(); /** * Sets the currently validated value. * - * @param mixed $value The validated value - * @param object|null $object The currently validated object - * @param MetadataInterface $metadata The validation metadata - * @param string $propertyPath The property path to the current value + * @param mixed $value The validated value + * @param object|null $object The currently validated object + * @param MetadataInterface|null $metadata The validation metadata + * @param string $propertyPath The property path to the current value * * @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. @@ -186,4 +186,30 @@ public function markConstraintAsValidated($cacheKey, $constraintHash); * code. */ public function isConstraintValidated($cacheKey, $constraintHash); + + /** + * Marks that an object was initialized. + * + * @param string $cacheKey The hash of the object + * + * @internal Used by the validator engine. Should not be called by user + * code. + * + * @see ObjectInitializerInterface + */ + public function markObjectAsInitialized($cacheKey); + + /** + * Returns whether an object was initialized. + * + * @param string $cacheKey The hash of the object + * + * @return bool Whether the object was already initialized + * + * @internal Used by the validator engine. Should not be called by user + * code. + * + * @see ObjectInitializerInterface + */ + public function isObjectInitialized($cacheKey); } diff --git a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php index 02fefda5f042..e920da9a7219 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php @@ -193,13 +193,26 @@ public function testValidateInContext() $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 @@ public function testValidateArrayInContext() $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 56e94313bed3..53b935f5c373 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php @@ -120,8 +120,19 @@ public function testValidateInContext() $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 @@ public function testValidateArrayInContext() $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 3738dab069a0..581b2f17f50f 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -96,6 +96,12 @@ public function validate($value, $constraints = null, $groups = null) { $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 @@ public function validate($value, $constraints = null, $groups = null) $this->context ); + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -134,6 +143,9 @@ public function validate($value, $constraints = null, $groups = null) $this->context ); + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -148,6 +160,9 @@ public function validate($value, $constraints = null, $groups = null) $this->context ); + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -180,6 +195,12 @@ public function validateProperty($object, $propertyName, $groups = null) $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 @@ public function validateProperty($object, $propertyName, $groups = null) ); } + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; } @@ -221,6 +245,12 @@ public function validatePropertyValue($object, $propertyName, $value, $groups = $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 @@ public function validatePropertyValue($object, $propertyName, $value, $groups = ); } + $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); + $this->context->setGroup($previousGroup); + return $this; }