Skip to content

Commit 450191b

Browse files
bug #44860 [Validator] Fix Choice constraint with associative choices array (derrabus)
This PR was merged into the 5.3 branch. Discussion ---------- [Validator] Fix Choice constraint with associative choices array | Q | A | ------------- | --- | Branch? | 5.3 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #41508 | License | MIT | Doc PR | N/A This PR moves the `$options` parameter to the beginning of the constructor signature in order to fix the scenario described in #41508. I assume that the supported ways to construct this class are either an ordered arguments call with exactly one argument or a named argument call with zero or one ordered arguments. Those scenarios should continue to work and are covered with additional tests now. However, an ordered arguments call to the constructor with at least two parameters would break after this change. Commits ------- ccd85fe3e8 Fix Choice constraint with associative choices array
2 parents 4e25675 + dd0dc14 commit 450191b

File tree

3 files changed

+58
-6
lines changed

3 files changed

+58
-6
lines changed

Constraints/Choice.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public function getDefaultOption()
5252
}
5353

5454
public function __construct(
55-
$choices = null,
55+
$options = [],
56+
array $choices = null,
5657
$callback = null,
5758
bool $multiple = null,
5859
bool $strict = null,
@@ -63,12 +64,13 @@ public function __construct(
6364
string $minMessage = null,
6465
string $maxMessage = null,
6566
$groups = null,
66-
$payload = null,
67-
array $options = []
67+
$payload = null
6868
) {
69-
if (\is_array($choices) && \is_string(key($choices))) {
70-
$options = array_merge($choices, $options);
71-
} elseif (null !== $choices) {
69+
if (\is_array($options) && $options && array_is_list($options)) {
70+
$choices = $choices ?? $options;
71+
$options = [];
72+
}
73+
if (null !== $choices) {
7274
$options['value'] = $choices;
7375
}
7476

Tests/Constraints/ChoiceTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
namespace Symfony\Component\Validator\Tests\Constraints;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Validator\Constraints\Choice;
16+
use Symfony\Component\Validator\Mapping\ClassMetadata;
17+
use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader;
1518
use Symfony\Component\Validator\Tests\Fixtures\ConstraintChoiceWithPreset;
1619

1720
class ChoiceTest extends TestCase
@@ -22,4 +25,50 @@ public function testSetDefaultPropertyChoice()
2225

2326
self::assertEquals(['A', 'B', 'C'], $constraint->choices);
2427
}
28+
29+
/**
30+
* @requires PHP 8
31+
*/
32+
public function testAttributes()
33+
{
34+
$metadata = new ClassMetadata(ChoiceDummy::class);
35+
$loader = new AnnotationLoader();
36+
self::assertTrue($loader->loadClassMetadata($metadata));
37+
38+
/** @var Choice $aConstraint */
39+
[$aConstraint] = $metadata->properties['a']->getConstraints();
40+
self::assertSame([1, 2], $aConstraint->choices);
41+
self::assertSame(['Default', 'ChoiceDummy'], $aConstraint->groups);
42+
43+
/** @var Choice $bConstraint */
44+
[$bConstraint] = $metadata->properties['b']->getConstraints();
45+
self::assertSame(['foo', 'bar'], $bConstraint->choices);
46+
self::assertSame('myMessage', $bConstraint->message);
47+
self::assertSame(['Default', 'ChoiceDummy'], $bConstraint->groups);
48+
49+
/** @var Choice $cConstraint */
50+
[$cConstraint] = $metadata->properties['c']->getConstraints();
51+
self::assertSame([1, 2], $aConstraint->choices);
52+
self::assertSame(['my_group'], $cConstraint->groups);
53+
self::assertSame('some attached data', $cConstraint->payload);
54+
55+
/** @var Choice $stringIndexedConstraint */
56+
[$stringIndexedConstraint] = $metadata->properties['stringIndexed']->getConstraints();
57+
self::assertSame(['one' => 1, 'two' => 2], $stringIndexedConstraint->choices);
58+
}
59+
}
60+
61+
class ChoiceDummy
62+
{
63+
#[Choice(choices: [1, 2])]
64+
private $a;
65+
66+
#[Choice(choices: ['foo', 'bar'], message: 'myMessage')]
67+
private $b;
68+
69+
#[Choice([1, 2], groups: ['my_group'], payload: 'some attached data')]
70+
private $c;
71+
72+
#[Choice(choices: ['one' => 1, 'two' => 2])]
73+
private $stringIndexed;
2574
}

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"symfony/polyfill-mbstring": "~1.0",
2323
"symfony/polyfill-php73": "~1.0",
2424
"symfony/polyfill-php80": "^1.16",
25+
"symfony/polyfill-php81": "^1.22",
2526
"symfony/translation-contracts": "^1.1|^2"
2627
},
2728
"require-dev": {

0 commit comments

Comments
 (0)