From 092d85c947064e793a3a717fe7aabd5cb5e29028 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Thu, 19 Mar 2020 10:54:56 +0100 Subject: [PATCH] [Validator] Add BC layer for notInRangeMessage when min and max are set --- .../Component/Validator/Constraints/Range.php | 20 +++++++ .../Validator/Constraints/RangeValidator.php | 17 +++++- .../Validator/Tests/Constraints/RangeTest.php | 39 ++++++++++++ .../Tests/Constraints/RangeValidatorTest.php | 60 +++++++++++++++++++ 4 files changed, 134 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Range.php b/src/Symfony/Component/Validator/Constraints/Range.php index b713090de7..fd2fc4790e 100644 --- a/src/Symfony/Component/Validator/Constraints/Range.php +++ b/src/Symfony/Component/Validator/Constraints/Range.php @@ -46,6 +46,17 @@ class Range extends Constraint public $max; public $maxPropertyPath; + // BC layer, to be removed in 5.0 + /** + * @internal + */ + public $deprecatedMinMessageSet = false; + + /** + * @internal + */ + public $deprecatedMaxMessageSet = false; + public function __construct($options = null) { if (\is_array($options)) { @@ -60,6 +71,15 @@ class Range extends Constraint if ((isset($options['minPropertyPath']) || isset($options['maxPropertyPath'])) && !class_exists(PropertyAccess::class)) { throw new LogicException(sprintf('The "%s" constraint requires the Symfony PropertyAccess component to use the "minPropertyPath" or "maxPropertyPath" option.', static::class)); } + + if (isset($options['min']) && isset($options['max'])) { + $this->deprecatedMinMessageSet = isset($options['minMessage']); + $this->deprecatedMaxMessageSet = isset($options['maxMessage']); + + if ($this->deprecatedMinMessageSet || $this->deprecatedMaxMessageSet) { + @trigger_error('Since symfony/validator 4.4: "minMessage" and "maxMessage" are deprecated when the "min" and "max" options are both set. Use "notInRangeMessage" instead.', E_USER_DEPRECATED); + } + } } parent::__construct($options); diff --git a/src/Symfony/Component/Validator/Constraints/RangeValidator.php b/src/Symfony/Component/Validator/Constraints/RangeValidator.php index 9b7c40ce5a..91aca9018e 100644 --- a/src/Symfony/Component/Validator/Constraints/RangeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/RangeValidator.php @@ -88,11 +88,24 @@ class RangeValidator extends ConstraintValidator $hasUpperLimit = null !== $max; if ($hasLowerLimit && $hasUpperLimit && ($value < $min || $value > $max)) { - $violationBuilder = $this->context->buildViolation($constraint->notInRangeMessage) + $message = $constraint->notInRangeMessage; + $code = Range::NOT_IN_RANGE_ERROR; + + if ($value < $min && $constraint->deprecatedMinMessageSet) { + $message = $constraint->minMessage; + $code = Range::TOO_LOW_ERROR; + } + + if ($value > $max && $constraint->deprecatedMaxMessageSet) { + $message = $constraint->maxMessage; + $code = Range::TOO_HIGH_ERROR; + } + + $violationBuilder = $this->context->buildViolation($message) ->setParameter('{{ value }}', $this->formatValue($value, self::PRETTY_DATE)) ->setParameter('{{ min }}', $this->formatValue($min, self::PRETTY_DATE)) ->setParameter('{{ max }}', $this->formatValue($max, self::PRETTY_DATE)) - ->setCode(Range::NOT_IN_RANGE_ERROR); + ->setCode($code); if (null !== $constraint->maxPropertyPath) { $violationBuilder->setParameter('{{ max_limit_path }}', $constraint->maxPropertyPath); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php index 052a8ee024..ee99c8deef 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RangeTest.php @@ -40,4 +40,43 @@ class RangeTest extends TestCase $this->expectExceptionMessage('No default option is configured'); new Range('value'); } + + public function provideDeprecationTriggeredIfMinMaxAndMinMessageOrMaxMessageSet(): array + { + return [ + [['min' => 1, 'max' => 10, 'minMessage' => 'my_min_message'], true, false], + [['min' => 1, 'max' => 10, 'maxMessage' => 'my_max_message'], false, true], + [['min' => 1, 'max' => 10, 'minMessage' => 'my_min_message', 'maxMessage' => 'my_max_message'], true, true], + ]; + } + + /** + * @group legacy + * @expectedDeprecation Since symfony/validator 4.4: minMessage and maxMessage are deprecated when min and max options are set together. Use notInRangeMessage instead. + * @dataProvider provideDeprecationTriggeredIfMinMaxAndMinMessageOrMaxMessageSet + */ + public function testDeprecationTriggeredIfMinMaxAndMinMessageOrMaxMessageSet(array $options, bool $expectedDeprecatedMinMessageSet, bool $expectedDeprecatedMaxMessageSet) + { + $sut = new Range($options); + $this->assertEquals($expectedDeprecatedMinMessageSet, $sut->deprecatedMinMessageSet); + $this->assertEquals($expectedDeprecatedMaxMessageSet, $sut->deprecatedMaxMessageSet); + } + + public function provideDeprecationNotTriggeredIfNotMinMaxOrNotMinMessageNorMaxMessageSet(): array + { + return [ + [['min' => 1, 'minMessage' => 'my_min_message', 'maxMessage' => 'my_max_message']], + [['max' => 10, 'minMessage' => 'my_min_message', 'maxMessage' => 'my_max_message']], + [['min' => 1, 'max' => 10, 'notInRangeMessage' => 'my_message']], + ]; + } + + /** + * @doesNotPerformAssertions + * @dataProvider provideDeprecationNotTriggeredIfNotMinMaxOrNotMinMessageNorMaxMessageSet + */ + public function testDeprecationNotTriggeredIfNotMinMaxOrNotMinMessageNorMaxMessageSet(array $options) + { + new Range($options); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php index ef70c16145..ff1497c923 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php @@ -754,6 +754,66 @@ class RangeValidatorTest extends ConstraintValidatorTestCase ->setCode(Range::NOT_IN_RANGE_ERROR) ->assertRaised(); } + + public function provideMessageIfMinAndMaxSet(): array + { + $notInRangeMessage = (new Range(['min' => '']))->notInRangeMessage; + + return [ + [ + [], + 12, + $notInRangeMessage, + Range::NOT_IN_RANGE_ERROR, + ], + [ + ['notInRangeMessage' => 'not_in_range_message'], + 12, + 'not_in_range_message', + Range::NOT_IN_RANGE_ERROR, + ], + [ + ['minMessage' => 'min_message'], + 0, + 'min_message', + Range::TOO_LOW_ERROR, + ], + [ + ['maxMessage' => 'max_message'], + 0, + $notInRangeMessage, + Range::NOT_IN_RANGE_ERROR, + ], + [ + ['minMessage' => 'min_message'], + 15, + $notInRangeMessage, + Range::NOT_IN_RANGE_ERROR, + ], + [ + ['maxMessage' => 'max_message'], + 15, + 'max_message', + Range::TOO_HIGH_ERROR, + ], + ]; + } + + /** + * @group legacy + * @dataProvider provideMessageIfMinAndMaxSet + */ + public function testMessageIfMinAndMaxSet(array $constraintExtraOptions, int $value, string $expectedMessage, string $expectedCode) + { + $constraint = new Range(array_merge(['min' => 1, 'max' => 10], $constraintExtraOptions)); + $this->validator->validate($value, $constraint); + + $this + ->buildViolation($expectedMessage) + ->setParameters(['{{ min }}' => '1', '{{ max }}' => '10', '{{ value }}' => (string) $value]) + ->setCode($expectedCode) + ->assertRaised(); + } } final class Limit