-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Validator] Choice constraint as Attribute differs from Annotation when "choices" is an associative array #41508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi! Can confirm I can reproduce it. The problem happens when choices array is a string-keyed array. Giving public const ALL = [
'enum.format.example1',
'enum.format.example2',
'enum.format.example3'
]; Works just fine. If your possible solution works fine, you should definitely create a pull-request 👍 ! |
My solution is a hack, someone could use a choices array with a key named "multiple" thus breaking this constraint again. There is no real solution to support both attribute and annotation. Here I tried to reintroduce public function __construct(
$value = null, // <--------------------------------- reintroduce "value" before "choices"
$choices = null,
// ...
) {
if (\is_array($value)) { // <----------------------- @Choice({...}) or #[Choice([...])]
if (\is_string(key($value))) { // <------------- @Choice({"min":1}) or #[Choice(['min' => 1])]
$options = array_merge($value, $options); // @todo this does not eliminate the possibility of an associative array as choices
} else {
$options['value'] = $value; // <------------ @Choice({"foo","bar"}) or #[Choice(['foo','bar'])]
}
}
if (null !== $choices) { // <----------------------- @Choice(choices={...}) or #[Choice(choices: [...])]
if (null !== $options['value']) {
throw new Exception('You cannot use both "value" and "choices" in ' . self::class);
}
$options['value'] = $choices;
}
// ...
} |
Hey, thanks for your report! |
Hi! Yes this is still relevant. My workaround was to create a new choice constraint extending the current one but removing the faulty compatibility layer between Annotation & Attribute. I get that this is not a priority at all, but at least consider adding a note in the Choice constraint documentation stating that support for https://symfony.com/doc/current/reference/constraints/Choice.html#choices |
Are you able to submit a PR that fixes the problem? |
Hi @derrabus , I tried to find a way but could not find a real solution to fix this and cover all use cases. There is always an edge case. You added an if (\is_array($choices) && \is_string(key($choices))) {
// ^
// +- this removed support for a string indexed array of choices
//
$options = array_merge($choices, $options);
} elseif (null !== $choices) {
$options['choices'] = $choices;
} Merging In short, it's a niche problem. For people stuck with this, maybe use this simple hack |
I see. Using a string-keyed array as choices is indeed an edge case that broke completely when migratng to attributes. With annotations, it was only partly broken. Since the choice constraint does not use the keys, passing a non-list arrays was kind-of working by accident and not really by design. A possible solution would be to move the
The |
I previously tried to reintroduce a parameter to position This issue did not get a lot of feedback to really require all our attention. Feel free to close as I already provided workarounds if others were to need them. The reasoning behind this all thing was to avoid duplicating stuff in our codes, mainly enums when this was not a thing in PHP.
Skipping the constraint because of the choice type usage was not on the table as our models are not always handled by forms. abstract class FakeEnum {
public const ALL = [
'key.to.translation1' => 'Choice 1',
'key.to.translation2' => 'Choice 2,
];
}
// then validator could use
#[Choice(FakeEnum::ALL)]
// and form could use
$builder->add('choice', ChoiceType::class, ['choices' => array_flip(FakeEnum::ALL)]);
// the flipped version was also usefull to get translations from values in templates |
#44860 would be my take at fixing the issue. |
… 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 ------- ccd85fe Fix Choice constraint with associative choices array
Symfony version(s) affected: 5.2.0
Description
I was moving my projects to PHP8, using Attribute constraints (thanks to @derrabus) instead of Annotation ones. Regarding the
Symfony\Component\Validator\Constraints\Choice
constraint, I encountered a difference between the two. This started here.I often use associative arrays as choices - using the translation key as choice key (see How to reproduce below) ; one reason would be to share this constant array with the
ChoiceType
choices
option. It was completely ok with Annotations. But the compatibility rule implemented below for the new Attribute usage is now concidering my choices keys as constraint options and breaks my code. I get that this is required to support both Annotation and Attribute but this changes the way this constraint is working.symfony/src/Symfony/Component/Validator/Constraints/Choice.php
Lines 69 to 70 in d1cb2d6
How to reproduce
Possible Solution
Do not limit the test to
\is_string(key($choices))
but check ifkey($choices)
is in a "whitelist" of arguments (the one from the constructor) ;Edit 03/06/21:
The text was updated successfully, but these errors were encountered: