diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 740e23b09051e..214f671358157 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG the `Url::CHECK_DNS_TYPE_*` constants values and will throw an exception in Symfony 4.0 * added min/max amount of pixels check to `Image` constraint via `minPixels` and `maxPixels` * added a new "propertyPath" option to comparison constraints in order to get the value to compare from an array or object + * added a `dataPath` option to the `Expression` constraint to allow an other way to get `this` from the context 3.3.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Expression.php b/src/Symfony/Component/Validator/Constraints/Expression.php index 3329bd2494028..d95f279aa2636 100644 --- a/src/Symfony/Component/Validator/Constraints/Expression.php +++ b/src/Symfony/Component/Validator/Constraints/Expression.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Validator\Constraints; +use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\RuntimeException; /** * @Annotation @@ -30,6 +32,28 @@ class Expression extends Constraint public $message = 'This value is not valid.'; public $expression; + protected $dataPath; + + /** + * {@inheritdoc} + */ + public function __construct($options = null) + { + parent::__construct($options); + + if ($this->dataPath && !class_exists(PropertyAccess::class)) { + throw new RuntimeException('Unable to use expressions with data path as the Symfony PropertyAccess component is not installed.'); + } + } + + public function __get($option) + { + if ('dataPath' === $option) { + return $this->dataPath; + } + + return parent::__get($option); + } /** * {@inheritdoc} diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php index e2f3139af73b8..2fafa471c80ba 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\RuntimeException; @@ -44,7 +45,12 @@ public function validate($value, Constraint $constraint) $variables = array(); $variables['value'] = $value; - $variables['this'] = $this->context->getObject(); + + if ($constraint->dataPath) { + $variables['this'] = PropertyAccess::createPropertyAccessor()->getValue($this->context, $constraint->dataPath); + } else { + $variables['this'] = $this->context->getObject(); + } if (!$this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) { $this->context->buildViolation($constraint->message) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php index e4316243e5580..4dc9737cd97f3 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php @@ -235,4 +235,17 @@ public function testExpressionLanguageUsage() $this->assertTrue($used, 'Failed asserting that custom ExpressionLanguage instance is used.'); } + + public function testExpressionWithCustomDataPath() + { + $constraint = new Expression(array('expression' => 'value <= this["dateEnd"]', 'dataPath' => 'root[data]')); + + $this->setRoot(array('data' => array('dateEnd' => '2011-06-07', 'dateStart' => '2011-06-05'))); + $this->setPropertyPath(''); + $this->setProperty(null, 'property'); + + $this->validator->validate('2011-06-05', $constraint); + + $this->assertNoViolation(); + } }