Skip to content

Commit

Permalink
[Validator] Simplified ExecutionContext::addViolation(), added Execut…
Browse files Browse the repository at this point in the history
…ionContext::addViolationAt()
  • Loading branch information
webmozart committed Jan 31, 2012
1 parent f77fd41 commit fe85bbd
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 19 deletions.
Expand Up @@ -68,21 +68,19 @@ public function isValid($value, Constraint $constraint)
$walker->walkConstraint($constr, $value[$field], $group, $propertyPath.'['.$field.']');
}
} elseif (!$fieldConstraint instanceof Optional && !$constraint->allowMissingFields) {
$this->context->setPropertyPath($propertyPath.'['.$field.']');
$this->context->addViolation($constraint->missingFieldsMessage, array(
$this->context->addViolationAt($propertyPath.'['.$field.']', $constraint->missingFieldsMessage, array(
'{{ field }}' => '"'.$field.'"'
), $value);
), null);
$valid = false;
}
}

if (!$constraint->allowExtraFields) {
foreach ($value as $field => $fieldValue) {
if (!isset($constraint->fields[$field])) {
$this->context->setPropertyPath($propertyPath.'['.$field.']');
$this->context->addViolation($constraint->extraFieldsMessage, array(
$this->context->addViolationAt($propertyPath.'['.$field.']', $constraint->extraFieldsMessage, array(
'{{ field }}' => '"'.$field.'"'
), $value);
), $fieldValue);
$valid = false;
}
}
Expand Down
32 changes: 28 additions & 4 deletions src/Symfony/Component/Validator/ExecutionContext.php
Expand Up @@ -14,13 +14,13 @@
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
* items and keep track of the violations.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @api
*/
Expand All @@ -30,6 +30,7 @@ class ExecutionContext
protected $propertyPath;
protected $class;
protected $property;
protected $value;
protected $group;
protected $violations;
protected $graphWalker;
Expand All @@ -55,14 +56,27 @@ public function __clone()
/**
* @api
*/
public function addViolation($message, array $params, $invalidValue)
public function addViolation($message, array $params = array(), $invalidValue = null)
{
$this->violations->add(new ConstraintViolation(
$message,
$params,
$this->root,
$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
));
}

Expand Down Expand Up @@ -111,6 +125,16 @@ public function getCurrentProperty()
return $this->property;
}

public function setCurrentValue($value)
{
$this->value = $value;
}

public function getCurrentValue()
{
return $this->value;
}

public function setGroup($group)
{
$this->group = $group;
Expand Down
4 changes: 3 additions & 1 deletion src/Symfony/Component/Validator/GraphWalker.php
Expand Up @@ -168,6 +168,7 @@ public function walkConstraint(Constraint $constraint, $value, $group, $property
{
$validator = $this->validatorFactory->getInstance($constraint);

$this->context->setCurrentValue($value);
$this->context->setPropertyPath($propertyPath);
$this->context->setGroup($group);

Expand All @@ -184,9 +185,10 @@ public function walkConstraint(Constraint $constraint, $value, $group, $property
// Resetting the property path. This is needed because some
// validators, like CollectionValidator, use the walker internally
// and so change the context.
$this->context->setCurrentValue($value);
$this->context->setPropertyPath($propertyPath);

$this->context->addViolation($messageTemplate, $messageParams, $value);
$this->context->addViolation($messageTemplate, $messageParams);
}
}
}
Expand Down
Expand Up @@ -127,13 +127,14 @@ public function testWalkMultipleConstraints()

public function testExtraFieldsDisallowed()
{
$this->context->setPropertyPath('bar');

$data = $this->prepareTestData(array(
'foo' => 5,
'baz' => 6,
));

$this->context->setCurrentValue($data);
$this->context->setPropertyPath('bar');

$this->assertFalse($this->validator->isValid($data, new Collection(array(
'fields' => array(
'foo' => new Min(4),
Expand All @@ -146,7 +147,7 @@ public function testExtraFieldsDisallowed()
array('{{ field }}' => '"baz"'),
'Root',
'bar[baz]',
$data
6
),
)), $this->context->getViolations());
}
Expand Down Expand Up @@ -184,8 +185,9 @@ public function testExtraFieldsAllowed()

public function testMissingFieldsDisallowed()
{
$this->context->setPropertyPath('bar');
$data = $this->prepareTestData(array());
$this->context->setCurrentValue($data);
$this->context->setPropertyPath('bar');

$this->assertFalse($this->validator->isValid($data, new Collection(array(
'fields' => array(
Expand All @@ -199,7 +201,7 @@ public function testMissingFieldsDisallowed()
array('{{ field }}' => '"foo"'),
'Root',
'bar[foo]',
$data
null
),
)), $this->context->getViolations());
}
Expand Down
118 changes: 116 additions & 2 deletions tests/Symfony/Tests/Component/Validator/ExecutionContextTest.php
Expand Up @@ -11,6 +11,10 @@

namespace Symfony\Tests\Component\Validator;

use Symfony\Component\Validator\ConstraintViolation;

use Symfony\Component\Validator\ConstraintViolationList;

use Symfony\Component\Validator\ExecutionContext;

class ExecutionContextTest extends \PHPUnit_Framework_TestCase
Expand Down Expand Up @@ -43,9 +47,119 @@ public function testClone()
public function testAddViolation()
{
$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()
Expand Down
5 changes: 4 additions & 1 deletion tests/Symfony/Tests/Component/Validator/GraphWalkerTest.php
Expand Up @@ -58,9 +58,11 @@ public function testWalkObjectUpdatesContext()
{
$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($entity, $this->getContext()->getCurrentValue());
}

public function testWalkObjectValidatesConstraints()
Expand Down Expand Up @@ -220,6 +222,7 @@ public function testWalkPropertyUpdatesContext()

$this->assertEquals('Symfony\Tests\Component\Validator\Fixtures\Entity', $this->getContext()->getCurrentClass());
$this->assertEquals('firstName', $this->getContext()->getCurrentProperty());
$this->assertEquals('value', $this->getContext()->getCurrentValue());
}

public function testWalkPropertyValueValidatesConstraints()
Expand Down

0 comments on commit fe85bbd

Please sign in to comment.