Description
Hello,
I've ran into an issue with the Symfony\Bridge\Doctrine\Form\Type\EntityType
form type in very dynamic form.
The context:
A Project has multiple ProjectSteps. Each ProjectStep has 0 or more ActorLists, which contains a mask and multiple actors. The form described below serves to let users choose, based on the mask given, which actors should be included in the ActorList for execution of the project.
This leads to the following form: A ProjectType that has a CollectionType for the ProjectSteps: Each ProjectStep has a CollectionType for the ActorLists. The ActorList contains an EventSubscriber that adds the actor choices as an EntityType.
The issue is that for each of the EntityTypes, always the choices of the first one added are used, even though the choices are (verified) different per EntityType. The choices are added as a Doctrine ArrayCollection and according to the docs \Traversable
is supported, which the ArrayCollection
implements (1).
After some research, it turns out the $choiceList
closure in the setDefaults
method of the DoctrineType
(which the EntityType
extends) use a cache to prevent having to instantiate multiple Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList
for forms that have the same options (for reference, see here). The cache-key, based on which the lookup is done, includes the choices option. If the choices given is an array, the values are converted to the spl_object_hashes of those values (see lines 82-92). If the choices given is an ArrayCollection, no conversion is made. Within the actual creation of the cache-key, the $choiceHashes
, together with several other identifiers, are run through json_encode
and the resulting string is hashed to get the cache-key (see lines 112-120).
With the lack of getting the spl_object_hashes for the values of the ArrayCollection as the $choiceHashes
and the json_encond converting the ArrayCollection
to an empty object, if all other options are the same, this leads to the same key being generated for different forms, leading to always getting the same choice-options.
This can be fixed two ways:
- Remove the
\Traversable
support from the docs, and always require an array - Add support for
\Traversable
objects such that the$choiceHashes
value is set to an array of spl_object_hashes, one for each value in the\Traversable
object.
For now I'm just using ->toArray()
when assigning the choices to the options array to circumvent the cache-key conflict, which would indicate option 1. However I can imagine option 2 is preferred (and it has my personal preference).
Either way I will make a pull request for it (be it for the docs or the code), I'm just wondering what the preferred route is.
Regards,
Daan.
(1): ArrayCollection
implements \Doctrine\Common\Collections\Collection
, which extends IteratorAggregate
, which in turn extends Traversable