Ce qui se passe
CollectionType est le champ standard pour éditer une liste d'éléments dans un formulaire Symfony. Il traîne deux
limites : toutes ses entrées partagent le même type de formulaire, et les lignes envoyées sont rattachées aux entrées
par leur position. Symfony 8.2 lève les deux, avec deux contributions du billet « New in Symfony 8.2 ».
Des entrées de types différents
Pour une page de CMS faite de blocs (titre, paragraphe, pied de page), une seule option entry_type ne suffit plus.
Le nouveau PolymorphicCollectionType (Michael Käfer, PR #63487) déclare un type de formulaire par sorte
d'entrée, plus un fournisseur qui choisit le bon type pour chaque entrée, via l'option entry_type_provider.
Le fournisseur reçoit les données d'une entrée sous deux formes, d'où deux méthodes. L'une, forSubmittedData(), ne
sert que pour les lignes ajoutées dans le navigateur : leurs données envoyées ne contiennent que les valeurs des
champs, donc chaque type d'entrée y ajoute un champ caché et non mappé type qui porte le nom de l'entrée.
Avec allow_add, Symfony produit un prototype par type d'entrée, exposé dans des attributs HTML
data-prototype-<nom> (data-prototype-heading, data-prototype-paragraph…) que votre JavaScript choisit
d'insérer. Les options entry_options, prototype_options et prototype_data fonctionnent comme dans
CollectionType, mais leurs valeurs sont indexées par nom d'entrée.
Des lignes nommées d'après leurs données
Les sous-formulaires d'une collection portent le nom des clés de ses entrées. Si l'ordre change entre le rendu et
l'envoi (un autre utilisateur a modifié les mêmes données, par exemple), les valeurs de la ligne 0 sont écrites dans
l'entrée qui occupe maintenant la clé 0.
La nouvelle option entry_name (Nicolas Grekas), disponible sur CollectionType comme sur
PolymorphicCollectionType, nomme chaque formulaire d'après l'entrée elle-même. Sa valeur peut être un chemin de
propriété lu sur chaque entrée, ou un callable qui reçoit l'entrée et sa clé, utile quand certaines entrées n'ont pas
encore d'identifiant. Le tag d'identifiant 42 stocké à la clé 0 donne alors des champs
post[tags][42][name] au lieu de post[tags][0][name], mais les valeurs vont toujours à ce tag et la collection garde
ses clés d'origine.
Le piège à éviter
Avec allow_add, une nouvelle ligne dont le nom correspond à une entrée existante met cette entrée à jour. Un
compteur numérique peut tomber sur l'identifiant d'une entrée : nommez les nouvelles lignes avec des noms qu'aucune
entrée ne peut avoir, comme new_1.
Source : blog Symfony, en anglais. Les exemples de code complets y figurent.