8000 [Validator] Choice constraint as Attribute differs from Annotation when "choices" is an associative array · Issue #41508 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content
[Validator] Choice constraint as Attribute differs from Annotation when "choices" is an associative array #41508
Closed
@emmanuelballery

Description

@emmanuelballery

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.

if (\is_array($choices) && \is_string(key($choices))) {
$options = array_merge($choices, $options);

How to reproduce

// stupid example
abstract class FormatEnum
{
    public const ALL = [
        'enum.format.example1' => 'f1',
        'enum.format.example2' => 'd6',
        'enum.format.example3' => 'u9',
    ];
}

// Annotation is fine 👍🏻 
/** @Choice(choices=FormatEnum::ALL) */

// Attribute is ko 👎🏻 
#[Choice(choices: FormatEnum::ALL)]

Possible Solution

Do not limit the test to \is_string(key($choices)) but check if key($choices) is in a "whitelist" of arguments (the one from the constructor) ;

Edit 03/06/21:

    $parameters = [
        'choices', 'callback', 'multiple', 'strict', 'min', 'max', 'message',
        'multipleMessage', 'minMessage', 'maxMessage', 'groups', 'payload', 'options',
    ];
    if (\is_array($choices) && \is_string(key($choices)) && \in_array(key($choices), $parameters, true)) {
        $options = array_merge($choices, $options);
    } elseif (null !== $choices) {
        $options['value'] = $choices;
    }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0