[Validator] Simplified ExecutionContext::addViolation(), added ExecutionContext::addViolationAt()

This commit is contained in:
Bernhard Schussek 2012-01-31 18:42:14 +01:00
parent f77fd416c8
commit fe85bbdb06
6 changed files with 162 additions and 19 deletions

View File

@ -68,10 +68,9 @@ class CollectionValidator extends ConstraintValidator
$walker->walkConstraint($constr, $value[$field], $group, $propertyPath.'['.$field.']'); $walker->walkConstraint($constr, $value[$field], $group, $propertyPath.'['.$field.']');
} }
} elseif (!$fieldConstraint instanceof Optional && !$constraint->allowMissingFields) { } elseif (!$fieldConstraint instanceof Optional && !$constraint->allowMissingFields) {
$this->context->setPropertyPath($propertyPath.'['.$field.']'); $this->context->addViolationAt($propertyPath.'['.$field.']', $constraint->missingFieldsMessage, array(
$this->context->addViolation($constraint->missingFieldsMessage, array(
'{{ field }}' => '"'.$field.'"' '{{ field }}' => '"'.$field.'"'
), $value); ), null);
$valid = false; $valid = false;
} }
} }
@ -79,10 +78,9 @@ class CollectionValidator extends ConstraintValidator
if (!$constraint->allowExtraFields) { if (!$constraint->allowExtraFields) {
foreach ($value as $field => $fieldValue) { foreach ($value as $field => $fieldValue) {
if (!isset($constraint->fields[$field])) { if (!isset($constraint->fields[$field])) {
$this->context->setPropertyPath($propertyPath.'['.$field.']'); $this->context->addViolationAt($propertyPath.'['.$field.']', $constraint->extraFieldsMessage, array(
$this->context->addViolation($constraint->extraFieldsMessage, array(
'{{ field }}' => '"'.$field.'"' '{{ field }}' => '"'.$field.'"'
), $value); ), $fieldValue);
$valid = false; $valid = false;
} }
} }

View File

@ -14,13 +14,13 @@ namespace Symfony\Component\Validator;
use Symfony\Component\Validator\Mapping\ClassMetadataFactoryInterface; use Symfony\Component\Validator\Mapping\ClassMetadataFactoryInterface;
/** /**
* The central object representing a single validation process. * Stores the state of the current node in the validation graph.
* *
* This object is used by the GraphWalker to initialize validation of different * This object is used by the GraphWalker to initialize validation of different
* items and keep track of the violations. * items and keep track of the violations.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bernhard.schussek@symfony.com> * @author Bernhard Schussek <bschussek@gmail.com>
* *
* @api * @api
*/ */
@ -30,6 +30,7 @@ class ExecutionContext
protected $propertyPath; protected $propertyPath;
protected $class; protected $class;
protected $property; protected $property;
protected $value;
protected $group; protected $group;
protected $violations; protected $violations;
protected $graphWalker; protected $graphWalker;
@ -55,14 +56,27 @@ class ExecutionContext
/** /**
* @api * @api
*/ */
public function addViolation($message, array $params, $invalidValue) public function addViolation($message, array $params = array(), $invalidValue = null)
{ {
$this->violations->add(new ConstraintViolation( $this->violations->add(new ConstraintViolation(
$message, $message,
$params, $params,
$this->root, $this->root,
$this->propertyPath, $this->propertyPath,
$invalidValue // check using func_num_args() to allow passing null values
func_num_args() === 3 ? $invalidValue : $this->value
));
}
public function addViolationAt($propertyPath, $message, array $params = array(), $invalidValue = null)
{
$this->violations->add(new ConstraintViolation(
$message,
$params,
$this->root,
$propertyPath,
// check using func_num_args() to allow passing null values
func_num_args() === 4 ? $invalidValue : $this->value
)); ));
} }
@ -111,6 +125,16 @@ class ExecutionContext
return $this->property; return $this->property;
} }
public function setCurrentValue($value)
{
$this->value = $value;
}
public function getCurrentValue()
{
return $this->value;
}
public function setGroup($group) public function setGroup($group)
{ {
$this->group = $group; $this->group = $group;

View File

@ -168,6 +168,7 @@ class GraphWalker
{ {
$validator = $this->validatorFactory->getInstance($constraint); $validator = $this->validatorFactory->getInstance($constraint);
$this->context->setCurrentValue($value);
$this->context->setPropertyPath($propertyPath); $this->context->setPropertyPath($propertyPath);
$this->context->setGroup($group); $this->context->setGroup($group);
@ -184,9 +185,10 @@ class GraphWalker
// Resetting the property path. This is needed because some // Resetting the property path. This is needed because some
// validators, like CollectionValidator, use the walker internally // validators, like CollectionValidator, use the walker internally
// and so change the context. // and so change the context.
$this->context->setCurrentValue($value);
$this->context->setPropertyPath($propertyPath); $this->context->setPropertyPath($propertyPath);
$this->context->addViolation($messageTemplate, $messageParams, $value); $this->context->addViolation($messageTemplate, $messageParams);
} }
} }
} }

