The Choice Form Type is one of the most advanced form types defined by Symfony. It's also one of the most important types, because a lot of other types inherit from it, such as EntityType, CountryType and LocaleType.
In Symfony 2.7 this form type has been completely refactored to support
dynamic generation for labels, values, indexes and attributes. This is now
possible thanks to the new options choice_label
, choice_name
,
choice_value
, choice_attr
, group_by
and choices_as_values
.
Dynamic generation of choice labels
By default, the keys of the choices
array are used as labels, but you can
pass a callable to the choice_label
option to generate them dynamically:
1 2 3 4 5 6 7 8 9 10 11
$builder->add('attending', 'choice', array(
'choices' => array(
'yes' => true,
'no' => false,
'maybe' => null,
),
'choices_as_values' => true,
'choice_label' => function ($allChoices, $currentChoiceKey) {
return 'form.choice.'.$currentChoiceKey;
},
));
Instead of a callable, you can also pass the name of the property to use as label:
1 2 3 4 5 6 7 8 9
$builder->add('attending', 'choice', array(
'choices' => array(
Status::getInstance(Status::YES),
Status::getInstance(Status::NO),
Status::getInstance(Status::MAYBE),
),
'choices_as_values' => true,
'choice_label' => 'displayName',
));
Dynamic generation of choice names and values
Use the choice_name
option to generate the form name for each choice and the
choice_value
option to generate their string value:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
$builder->add('attending', 'choice', array(
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
),
'choices_as_values' => true,
'choice_name' => function ($allChoices, $currentChoiceKey) {
// use the labels as names
return strtolower($currentChoiceKey);
},
'choice_value' => function ($allChoices, $currentChoiceKey) {
if (null === $currentChoiceKey) {
return 'null';
}
if (true === $currentChoiceKey) {
return 'true';
}
return 'false';
},
));
Instead of a callable, in these options you can also use the name of a property.
Dynamic generation of choice attributes
The choice_attr
defines all the additional HTML attributes applied to each
choice. This option allows to define its values using a simple array, which is
ideal for simple choices:
1 2 3 4 5 6 7 8 9 10 11
$builder->add('attending', 'choice', array(
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
),
'choices_as_values' => true,
'choice_attr' => array(
'Maybe' => array('class' => 'text-muted'),
),
));
When using more complex choices, it's probably a good idea to use a callable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$builder->add('attending', 'choice', array(
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
),
'choices_as_values' => true,
'choice_attr' => function ($allChoices, $currentChoiceKey) {
if (null === $currentChoiceKey) {
return array('class' => 'text-muted');
}
return array();
},
));
Again, you can pass to this option a property path instead of an array or a callable.
Dynamic choice grouping
By default, choices are grouped using the same structure as provided by the
choices
option:
1 2 3 4 5 6 7 8 9 10 11 12
$builder->add('attending', 'choice', array(
'choices' => array(
'Decided' => array(
'Yes' => true,
'No' => false,
),
'Undecided' => array(
'Maybe' => null,
),
),
'choices_as_values' => true,
));
The grouping of choices can also be generated dynamically using a callback or
a property path with the group_by
option:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$builder->add('attending', 'choice', array(
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
),
'choices_as_values' => true,
// grouping defined using a callback
'group_by' => function ($allChoices, $currentChoiceKey) {
if (null === $currentChoiceKey) {
return 'Undecided';
}
return 'Decided';
},
));
Dynamic generation of preferred choices
Lastly, the generation of the preferred choices can be defined in the new
preferred_choices
option using an array, a callback or a property path:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$builder->add('attending', 'choice', array(
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
),
'choices_as_values' => true,
// using an array to show the 'true' choice as preferred
'preferred_choices' => array(true),
// using a callable to show the 'true' choice as preferred
'preferred_choices' => function ($choice, $key) {
return true === $choice;
},
));
Thanks for this improvement @webmozart !
I had been waiting for the 'choice_attr' functionality since 2.3! Decided to temporarily solve the problem with JavaScript while there was an official solution, and I'm happy to see it implemented. Thank you!
Great! Finally an easy way to add a flag icon in front of the country name :)
This sounds very great, good job!
But be aware, this introduce some BC breaks from 2.6 (and lower) which are not resolved at this time.
See here: https://github.com/symfony/symfony/issues/14377 And here: https://github.com/symfony/symfony/issues/14382