Bonjour,
Au menu aujourd’hui, un DataTransformer récalcitrant.
Sur le principe, je fais des groupes d’utilisateurs pour qu’ils puissent communiquer entre eux. Entité Group typique avec un 'name' de groupe et une liste de 'members’, des Users (relation ManyToMany). Bon. Si je fais un formulaire Symfony classique avec un champ 'members’ configuré comme un EntityType avec multiple et expanded à true, j’ai des checkboxes, j’envoie le formulaire, ça fonctionne, c’est chouette.
Mon souci, (et je m’en veux tellement d’être perfectionniste à la noix qui cherche à optimiser ce truc) c’est qu’à l’affichage du formulaire il me fait 97 requêtes pour les utilisateurs, et ça, c’est sans que la liste définitive des utilisateurs soit en place. Vu que ce nombre apparait en jaune dans la debug bar de Symfony, je tente d’optimiser le formulaire via un chargement de la liste par Ajax. Mon formulaire perd donc son EntityType et gagne à la place un ChoiceType :
$builder
->add('name')
->add('members', ChoiceType::class, [
'label' => 'Membres',
'choices' => $options['users'],
'multiple' => true,
'expanded' => true,
])
->add('save', SubmitType::class, [
'label' => $options['submit_label']
])
->get('members') // Récupérer le champ
->addModelTransformer($this->transformer)
;
Il y a donc un DataTransformer comme recommandé par Symfony. (j’ai d’abord testé sans mais S me renvoie "An exception has been thrown during the rendering of a template ("Unable to transform value for property path "members": Expected an array.")."
Voilà le DataTransformer en question :
<?php
namespace App\Form\DataTransformer;
use App\Repository\UserRepository;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class UserToArrayTransformer implements DataTransformerInterface
{
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* Transforme une collection d'utilisateurs en un tableau contenant leurs IDs.
*
* @param mixed $users
* @return array
*/
public function transform($users): array
{
dump('Transform called', $users);
if (null === $users) {
return [];
}
// Si la collection est un objet Doctrine (ArrayCollection), on la convertit en tableau
if ($users instanceof \Doctrine\Common\Collections\Collection) {
$users = $users->toArray();
}
// Retourne un tableau des IDs des utilisateurs
return array_map(static fn($user) => $user->getId(), $users);
}
/**
* Transforme un tableau d'IDs en une collection d'utilisateurs.
*
* @param mixed $userIds
* @return array
* @throws TransformationFailedException
*/
public function reverseTransform($userIds): array
{
dump('ReverseTransform called', $userIds);
if (null === $userIds || !is_array($userIds)) {
return [];
}
// Recherche les utilisateurs par leurs IDs
$users = $this->userRepository->findBy(['id' => $userIds]);
// Vérifie que tous les IDs correspondent à des utilisateurs
if (count($users) !== count($userIds)) {
throw new TransformationFailedException('Certaines valeurs ne correspondent à aucun utilisateur.');
}
return $users;
}
}
Quand je soumets le formulaire, j’ai bien le dump "ReverseTransform called" mais $userIds est []. Pourtant, à l’envoi du formulaire, intercepté en AJAX et mis en forme avec un FormData, j’ai bien dans mon formulaire "group[members][]": Array["6", "12"].
Pour info, quand je teste la même chose avec le formulaire Symfony classique avec EntityType, j’ai bien exactement la même structure de données, et si j’ajoute le DataTransformer dans ce formulaire, il dump deux Users (ceux que j’avais cochés ; oui il les dump avant d’aller les chercher dans la BDD ligne 55 mais j’imagine que c’est parce que ce sont directement des entités).
Est-ce qu’il y a moyen de s’insérer d’une manière ou d’une autre entre l’envoi et le datatransformer pour voir quelles sont les données effectivement reçues ? Je ne trouve pas dans la documentation
Ou bien je m’y prends comme un manche dans ma démarche ?
Merci merci.