View File

@ -127,13 +127,14 @@ abstract class CollectionValidatorTest extends \PHPUnit_Framework_TestCase
public function testExtraFieldsDisallowed() public function testExtraFieldsDisallowed()
{ {
$this->context->setPropertyPath('bar');
$data = $this->prepareTestData(array( $data = $this->prepareTestData(array(
'foo' => 5, 'foo' => 5,
'baz' => 6, 'baz' => 6,
)); ));
$this->context->setCurrentValue($data);
$this->context->setPropertyPath('bar');
$this->assertFalse($this->validator->isValid($data, new Collection(array( $this->assertFalse($this->validator->isValid($data, new Collection(array(
'fields' => array( 'fields' => array(
'foo' => new Min(4), 'foo' => new Min(4),
@ -146,7 +147,7 @@ abstract class CollectionValidatorTest extends \PHPUnit_Framework_TestCase
array('{{ field }}' => '"baz"'), array('{{ field }}' => '"baz"'),
'Root', 'Root',
'bar[baz]', 'bar[baz]',
$data 6
), ),
)), $this->context->getViolations()); )), $this->context->getViolations());
} }
@ -184,8 +185,9 @@ abstract class CollectionValidatorTest extends \PHPUnit_Framework_TestCase
public function testMissingFieldsDisallowed() public function testMissingFieldsDisallowed()
{ {
$this->context->setPropertyPath('bar');
$data = $this->prepareTestData(array()); $data = $this->prepareTestData(array());
$this->context->setCurrentValue($data);
$this->context->setPropertyPath('bar');
$this->assertFalse($this->validator->isValid($data, new Collection(array( $this->assertFalse($this->validator->isValid($data, new Collection(array(
'fields' => array( 'fields' => array(
@ -199,7 +201,7 @@ abstract class CollectionValidatorTest extends \PHPUnit_Framework_TestCase
array('{{ field }}' => '"foo"'), array('{{ field }}' => '"foo"'),
'Root', 'Root',
'bar[foo]', 'bar[foo]',
$data null
), ),
)), $this->context->getViolations()); )), $this->context->getViolations());
} }

View File

@ -11,6 +11,10 @@
namespace Symfony\Tests\Component\Validator; namespace Symfony\Tests\Component\Validator;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\ExecutionContext; use Symfony\Component\Validator\ExecutionContext;
class ExecutionContextTest extends \PHPUnit_Framework_TestCase class ExecutionContextTest extends \PHPUnit_Framework_TestCase
@ -43,9 +47,119 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase
public function testAddViolation() public function testAddViolation()
{ {
$this->assertCount(0, $this->context->getViolations()); $this->assertCount(0, $this->context->getViolations());
$this->context->addViolation('', array(), '');
$this->assertCount(1, $this->context->getViolations()); $this->context->setPropertyPath('foo.bar');
$this->context->addViolation('Error', array('foo' => 'bar'), 'invalid');
$this->assertEquals(new ConstraintViolationList(array(
new ConstraintViolation(
'Error',
array('foo' => 'bar'),
'Root',
'foo.bar',
'invalid'
),
)), $this->context->getViolations());
}
public function testAddViolationUsesPreconfiguredValueIfNotPassed()
{
$this->assertCount(0, $this->context->getViolations());
$this->context->setPropertyPath('foo.bar');
$this->context->setCurrentValue('invalid');
$this->context->addViolation('Error');
$this->assertEquals(new ConstraintViolationList(array(
new ConstraintViolation(
'Error',
array(),
'Root',
'foo.bar',
'invalid'
),
)), $this->context->getViolations());
}
public function testAddViolationUsesPassedNulValue()
{
$this->assertCount(0, $this->context->getViolations());
$this->context->setPropertyPath('foo.bar');
$this->context->setCurrentValue('invalid');
// passed null value should override preconfigured value "invalid"
$this->context->addViolation('Error', array('foo' => 'bar'), null);
$this->assertEquals(new ConstraintViolationList(array(
new ConstraintViolation(
'Error',
array('foo' => 'bar'),
'Root',
'foo.bar',
null
),
)), $this->context->getViolations());
}
public function testAddViolationAt()
{
$this->assertCount(0, $this->context->getViolations());
$this->context->setPropertyPath('foo.bar');
// override preconfigured property path
$this->context->addViolationAt('bar.baz', 'Error', array('foo' => 'bar'), 'invalid');
$this->assertEquals(new ConstraintViolationList(array(
new ConstraintViolation(
'Error',
array('foo' => 'bar'),
'Root',
'bar.baz',
'invalid'
),
)), $this->context->getViolations());
}
public function testAddViolationAtUsesPreconfiguredValueIfNotPassed()
{
$this->assertCount(0, $this->context->getViolations());
$this->context->setPropertyPath('foo.bar');
$this->context->setCurrentValue('invalid');
$this->context->addViolationAt('bar.baz', 'Error');
$this->assertEquals(new ConstraintViolationList(array(
new ConstraintViolation(
'Error',
array(),
'Root',
'bar.baz',
'invalid'
),
)), $this->context->getViolations());
}
public function testAddViolationAtUsesPassedNulValue()
{
$this->assertCount(0, $this->context->getViolations());
$this->context->setPropertyPath('foo.bar');
$this->context->setCurrentValue('invalid');
// passed null value should override preconfigured value "invalid"
$this->context->addViolationAt('bar.baz', 'Error', array('foo' => 'bar'), null);
$this->assertEquals(new ConstraintViolationList(array(
new ConstraintViolation(
'Error',
array('foo' => 'bar'),
'Root',
'bar.baz',
null
),
)), $this->context->getViolations());
} }
public function testGetViolations() public function testGetViolations()

View File

@ -58,9 +58,11 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase
{ {
$this->metadata->addConstraint(new ConstraintA()); $this->metadata->addConstraint(new ConstraintA());
$this->walker->walkObject($this->metadata, new Entity(), 'Default', ''); $entity = new Entity();
$this->walker->walkObject($this->metadata, $entity, 'Default', '');
$this->assertEquals('Symfony\Tests\Component\Validator\Fixtures\Entity', $this->getContext()->getCurrentClass()); $this->assertEquals('Symfony\Tests\Component\Validator\Fixtures\Entity', $this->getContext()->getCurrentClass());
$this->assertEquals($entity, $this->getContext()->getCurrentValue());
} }
public function testWalkObjectValidatesConstraints() public function testWalkObjectValidatesConstraints()
@ -220,6 +222,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('Symfony\Tests\Component\Validator\Fixtures\Entity', $this->getContext()->getCurrentClass()); $this->assertEquals('Symfony\Tests\Component\Validator\Fixtures\Entity', $this->getContext()->getCurrentClass());
$this->assertEquals('firstName', $this->getContext()->getCurrentProperty()); $this->assertEquals('firstName', $this->getContext()->getCurrentProperty());
$this->assertEquals('value', $this->getContext()->getCurrentValue());
} }
public function testWalkPropertyValueValidatesConstraints() public function testWalkPropertyValueValidatesConstraints()