feature #32435 [Validator] Add a new constraint message when there is both min and max (Lctrs)

This PR was squashed before being merged into the 4.4 branch (closes #32435).

Discussion
----------

[Validator] Add a new constraint message when there is both min and max

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | Part of #31503
| License       | MIT
| Doc PR        | to do

Currently, the failed validation messages in the `Range` constraint doesn't carry a notion of range. This can be confusing and error-prone if we report these messages to the user as-is.

This PR introduces a new message to the `Range` constraint (`This value should be between {{ min }} and {{ max }}.`) that will be displayed if both `min` and `max` are not `null`.

Commits
-------

c5488bcec1 [Validator] Add a new constraint message when there is both min and max
This commit is contained in:
Fabien Potencier 2019-07-12 08:12:45 +03:00
commit fd3ad6520c
6 changed files with 78 additions and 42 deletions

View File

@ -18,6 +18,8 @@ CHANGELOG
* added the `min_limit_path` and `max_limit_path` parameters in violations when using
`Range` constraint with respectively the `minPropertyPath` and
`maxPropertyPath` options.
* added a new `notInRangeMessage` options to the `Range` constraint that will
be used in the violation builder when both `min` and `max` are not null.
4.3.0
-----

View File

@ -26,15 +26,18 @@ use Symfony\Component\Validator\Exception\MissingOptionsException;
class Range extends Constraint
{
const INVALID_CHARACTERS_ERROR = 'ad9a9798-7a99-4df7-8ce9-46e416a1e60b';
const NOT_IN_RANGE_ERROR = '04b91c99-a946-4221-afc5-e65ebac401eb';
const TOO_HIGH_ERROR = '2d28afcb-e32e-45fb-a815-01c431a86a69';
const TOO_LOW_ERROR = '76454e69-502c-46c5-9643-f447d837c4d5';
protected static $errorNames = [
self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR',
self::NOT_IN_RANGE_ERROR => 'NOT_IN_RANGE_ERROR',
self::TOO_HIGH_ERROR => 'TOO_HIGH_ERROR',
self::TOO_LOW_ERROR => 'TOO_LOW_ERROR',
];
public $notInRangeMessage = 'This value should be between {{ min }} and {{ max }}.';
public $minMessage = 'This value should be {{ limit }} or more.';
public $maxMessage = 'This value should be {{ limit }} or less.';
public $invalidMessage = 'This value should be a valid number.';

View File

@ -70,7 +70,30 @@ class RangeValidator extends ConstraintValidator
}
}
if (null !== $max && $value > $max) {
$hasLowerLimit = null !== $min;
$hasUpperLimit = null !== $max;
if ($hasLowerLimit && $hasUpperLimit && ($value < $min || $value > $max)) {
$violationBuilder = $this->context->buildViolation($constraint->notInRangeMessage)
->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);
if (null !== $constraint->maxPropertyPath) {
$violationBuilder->setParameter('{{ max_limit_path }}', $constraint->maxPropertyPath);
}
if (null !== $constraint->minPropertyPath) {
$violationBuilder->setParameter('{{ min_limit_path }}', $constraint->minPropertyPath);
}
$violationBuilder->addViolation();
return;
}
if ($hasUpperLimit && $value > $max) {
$violationBuilder = $this->context->buildViolation($constraint->maxMessage)
->setParameter('{{ value }}', $this->formatValue($value, self::PRETTY_DATE))
->setParameter('{{ limit }}', $this->formatValue($max, self::PRETTY_DATE))
@ -89,7 +112,7 @@ class RangeValidator extends ConstraintValidator
return;
}
if (null !== $min && $value < $min) {
if ($hasLowerLimit && $value < $min) {
$violationBuilder = $this->context->buildViolation($constraint->minMessage)
->setParameter('{{ value }}', $this->formatValue($value, self::PRETTY_DATE))
->setParameter('{{ limit }}', $this->formatValue($min, self::PRETTY_DATE))

View File

@ -362,6 +362,10 @@
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
<target>This password has been leaked in a data breach, it must not be used. Please use another password.</target>
</trans-unit>
<trans-unit id="94">
<source>This value should be between {{ min }} and {{ max }}.</source>
<target>This value should be between {{ min }} and {{ max }}.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -362,6 +362,10 @@
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
<target>Ce mot de passe a été divulgué lors d'une fuite de données, il ne doit plus être utilisé. Veuillez utiliser un autre mot de passe.</target>
</trans-unit>
<trans-unit id="94">
<source>This value should be between {{ min }} and {{ max }}.</source>
<target>Cette valeur doit être comprise entre {{ min }} et {{ max }}.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -143,16 +143,16 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'min' => 10,
'max' => 20,
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMaxMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $formattedValue)
->setParameter('{{ limit }}', 20)
->setCode(Range::TOO_HIGH_ERROR)
->setParameter('{{ min }}', 10)
->setParameter('{{ max }}', 20)
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -164,16 +164,16 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'min' => 10,
'max' => 20,
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMinMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $formattedValue)
->setParameter('{{ limit }}', 10)
->setCode(Range::TOO_LOW_ERROR)
->setParameter('{{ min }}', 10)
->setParameter('{{ max }}', 20)
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -327,16 +327,16 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'min' => 'March 10, 2014',
'max' => 'March 20, 2014',
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMaxMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $dateTimeAsString)
->setParameter('{{ limit }}', 'Mar 20, 2014, 12:00 AM')
->setCode(Range::TOO_HIGH_ERROR)
->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM')
->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM')
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -352,16 +352,16 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'min' => 'March 10, 2014',
'max' => 'March 20, 2014',
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMinMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $dateTimeAsString)
->setParameter('{{ limit }}', 'Mar 10, 2014, 12:00 AM')
->setCode(Range::TOO_LOW_ERROR)
->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM')
->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM')
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -499,18 +499,18 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'minPropertyPath' => 'min',
'maxPropertyPath' => 'max',
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMaxMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $formattedValue)
->setParameter('{{ limit }}', 20)
->setParameter('{{ min }}', 10)
->setParameter('{{ max }}', 20)
->setParameter('{{ max_limit_path }}', 'max')
->setParameter('{{ min_limit_path }}', 'min')
->setCode(Range::TOO_HIGH_ERROR)
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -524,18 +524,18 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'minPropertyPath' => 'min',
'maxPropertyPath' => 'max',
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMinMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $formattedValue)
->setParameter('{{ limit }}', 10)
->setParameter('{{ min }}', 10)
->setParameter('{{ max }}', 20)
->setParameter('{{ max_limit_path }}', 'max')
->setParameter('{{ min_limit_path }}', 'min')
->setCode(Range::TOO_LOW_ERROR)
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -685,18 +685,18 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'minPropertyPath' => 'min',
'maxPropertyPath' => 'max',
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMaxMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $dateTimeAsString)
->setParameter('{{ limit }}', 'Mar 20, 2014, 12:00 AM')
->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM')
->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM')
->setParameter('{{ max_limit_path }}', 'max')
->setParameter('{{ min_limit_path }}', 'min')
->setCode(Range::TOO_HIGH_ERROR)
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
@ -714,18 +714,18 @@ class RangeValidatorTest extends ConstraintValidatorTestCase
$constraint = new Range([
'minPropertyPath' => 'min',
'maxPropertyPath' => 'max',
'minMessage' => 'myMinMessage',
'maxMessage' => 'myMaxMessage',
'notInRangeMessage' => 'myNotInRangeMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMinMessage')
$this->buildViolation('myNotInRangeMessage')
->setParameter('{{ value }}', $dateTimeAsString)
->setParameter('{{ limit }}', 'Mar 10, 2014, 12:00 AM')
->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM')
->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM')
->setParameter('{{ max_limit_path }}', 'max')
->setParameter('{{ min_limit_path }}', 'min')
->setCode(Range::TOO_LOW_ERROR)
->setCode(Range::NOT_IN_RANGE_ERROR)
->assertRaised();
}
}