[Validator] Fixed: Made it possible (again) to pass a class name to Validator::validatePropertyValue()

This commit is contained in:
Bernhard Schussek 2014-07-28 16:24:30 +02:00
parent 7e175ef8f3
commit ef6f5f50c5
7 changed files with 92 additions and 25 deletions

View File

@ -904,6 +904,57 @@ abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase
$this->assertNull($violations[0]->getCode());
}
public function testValidatePropertyValueWithClassName()
{
$test = $this;
$callback1 = function ($value, ExecutionContextInterface $context) use ($test) {
$propertyMetadatas = $test->metadata->getPropertyMetadata('firstName');
$test->assertSame($test::ENTITY_CLASS, $context->getClassName());
$test->assertSame('firstName', $context->getPropertyName());
$test->assertSame('', $context->getPropertyPath());
$test->assertSame('Group', $context->getGroup());
$test->assertSame($propertyMetadatas[0], $context->getMetadata());
$test->assertSame('Bernhard', $context->getRoot());
$test->assertSame('Bernhard', $context->getValue());
$test->assertSame('Bernhard', $value);
$context->addViolation('Message %param%', array('%param%' => 'value'));
};
$callback2 = function ($value, ExecutionContextInterface $context) {
$context->addViolation('Other violation');
};
$this->metadata->addPropertyConstraint('firstName', new Callback(array(
'callback' => $callback1,
'groups' => 'Group',
)));
$this->metadata->addPropertyConstraint('lastName', new Callback(array(
'callback' => $callback2,
'groups' => 'Group',
)));
$violations = $this->validatePropertyValue(
self::ENTITY_CLASS,
'firstName',
'Bernhard',
'Group'
);
/** @var ConstraintViolationInterface[] $violations */
$this->assertCount(1, $violations);
$this->assertSame('Message value', $violations[0]->getMessage());
$this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
$this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters());
$this->assertSame('', $violations[0]->getPropertyPath());
$this->assertSame('Bernhard', $violations[0]->getRoot());
$this->assertSame('Bernhard', $violations[0]->getInvalidValue());
$this->assertNull($violations[0]->getMessagePluralization());
$this->assertNull($violations[0]->getCode());
}
/**
* Cannot be UnsupportedMetadataException for BC with Symfony < 2.5.
*

View File

@ -142,7 +142,7 @@ class Validator implements ValidatorInterface, Mapping\Factory\MetadataFactoryIn
*/
public function validatePropertyValue($containingValue, $property, $value, $groups = null)
{
$visitor = $this->createVisitor($containingValue);
$visitor = $this->createVisitor(is_object($containingValue) ? $containingValue : $value);
$metadata = $this->metadataFactory->getMetadataFor($containingValue);
if (!$metadata instanceof PropertyMetadataContainerInterface) {
@ -153,13 +153,17 @@ class Validator implements ValidatorInterface, Mapping\Factory\MetadataFactoryIn
throw new ValidatorException(sprintf('The metadata for '.$valueAsString.' does not support properties.'));
}
// If $containingValue is passed as class name, take $value as root
// and start the traversal with an empty property path
$propertyPath = is_object($containingValue) ? $property : '';
foreach ($this->resolveGroups($groups) as $group) {
if (!$metadata->hasPropertyMetadata($property)) {
continue;
}
foreach ($metadata->getPropertyMetadata($property) as $propMeta) {
$propMeta->accept($visitor, $value, $group, $property);
$propMeta->accept($visitor, $value, $group, $propertyPath);
}
}

View File

@ -68,16 +68,16 @@ interface ContextualValidatorInterface
* Validates a value against the constraints specified for an object's
* property.
*
* @param object $object The object
* @param string $propertyName The name of the property
* @param mixed $value The value to validate against the
* property's constraints
* @param array|null $groups The validation groups to validate. If
* none is given, "Default" is assumed
* @param object|string $objectOrClass The object or its class name
* @param string $propertyName The name of the property
* @param mixed $value The value to validate against the
* property's constraints
* @param array|null $groups The validation groups to validate. If
* none is given, "Default" is assumed
*
* @return ContextualValidatorInterface This validator
*/
public function validatePropertyValue($object, $propertyName, $value, $groups = null);
public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null);
/**
* Returns the violations that have been generated so far in the context

View File

@ -194,6 +194,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName);
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
$cacheKey = spl_object_hash($object);
$propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName);
$previousValue = $this->context->getValue();
$previousObject = $this->context->getObject();
@ -209,7 +210,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$object,
$cacheKey.':'.$propertyName,
$propertyMetadata,
PropertyPath::append($this->defaultPropertyPath, $propertyName),
$propertyPath,
$groups,
null,
TraversalStrategy::IMPLICIT,
@ -226,9 +227,9 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
/**
* {@inheritdoc}
*/
public function validatePropertyValue($object, $propertyName, $value, $groups = null)
public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null)
{
$classMetadata = $this->metadataFactory->getMetadataFor($object);
$classMetadata = $this->metadataFactory->getMetadataFor($objectOrClass);
if (!$classMetadata instanceof ClassMetadataInterface) {
// Cannot be UnsupportedMetadataException because of BC with
@ -243,7 +244,17 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName);
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
$cacheKey = spl_object_hash($object);
if (is_object($objectOrClass)) {
$object = $objectOrClass;
$cacheKey = spl_object_hash($objectOrClass);
$propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName);
} else {
// $objectOrClass contains a class name
$object = null;
$cacheKey = null;
$propertyPath = $this->defaultPropertyPath;
}
$previousValue = $this->context->getValue();
$previousObject = $this->context->getObject();
@ -257,7 +268,7 @@ class RecursiveContextualValidator implements ContextualValidatorInterface
$object,
$cacheKey.':'.$propertyName,
$propertyMetadata,
PropertyPath::append($this->defaultPropertyPath, $propertyName),
$propertyPath,
$groups,
null,
TraversalStrategy::IMPLICIT,

View File

@ -130,10 +130,11 @@ class RecursiveValidator implements ValidatorInterface
/**
* {@inheritdoc}
*/
public function validatePropertyValue($object, $propertyName, $value, $groups = null)
public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null)
{
return $this->startContext($object)
->validatePropertyValue($object, $propertyName, $value, $groups)
// If a class name is passed, take $value as root
return $this->startContext(is_object($objectOrClass) ? $objectOrClass : $value)
->validatePropertyValue($objectOrClass, $propertyName, $value, $groups)
->getViolations();
}
}

View File

@ -62,18 +62,18 @@ interface ValidatorInterface extends MetadataFactoryInterface
* Validates a value against the constraints specified for an object's
* property.
*
* @param object $object The object
* @param string $propertyName The name of the property
* @param mixed $value The value to validate against the
* property's constraints
* @param array|null $groups The validation groups to validate. If
* none is given, "Default" is assumed
* @param object|string $objectOrClass The object or its class name
* @param string $propertyName The name of the property
* @param mixed $value The value to validate against the
* property's constraints
* @param array|null $groups The validation groups to validate. If
* none is given, "Default" is assumed
*
* @return ConstraintViolationListInterface A list of constraint violations.
* If the list is empty, validation
* succeeded
*/
public function validatePropertyValue($object, $propertyName, $value, $groups = null);
public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null);
/**
* Starts a new validation context and returns a validator for that context.

View File

@ -68,7 +68,7 @@ interface ValidatorInterface
* The accepted values depend on the {@link MetadataFactoryInterface}
* implementation.
*
* @param string $containingValue The value containing the property.
* @param mixed $containingValue The value containing the property.
* @param string $property The name of the property to validate
* @param string $value The value to validate against the
* constraints of the property.