Skip to content

[Validator] Made it possible (again) to pass a class name to validatePropertyValue() #11498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 4, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,18 @@ public function validate($value, Constraint $constraint)
$variables['value'] = $value;
$variables['this'] = $value;
} else {
// Extract the object that the property belongs to from the object
// graph
$path = new PropertyPath($this->context->getPropertyPath());
$parentPath = $path->getParent();
$root = $this->context->getRoot();

$variables['value'] = $value;
$variables['this'] = $parentPath ? $this->getPropertyAccessor()->getValue($root, $parentPath) : $root;

if (is_object($root)) {
// Extract the object that the property belongs to from the object
// graph
$path = new PropertyPath($this->context->getPropertyPath());
$parentPath = $path->getParent();
$variables['this'] = $parentPath ? $this->getPropertyAccessor()->getValue($root, $parentPath) : $root;
} else {
$variables['this'] = null;
}
}

if (!$this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,60 @@ public function testFailingExpressionAtNestedPropertyLevel()

$this->validator->validate('2', $constraint);
}

/**
* When validatePropertyValue() is called with a class name
* https://github.com/symfony/symfony/pull/11498
*/
public function testSucceedingExpressionAtPropertyLevelWithoutRoot()
{
$constraint = new Expression('value == "1"');

$this->context->expects($this->any())
->method('getPropertyName')
->will($this->returnValue('property'));

$this->context->expects($this->any())
->method('getPropertyPath')
->will($this->returnValue(''));

$this->context->expects($this->any())
->method('getRoot')
->will($this->returnValue('1'));

$this->context->expects($this->never())
->method('addViolation');

$this->validator->validate('1', $constraint);
}

/**
* When validatePropertyValue() is called with a class name
* https://github.com/symfony/symfony/pull/11498
*/
public function testFailingExpressionAtPropertyLevelWithoutRoot()
{
$constraint = new Expression(array(
'expression' => 'value == "1"',
'message' => 'myMessage',
));

$this->context->expects($this->any())
->method('getPropertyName')
->will($this->returnValue('property'));

$this->context->expects($this->any())
->method('getPropertyPath')
->will($this->returnValue(''));

$this->context->expects($this->any())
->method('getRoot')
->will($this->returnValue('2'));

$this->context->expects($this->once())
->method('addViolation')
->with('myMessage');

$this->validator->validate('2', $constraint);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,57 @@ public function testValidatePropertyValue()
$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.
*
Expand Down
8 changes: 6 additions & 2 deletions src/Symfony/Component/Validator/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public function validateProperty($containingValue, $property, $groups = null)
*/
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) {
Expand All @@ -153,13 +153,17 @@ public function validatePropertyValue($containingValue, $property, $value, $grou
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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,16 @@ public function validateProperty($object, $propertyName, $groups = null);
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ public function validateProperty($object, $propertyName, $groups = null)
$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();
Expand All @@ -209,7 +210,7 @@ public function validateProperty($object, $propertyName, $groups = null)
$object,
$cacheKey.':'.$propertyName,
$propertyMetadata,
PropertyPath::append($this->defaultPropertyPath, $propertyName),
$propertyPath,
$groups,
null,
TraversalStrategy::IMPLICIT,
Expand All @@ -226,9 +227,9 @@ public function validateProperty($object, $propertyName, $groups = null)
/**
* {@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
Expand All @@ -243,7 +244,17 @@ public function validatePropertyValue($object, $propertyName, $value, $groups =

$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();
Expand All @@ -257,7 +268,7 @@ public function validatePropertyValue($object, $propertyName, $value, $groups =
$object,
$cacheKey.':'.$propertyName,
$propertyMetadata,
PropertyPath::append($this->defaultPropertyPath, $propertyName),
$propertyPath,
$groups,
null,
TraversalStrategy::IMPLICIT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,11 @@ public function validateProperty($object, $propertyName, $groups = null)
/**
* {@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();
}
}
14 changes: 7 additions & 7 deletions src/Symfony/Component/Validator/Validator/ValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,18 @@ public function validateProperty($object, $propertyName, $groups = null);
* 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.
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Validator/ValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function validateProperty($containingValue, $property, $groups = null);
* 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.
Expand Down