[Validator] Made sure that context changes don't leak out of (Contextual)ValidatorInterface

This commit is contained in:
Bernhard Schussek 2014-07-17 17:54:00 +02:00
parent 2f7b702e3b
commit 91bf2774a2
5 changed files with 87 additions and 6 deletions

View File

@ -147,7 +147,7 @@ class ExecutionContext implements ExecutionContextInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setNode($value, $object, MetadataInterface $metadata, $propertyPath) public function setNode($value, $object, MetadataInterface $metadata = null, $propertyPath)
{ {
$this->value = $value; $this->value = $value;
$this->object = $object; $this->object = $object;

View File

@ -124,7 +124,7 @@ interface ExecutionContextInterface extends LegacyExecutionContextInterface
* @internal Used by the validator engine. Should not be called by user * @internal Used by the validator engine. Should not be called by user
* code. * code.
*/ */
public function setNode($value, $object, MetadataInterface $metadata, $propertyPath); public function setNode($value, $object, MetadataInterface $metadata = null, $propertyPath);
/** /**
* Sets the currently validated group. * Sets the currently validated group.

View File

@ -193,13 +193,26 @@ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest
$entity = new Entity(); $entity = new Entity();
$entity->reference = new Reference(); $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 $context
->getValidator() ->getValidator()
->inContext($context) ->inContext($context)
->atPath('subpath') ->atPath('subpath')
->validate($value->reference) ->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) { $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
@ -244,13 +257,26 @@ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest
$entity = new Entity(); $entity = new Entity();
$entity->reference = new Reference(); $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 $context
->getValidator() ->getValidator()
->inContext($context) ->inContext($context)
->atPath('subpath') ->atPath('subpath')
->validate(array('key' => $value->reference)) ->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) { $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {

View File

@ -120,8 +120,19 @@ abstract class AbstractLegacyApiTest extends AbstractValidatorTest
$entity = new Entity(); $entity = new Entity();
$entity->reference = new Reference(); $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->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) { $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
@ -167,8 +178,19 @@ abstract class AbstractLegacyApiTest extends AbstractValidatorTest
$entity = new Entity(); $entity = new Entity();
$entity->reference = new Reference(); $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->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) { $callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {

View File

@ -96,6 +96,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
{ {
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; $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 // If explicit constraints are passed, validate the value against
// those constraints // those constraints
if (null !== $constraints) { if (null !== $constraints) {
@ -120,6 +126,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$this->context $this->context
); );
$this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath);
$this->context->setGroup($previousGroup);
return $this; return $this;
} }
@ -134,6 +143,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$this->context $this->context
); );
$this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath);
$this->context->setGroup($previousGroup);
return $this; return $this;
} }
@ -148,6 +160,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$this->context $this->context
); );
$this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath);
$this->context->setGroup($previousGroup);
return $this; return $this;
} }
@ -180,6 +195,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
$cacheKey = spl_object_hash($object); $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) { foreach ($propertyMetadatas as $propertyMetadata) {
$propertyValue = $propertyMetadata->getPropertyValue($object); $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; return $this;
} }
@ -221,6 +245,12 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
$cacheKey = spl_object_hash($object); $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) { foreach ($propertyMetadatas as $propertyMetadata) {
$this->validateGenericNode( $this->validateGenericNode(
$value, $value,
@ -235,6 +265,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
); );
} }
$this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath);
$this->context->setGroup($previousGroup);
return $this; return $this;
} }