diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 5d74eba99afb0..ef4ced3890932 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Deprecate the "loose" e-mail validation mode, use "html5" instead * Add the `negate` option to the `Expression` constraint, to inverse the logic of the violation's creation + * Add `is_valid` function to the `Expression` constraint, its behavior is the same as `ValidatorInterface::validate` 6.1 --- diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageProvider.php b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageProvider.php new file mode 100644 index 0000000000000..9048e299f8fce --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageProvider.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\ExpressionLanguage\ExpressionFunction; +use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; + +/** + * @author Ihor Khokhlov + */ +class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface +{ + public function getFunctions(): array + { + return [ + new ExpressionFunction('is_valid', function (...$arguments) { + return sprintf( + '0 === $context->getValidator()->inContext($context)->validate(%s)->getViolations()->count()', + implode(', ', $arguments) + ); + }, function (array $variables, ...$arguments): bool { + return 0 === $variables['context']->getValidator()->inContext($variables['context'])->validate(...$arguments)->getViolations()->count(); + }), + ]; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php index 0e8ecac6b0093..80a924e9debe6 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php @@ -27,6 +27,7 @@ class ExpressionValidator extends ConstraintValidator public function __construct(ExpressionLanguage $expressionLanguage = null) { $this->expressionLanguage = $expressionLanguage; + $this->expressionLanguage?->registerProvider(new ExpressionLanguageProvider()); } /** @@ -41,6 +42,7 @@ public function validate(mixed $value, Constraint $constraint) $variables = $constraint->values; $variables['value'] = $value; $variables['this'] = $this->context->getObject(); + $variables['context'] = $this->context; if ($constraint->negate xor $this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) { $this->context->buildViolation($constraint->message) @@ -54,6 +56,7 @@ private function getExpressionLanguage(): ExpressionLanguage { if (null === $this->expressionLanguage) { $this->expressionLanguage = new ExpressionLanguage(); + $this->expressionLanguage->registerProvider(new ExpressionLanguageProvider()); } return $this->expressionLanguage; diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageProviderTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageProviderTest.php new file mode 100644 index 0000000000000..add2051e97942 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageProviderTest.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Constraints; + +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\Validator\Constraints\ExpressionLanguageProvider; +use Symfony\Component\Validator\Constraints\ExpressionValidator; +use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\ConstraintViolation; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; + +class ExpressionLanguageProviderTest extends ConstraintValidatorTestCase +{ + protected function createValidator() + { + return new ExpressionValidator(); + } + + /** + * @dataProvider dataProviderCompile + */ + public function testCompile(string $expression, array $names, string $expected) + { + $provider = new ExpressionLanguageProvider(); + + $expressionLanguage = new ExpressionLanguage(); + $expressionLanguage->registerProvider($provider); + + $result = $expressionLanguage->compile($expression, $names); + + $this->assertSame($expected, $result); + } + + public function dataProviderCompile(): array + { + return [ + [ + 'is_valid("foo", constraints)', + ['constraints'], + '0 === $context->getValidator()->inContext($context)->validate("foo", $constraints)->getViolations()->count()', + ], + [ + 'is_valid(this.data, constraints, groups)', + ['this', 'constraints', 'groups'], + '0 === $context->getValidator()->inContext($context)->validate($this->data, $constraints, $groups)->getViolations()->count()', + ], + ]; + } + + public function testEvaluateValid() + { + $constraints = [new Length(['min' => 2, 'max' => 12])]; + + $this->expectValidateValue(0, 'foo', $constraints); + + $expressionLanguage = new ExpressionLanguage(); + $expressionLanguage->registerProvider(new ExpressionLanguageProvider()); + + $this->assertTrue($expressionLanguage->evaluate('is_valid("foo", a)', ['a' => $constraints, 'context' => $this->context])); + } + + public function testEvaluateInvalid() + { + $constraints = [new Length(['min' => 7, 'max' => 12])]; + + $this->expectFailingValueValidation( + 0, + 'foo', + $constraints, + null, + new ConstraintViolation('error_length', '', [], '', '', 'foo', null, 'range') + ); + + $expressionLanguage = new ExpressionLanguage(); + $expressionLanguage->registerProvider(new ExpressionLanguageProvider()); + + $this->assertFalse($expressionLanguage->evaluate('is_valid("foo", a)', ['a' => $constraints, 'context' => $this->context])); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php index 9447648f35a9e..6df36c05315b6 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php @@ -14,6 +14,9 @@ use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\Validator\Constraints\Expression; use Symfony\Component\Validator\Constraints\ExpressionValidator; +use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Validator\Constraints\Range; +use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; use Symfony\Component\Validator\Tests\Fixtures\Annotation\Entity; use Symfony\Component\Validator\Tests\Fixtures\ToString; @@ -304,4 +307,50 @@ public function testViolationOnPass() ->setCode(Expression::EXPRESSION_FAILED_ERROR) ->assertRaised(); } + + public function testIsValidExpression() + { + $constraints = [new NotNull(), new Range(['min' => 2])]; + + $constraint = new Expression( + ['expression' => 'is_valid(this.data, a)', 'values' => ['a' => $constraints]] + ); + + $object = new Entity(); + $object->data = 7; + + $this->setObject($object); + + $this->expectValidateValue(0, $object->data, $constraints); + + $this->validator->validate($object, $constraint); + + $this->assertNoViolation(); + } + + public function testIsValidExpressionInvalid() + { + $constraints = [new Range(['min' => 2, 'max' => 5])]; + + $constraint = new Expression( + ['expression' => 'is_valid(this.data, a)', 'values' => ['a' => $constraints]] + ); + + $object = new Entity(); + $object->data = 7; + + $this->setObject($object); + + $this->expectFailingValueValidation( + 0, + 7, + $constraints, + null, + new ConstraintViolation('error_range', '', [], '', '', 7, null, 'range') + ); + + $this->validator->validate($object, $constraint); + + $this->assertCount(2, $this->context->getViolations()); + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy