Skip to content

Commit d4ebbfd

Browse files
webmozartfabpot
authored andcommitted
[Validator] Renamed Condition to Expression and added possibility to set it onto properties
1 parent a3b3a78 commit d4ebbfd

File tree

13 files changed

+405
-65
lines changed

13 files changed

+405
-65
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public function load(array $configs, ContainerBuilder $container)
4848
// will be used and everything will still work as expected.
4949
$loader->load('translation.xml');
5050

51+
// Property access is used by both the Form and the Validator component
52+
$loader->load('property_access.xml');
53+
5154
$loader->load('debug_prod.xml');
5255

5356
if ($container->getParameter('kernel.debug')) {

src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<parameter key="form.factory.class">Symfony\Component\Form\FormFactory</parameter>
1111
<parameter key="form.extension.class">Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension</parameter>
1212
<parameter key="form.type_guesser.validator.class">Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser</parameter>
13-
<parameter key="property_accessor.class">Symfony\Component\PropertyAccess\PropertyAccessor</parameter>
1413
</parameters>
1514

1615
<services>
@@ -54,9 +53,6 @@
5453
<argument type="service" id="validator.mapping.class_metadata_factory" />
5554
</service>
5655

57-
<!-- PropertyAccessor -->
58-
<service id="property_accessor" class="%property_accessor.class%" />
59-
6056
<!-- CoreExtension -->
6157
<service id="form.type.form" class="Symfony\Component\Form\Extension\Core\Type\FormType">
6258
<argument type="service" id="property_accessor"/>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<parameters>
8+
<parameter key="property_accessor.class">Symfony\Component\PropertyAccess\PropertyAccessor</parameter>
9+
</parameters>
10+
11+
<services>
12+
<service id="property_accessor" class="%property_accessor.class%" />
13+
</services>
14+
</container>

src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<parameter key="validator.validator_factory.class">Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory</parameter>
1818
<parameter key="validator.mapping.loader.xml_files_loader.mapping_files" type="collection" />
1919
<parameter key="validator.mapping.loader.yaml_files_loader.mapping_files" type="collection" />
20+
<parameter key="validator.expression.class">Symfony\Component\Validator\Constraints\ExpressionValidator</parameter>
2021
</parameters>
2122

2223
<services>
@@ -63,5 +64,10 @@
6364
<service id="validator.mapping.loader.yaml_files_loader" class="%validator.mapping.loader.yaml_files_loader.class%" public="false">
6465
<argument>%validator.mapping.loader.yaml_files_loader.mapping_files%</argument>
6566
</service>
67+
68+
<service id="validator.expression" class="%validator.expression.class%">
69+
<argument type="service" id="property_accessor" />
70+
<tag name="validator.constraint_validator" alias="validator.expression" />
71+
</service>
6672
</services>
6773
</container>

src/Symfony/Component/Validator/ConstraintValidatorFactory.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,53 @@
1111

1212
namespace Symfony\Component\Validator;
1313

14-
use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
15-
use Symfony\Component\Validator\Constraint;
14+
use Symfony\Component\PropertyAccess\PropertyAccess;
15+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
16+
use Symfony\Component\Validator\Constraints\ExpressionValidator;
1617

1718
/**
1819
* Default implementation of the ConstraintValidatorFactoryInterface.
1920
*
2021
* This enforces the convention that the validatedBy() method on any
2122
* Constrain will return the class name of the ConstraintValidator that
2223
* should validate the Constraint.
24+
*
25+
* @author Bernhard Schussek <bschussek@gmail.com>
2326
*/
2427
class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
2528
{
2629
protected $validators = array();
2730

31+
/**
32+
* @var PropertyAccessorInterface
33+
*/
34+
private $propertyAccessor;
35+
36+
public function __construct(PropertyAccessorInterface $propertyAccessor = null)
37+
{
38+
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
39+
}
40+
2841
/**
2942
* {@inheritDoc}
3043
*/
3144
public function getInstance(Constraint $constraint)
3245
{
3346
$className = $constraint->validatedBy();
3447

35-
if (!isset($this->validators[$className]) || $className === 'Symfony\Component\Validator\Constraints\CollectionValidator') {
36-
$this->validators[$className] = new $className();
48+
// The second condition is a hack that is needed when CollectionValidator
49+
// calls itself recursively (Collection constraints can be nested).
50+
// Since the context of the validator is overwritten when initialize()
51+
// is called for the nested constraint, the outer validator is
52+
// acting on the wrong context when the nested validation terminates.
53+
//
54+
// A better solution - which should be approached in Symfony 3.0 - is to
55+
// remove the initialize() method and pass the context as last argument
56+
// to validate() instead.
57+
if (!isset($this->validators[$className]) || 'Symfony\Component\Validator\Constraints\CollectionValidator' === $className) {
58+
$this->validators[$className] = 'validator.expression' === $className
59+
? new ExpressionValidator($this->propertyAccessor)
60+
: new $className();
3761
}
3862

3963
return $this->validators[$className];

src/Symfony/Component/Validator/Constraints/ConditionValidator.php

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/Symfony/Component/Validator/Constraints/Condition.php renamed to src/Symfony/Component/Validator/Constraints/Expression.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,42 @@
1717
* @Annotation
1818
*
1919
* @author Fabien Potencier <fabien@symfony.com>
20+
* @author Bernhard Schussek <bschussek@gmail.com>
2021
*/
21-
class Condition extends Constraint
22+
class Expression extends Constraint
2223
{
2324
public $message = 'This value is not valid.';
24-
public $condition;
25+
public $expression;
2526

2627
/**
2728
* {@inheritDoc}
2829
*/
2930
public function getDefaultOption()
3031
{
31-
return 'condition';
32+
return 'expression';
3233
}
3334

3435
/**
3536
* {@inheritDoc}
3637
*/
3738
public function getRequiredOptions()
3839
{
39-
return array('condition');
40+
return array('expression');
4041
}
42+
4143
/**
4244
* {@inheritDoc}
4345
*/
4446
public function getTargets()
4547
{
46-
return self::CLASS_CONSTRAINT;
48+
return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT);
49+
}
50+
51+
/**
52+
* {@inheritDoc}
53+
*/
54+
public function validatedBy()
55+
{
56+
return 'validator.expression';
4757
}
4858
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Constraints;
13+
14+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
15+
use Symfony\Component\PropertyAccess\PropertyPath;
16+
use Symfony\Component\Validator\Constraint;
17+
use Symfony\Component\Validator\ConstraintValidator;
18+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
19+
use Symfony\Component\Validator\Exception\RuntimeException;
20+
21+
/**
22+
* @author Fabien Potencier <fabien@symfony.com>
23+
* @author Bernhard Schussek <bschussek@symfony.com>
24+
*/
25+
class ExpressionValidator extends ConstraintValidator
26+
{
27+
/**
28+
* @var PropertyAccessorInterface
29+
*/
30+
private $propertyAccessor;
31+
32+
/**
33+
* @var ExpressionLanguage
34+
*/
35+
private $expressionLanguage;
36+
37+
public function __construct(PropertyAccessorInterface $propertyAccessor)
38+
{
39+
$this->propertyAccessor = $propertyAccessor;
40+
}
41+
42+
/**
43+
* {@inheritDoc}
44+
*/
45+
public function validate($value, Constraint $constraint)
46+
{
47+
if (null === $value || '' === $value) {
48+
return;
49+
}
50+
51+
$variables = array();
52+
53+
if (null === $this->context->getPropertyName()) {
54+
$variables['this'] = $value;
55+
} else {
56+
// Extract the object that the property belongs to from the object
57+
// graph
58+
$path = new PropertyPath($this->context->getPropertyPath());
59+
$parentPath = $path->getParent();
60+
$root = $this->context->getRoot();
61+
62+
$variables['value'] = $value;
63+
$variables['this'] = $parentPath ? $this->propertyAccessor->getValue($root, $parentPath) : $root;
64+
}
65+
66+
if (!$this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) {
67+
$this->context->addViolation($constraint->message);
68+
}
69+
}
70+
71+
private function getExpressionLanguage()
72+
{
73+
if (null === $this->expressionLanguage) {
74+
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
75+
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
76+
}
77+
$this->expressionLanguage = new ExpressionLanguage();
78+
}
79+
80+
return $this->expressionLanguage;
81+
}
82+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Exception;
13+
14+
/**
15+
* Base RuntimeException for the Validator component.
16+
*
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
class RuntimeException extends \RuntimeException implements ExceptionInterface
20+
{
21+
}

0 commit comments

Comments
 (0)