bug #36140 [Validator] Add BC layer for notInRangeMessage when min and max are set (l-vo)

This PR was merged into the 4.4 branch.

Discussion
----------

[Validator] Add BC layer for notInRangeMessage when min and max are set

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #36133
| License       | MIT
| Doc PR        |

According to #36133, the improvement added in  #32435 may lead to a BC break when the developer pass `min` and `max` options and a custom `minMessage` or `maxMessage`. In this case it's expected to receive a `minMessage`/`maxMessage` in the violation but a `notInRangeMessage` is received instead.

So in the following conditions:
- `min` and `max` options are set
- `minMessage` or `maxMessage` is set

A deprecation is triggered. If a limit is violated and matches to the min/max message passed as option (`minMessage` for `min` violated and `maxMessage` for `max` violated), `minMessage/maxMessage` is used in the violation instead of `notInRangeMessage`.

Commits
-------

092d85c947 [Validator] Add BC layer for notInRangeMessage when min and max are set
This commit is contained in:
Fabien Potencier 2020-08-12 10:39:50 +02:00
commit f3753e93d8
4 changed files with 134 additions and 2 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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