Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false #16685

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

Merged
merged 1 commit into from
Nov 27, 2015

Conversation

webmozart
Copy link
Contributor

Q A
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #15606
License MIT
Doc PR -

$nextKey = 0;
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one empty line too much

@ewgRa
Copy link
Contributor

ewgRa commented Nov 26, 2015

Seems it is cover my case, but not cover all cases. For example this one: https://gist.githubusercontent.com/ewgRa/2a71d44329be2be6446e/raw/733b5baf2b18e42149a670e92e0a27b87ff27567/gistfile1.txt

$options->offsetGet('choices');

// Pick labels from $choiceLabels if available
if (count($choiceLabels) > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ($choiceLabels) is enough. We do not actually need to count them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$choiceLabels is an array, so I think counting is more explicit and easier to understand.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact, there is a major performance issue in using count: $choiceLabels being a reference here, count is going to clone the array...

};

// BC closure, to be removed in 3.0
$choiceLabel = function (Options $options) use (&$choiceLabels) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should remove the &, it creates an unnecessary ref mismatch
or is it really required?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, the answer is yes, there is a reason to keep the &, which means the count below has to be removed to prevent a useless memory duplication

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, this is not really beautiful. But the closures need to access the same variable to be able to properly exchange information.

@webmozart
Copy link
Contributor Author

@ewgRa The keys you pass in the choices array need to be unique. You can map those keys to labels by using a closure in the choice_label option though. The closure accepts the current $choice, $key and $value. Use $key (i.e. the key in the choices array) to access the corresponding label and return it from the closure.


// Pick labels from $choiceLabels if available
if (count($choiceLabels) > 0) {
return function ($choice, $key) use ($choiceLabels) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may create a copy too (assuming we avoid the copy just above)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding an & may be necessary I agree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is without a & by intention. The outer $choiceLabels lives in the type's scope, i.e. every field uses the same variable to transfer information from choices to choice_label during its construction. The inner closure, however, lives in the scope of the field and is used to generate ChoiceView instances during view construction. If we'd use the global variable instead, all choice fields in a form would have the labels of the last one, which is not what we want.

@ewgRa
Copy link
Contributor

ewgRa commented Nov 26, 2015

@webmozart at least my case this PR solve.

Maybe good idea to document it, or add checks in cases like I show at gist.

@webmozart
Copy link
Contributor Author

See symfony/symfony-docs#5905 for documentation.

*/
private static function normalizeLegacyChoices(array &$choices, array &$choiceLabels, &$nextKey = null)
{
if (null === $nextKey) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$nextKey should defaut to 0 instead of this if

@nicolas-grekas
Copy link
Member

👍 (with one comment)

@webmozart
Copy link
Contributor Author

Updated

@nicolas-grekas
Copy link
Member

Thank you @webmozart.

@nicolas-grekas nicolas-grekas merged commit 1179f07 into symfony:2.7 Nov 27, 2015
nicolas-grekas added a commit that referenced this pull request Nov 27, 2015
…using "choices_as_values" = false (webmozart)

This PR was merged into the 2.7 branch.

Discussion
----------

[Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #15606
| License       | MIT
| Doc PR        | -

Commits
-------

1179f07 [Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false
// copy here so that every form has an own version of that
// variable (contrary to the global reference shared by all
// forms)
return function ($choice, $key) use ($choiceLabels) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this use a reference too, to avoid copying the array ?

@ghost
Copy link

ghost commented Jan 5, 2016

I did not follow the full thread, but this last update seems to have changed what is returned by $config->getOption('choices'). I'm not sure if this is intentional or not, but it is a breaking change and should not have been added to a minor release.
It can be fixed in my case by setting 'choices_as_values'=>true in all form types (and switch all values...).
I have already fought previously with the choice type and the big implementation changes and the general feeling is that it has been very unstable and a real headache through the 2.7 release.

@peter17
Copy link
Contributor

peter17 commented Jan 11, 2016

This change breaks compatibility with Symfony-2.7.7.
When updating to 2.7.8, I get this error:

Catchable Fatal Error: Argument 1 passed to Symfony\Component\Form\Extension\Core\Type\ChoiceType::normalizeLegacyChoices() must be of the type array, null given, called in myapp/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php on line 266 and defined

The form contains a choice list to Propel1 models. Setting 'choices_as_values' => true solves the problem.

@xabbuh
Copy link
Member

xabbuh commented Jan 11, 2016

see #17163 which will be included in the next patch releases

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

Successfully merging this pull request may close these issues.

7 participants