Skip to content

[Form] Symfony not selecting choice based on default choice data #17939

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

Closed
MichaelMackus opened this issue Feb 26, 2016 · 6 comments
Closed

[Form] Symfony not selecting choice based on default choice data #17939

MichaelMackus opened this issue Feb 26, 2016 · 6 comments

Comments

@MichaelMackus
Copy link

Issue

Symfony v2.8.3 is not selecting the default choice based on data set via the "data" parameter, when the choices consist of value objects. Its also not properly populating the "value" of the choices.

Steps to reproduce

git clone https://github.com/MichaelMackus/symfony-sandbox.git -b symfony-bug-default-choice-data
composer install
php app/console server:start

Note: this is just a symfony project created with symfony new acme 2.8

Results

When navigating to http://127.0.0.1:8000

2016-02-26-112115_417x217_scrot
2016-02-26-112152_453x161_scrot

Expected Results

"object 1" should be selected, but its not. Also, the values should be the string representation of the value objects (e.g. "object 1", "object 2", etc.), but its a simple numerical index.

Take a look at MyValueObject and MyChoiceType in particular. Composer is locked to symfony 2.8.3

Form submission works fine, and the resulting object gets returned properly from the form. Its just default data that seems broken.

Workaround

Workaround is to add this to the choice default options:

       // important if you rely on your option value attribute (e.g. for JavaScript)
       // this will keep the same functionality as before
       'choice_value' => function ($choice) {
           return $choice;
       }, 

But annoying, and the docs report this as fixed in 2.8

@HeahDude
Copy link
Contributor

HeahDude commented Mar 3, 2016

Hi @MichaelMackus, there were many ChoiceType bugs fixed in the last release of 2.8. Could you please update to the current 2.8.3 and confirm your issue ?

Some pieces of your form type implementation might help if so.

@MichaelMackus
Copy link
Author

@HeahDude I just updated my repo to 2.8.3, and the problem persists:

2016-03-03-094717_1272x463_scrot

2016-03-03-094725_468x152_scrot

@HeahDude
Copy link
Contributor

HeahDude commented Mar 3, 2016

Thanks for the update. Could you please provide a sample of your builder config ? Especially the parts where you define choices, and default data.

@MichaelMackus
Copy link
Author

All the code is in my repo:

@webmozart
Copy link
Contributor

@MichaelMackus Thanks for reporting this issue and special thanks for the detailed report! What you experience is not a bug: Symfony compares the choices in the data option and the choices you provide in choices using strict equality comparison. This is good, because false !== null, but false == null. However, when dealing with objects, this also means you must pass the same instance.

Second, Symfony will never automatically cast your objects to strings in order to generate the values. That's because Symfony doesn't know whether your object can be cast to a string or not.

The solution is to set the choice_value option, as you already figured out. I would also do a string cast in the closure and maybe even add a comment to make your intent explicit:

$resolver->setDefaults([
    'data_class' => MyValueObject::class,
    'choices' => $this->getChoices(),
    'choices_as_values' => true,
    'choice_value' => function (MyValueObject $object) {
        // Use the string representation as values
        return (string) $object;
    },
]);

The good thing about choice_value is that Symfony will also use this closure to compare two different object instances for equality. Hence even when passing different value objects, they will now be considered "the same" and your first issue is fixed as well. :)

@miguelrs
Copy link

The good thing about choice_value is that Symfony will also use this closure to compare two different object instances for equality.

This sentence should definitely be in the docs somewhere (I didn't find it at least) - I spent ages trying to figure this out! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants