I'm using Symfony 2.8, but the question is not specific to this version.
Let's say I have MyThingsFormType
with this field:
$builder->add(
'things',
ChoiceType::class,
[
'multiple' => true,
'choices_as_values' => true,
'choices' => [
'Thing no.20' => new Thing(20),
'Thing no.21' => new Thing(21),
'Thing no.22' => new Thing(22),
],
]
);
and 'data_class' => MyThings::class
.
The class MyThings
is defined as:
class MyThings
private Thing[] $myThings
And when I create my form I pass an object with some pre-populated choices, like:
$form = $this->formFactory->create(
new MyThingsFormType(),
new MyThings([new Thing(21)])
);
The point is, I would expect the choice Thing no.21
to be pre-populated in the view, because the underlying MyThings
object I pass to the form, does have that object in the $myThings
array... I know it's not the same object, but just one with the same data, and apparently Symfony does a strict comparison, so it does not consider that choice as being pre-selected...
So, what would be the quickest & cleanest way to customise that behaviour, so I can consider pre-selected the choices that have the same data, even if they're not the same objects?
I've found the solution in this response to a GitHub issue.
The good thing about choice_value is that Symfony will also use this closure to compare two different object instances for equality.
The trick is simply to use the choice_value
option to determine the value of the choice. Something like:
'choice_value' => function (Thing $thing) {
return $thing->getNumber();
},
This method will be called on the Thing
objects used as choices, and on the ones passed as data, so they will be considered equal even if they are different instances...