Description
Depends on: #3879, #3968 (OptionsParser::replaceDefaults
is required)
I want to add three options to the ChoiceType that abstract functionality of EntityType for use in all choice fields. See also #3479.
The new options are:
"choice_labels"
If given, the "choices" option is interpreted as storing the choices in the values instead of the keys. This way, choices can be created that select between values that are not allowed to be passed as array keys (any non-integer or non-string value).
"choice_labels" can be:
- an array with a label for each choice
- a callable that is executed for each choice and returns the label
- a property path string, if the choices are objects
<?php
// The following two are equivalent
$builder->add('foo', 'choice', array(
'choices' => array(0 => 'no', 1 => 'yes'),
));
$builder->add('foo', 'choice', array(
'choices' => array(0, 1),
'choice_labels' => array('no', 'yes'),
));
// The following ones cannot be expressed without the new option
$builder->add('foo', 'choice', array(
'choices' => array(null, false, true),
'choice_labels' => array('maybe', 'no', 'yes'),
));
$builder->add('foo', 'choice', array(
'choices' => array($obj1, $obj2),
'choice_labels' => 'name',
));
$builder->add('foo', 'choice', array(
'choices' => array($obj1, $obj2),
'choice_labels' => function ($obj) {
return 'Label for ' . $obj->name;
},
));
"choice_values"
Like "choice_labels", but stores/generates the values that are stored in the "value" attributes of the generated HTML. Values must be strings and unique (i.e. no two choices must have the same value).
By default, the choices are used as values, if possible. If not possible, integer values are generated.
Like "choice_labels", this option can be an array, a callable or a string (if choices are objects).
<?php
$builder->add('foo', 'choice', array(
'choices' => array($obj1, $obj2),
'choice_labels' => 'name',
'choice_values' => 'id',
));
"choice_attr"
Like choice_values.
"group_by"
The "group_by" option stores a callable that returns the choice group for each choice or a property path if the choices are objects.
<?php
$builder->add('favNumber', 'choice', array(
'choices' => range(0, 100),
'choice_labels' => range(0, 100),
'group_by' => function ($choice) {
return $choice % 2 == 0 ? 'Even' : 'Odd',
}
));
"preferred_choices"
The "preferred_choices" option allows to pass the values of the preferred choices as array, a callable or a property path if the choices are objects.
$builder->add('foo', 'choice', array(
'choices' => array(null, false, true),
'choice_labels' => array('maybe', 'no', 'yes'),
'preferred_choices' => array(true, false),
));
$builder->add('foo', 'choice', array(
'choices' => array($obj1, $obj2),
'preferred_choices' => 'preferred', // i.e. isPreferred()
));
$builder->add('foo', 'choice', array(
'choices' => array($obj1, $obj2),
'preferred_choices' => function ($obj) {
return $obj instanceof PreferredSomething;
},
));
Poll
If the "choices" option is given as hierarchical array sorting each choice into a choice group, there are two possible ways for associating choices with their labels/values. Which one do you prefer?
A. Duplicate the hierarchy
<?php
$builder->add('favNumber', 'choice', array(
'choices' => array(
'Even' => array($obj0, $obj2, $obj4),
'Odd' => array($obj1, $obj3, $obj5),
),
'choice_labels' => array(
'Even' => array('Zero', 'Two', 'Four'),
'Odd' => array('One', 'Three', 'Five'),
),
'choice_values' => array(
'Even' => array(0, 2, 4),
'Odd' => array(1, 3, 5),
),
));
B. Array-index based
<?php
$builder->add('favNumber', 'choice', array(
'choices' => array(
'Even' => array(0 => $obj0, 2 => $obj2, 4 => $obj4),
'Odd' => array(1 => $obj1, 3 => $obj3, 5 => $obj5),
),
'choice_labels' => array(
array(0 => 'Zero', 1 => 'One', 2 => 'Two', 3 => 'Three', 4 => 'Four', 5 => 'Five'),
),
'choice_values' => array(
array(0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5),
),
));
Please name your preferred option in the comments.