Simplifiez vos formulaires Symfony


Gilles
Simplifiez vos formulaires Symfony

Les formulaires Symfony permettent de soumettre des données, de les valider, et pourquoi pas de transformer la valeur en une classe.

On peut aussi y associer une classe et laisser le formulaire mettre à jour les propriétés de celle-ci sans notre intervention.

Est-ce une bonne chose ? Pourquoi ne pas laisser nos formulaires faire le moins de choses possible ? Laissez moi vous expliquer en commençant par revoir quelques bases de séparation des préoccupations (separation of concerns).

(suite…)
Show Comments (6)

Comments

  • Thomas

    Bonjour,
    Merci pour votre article, toujours intéressant de vous lire !

    On retrouve régulierement ce type de conseils visant à délaisser le mapping form/entité au profit de l’usage de DTO ou d’un simple array de data comme dans votre article. Les exemples donnés sont toujours sur des cas extrêmement simples mais l’intérêt d’un formulaire réside aussi dans sa gestion des collections (ex: entité many-to-many), des imbrications de forms, etc. Ces usages avancées sont souvent requis par des besoins d’interfaces utilisateur complexes et c’est difficile (et ça serait bête) de s’en passer.
    Peut-être pour les besoins de l’exemple, vous initialisez votre CreateCar() directement dans le controller. Pour des besoins plus complexes et réutilisables, je pense qu’il est requis de passer par des services intermédiaires pour renseigner nos models à partir des data du form, surtout dans le cas où nous avons des datas complexes faisant intervenir plusieurs entités (collections, imbrications, etc.), et là nous nous retrouvons à passer des arrays de valeurs de services en services, ce qui me ferait bien regretter l’usage d’un model.
    Actuellement, dès qu’un cas un peu complexe se présente, je passe par un model et je définis les contraintes sur ce model, mais j’ai régulièrement l’impression de reproduire une grosse portion des propriétés de mes entités sur ces models et la gestion des collections d’entités (création, mise à jour, suppression) dans les services est complexe et me fait souvent regretter de ne pas laisser les forms Symfony faire le boulot directement au niveau des entités.
    Pour les cas simples, j’ai tendances à conserver les interactions directes form/entité et bien que j’apprécie beaucoup votre approche, je me demande parfois si « ça vaut le coup » de se passer de cette facilité offerte par le composent de form.

    J’ai également un peu de mal à l’idée de valider mes données sur plusieurs niveaux (je parle de votre exemple du doublon d’email en base qui sera validé hors form) et pour lequel il faudra trouver un moyen élégant de remonter l’erreur à l’utilisateur.

    Je n’apporte pas d’avis spécifique ni une quelconque solution dans mon post, il s’agit juste de mes réflexions et de mon approche actuelle, même si je trouve cela plutôt imparfait.

    • Article Author
  • Gilles

    Bonjour Thomas,

    Merci pour cette réponse constructive !
    Oui l’exemple reste simple, je ferai un exemple plus complexe !

    Je ne remets pas en cause l’utilisation des models/entitées associés aux formulaires, je remets en cause leur utilisation régulière, automatique.

    C’est très pratique comme vous le dites, mais pratique ne signifie pas toujours le meilleur choix.

    J’ai longtemps suivi la méthode « enseignée » par symfony pendant des années, et force d’essayer et de regarder ce qui se fait ailleurs, de découpler plus simplement j’en suis arrivé à ce constat (qui n’est peut-être pas la meilleure pratique !)

    Mais aujourd’hui je n’utilise plus de model sur mes formulaires, mêmes ceux complexes…je me focalise en premier sur le traitement des données dans mes handlers, et une fois satisfait je commence mes formulaires. Souvent c’est le sens inverse qui est utilisé !

    Si vous voulez en discutez davantage je suis disponible sur le slack de Symfony @GillesG 😉

    • Article Author
  • Thomas

    J’avais bien compris que vous remettiez uniquement en cause l’usage systématique du mapping form/doctrine, et je fais de même lorsque je juge que le cas est complexe et peut être amené à évoluer. Je comprends également les approches plus « extrêmistes » qui préconisent de ne jamais mapper son form directement sur une entité (les entités sont des models précieux, le form va potentiellement les renseigner avec des données invalides et nous ne sommes alors qu’à un flush d’un gros soucis).
    Mais effectivement, il faut savoir rester pragmatique et choisir la voie complexe uniquement quand c’est requis.
    Ce qui me chiffonne avec une approche sans model (basée sur un array) pour gérer un cas complexe, c’est qu’on met en place une structure découplée et censée être évolutive (multiples services chargés des validations/persist des différents composants de nos data, etc.) en se basant sur un format de support/transfert de données dépourvu de typage et autres fonctionalités d’accessibilité ou de validation bien pratiques. Bref, j’ai l’impression qu’on effectue un dev lourd en se privant des objets qui sont parfaitement pensés pour ces besoins.

    Je me cherche toujours et tout avis complémentaire est le bienvenue 🙂

    Si d’autres avis constructurs

    • Article Author
  • Fabien

    Pas convaincu.

    Avoir des données potentiellement non valides après un $form->isValid(), ça ne fait pas sens.

    Le système de validation de Symfony est très poussé et permet de créer ses propres contraintes de validations, et de choisir selon chaque contexte quelles contraintes vérifier ou non grâce aux groupes de validation.

    « Faites des formulaires qui ne soient jamais reliés à une classe ou une entité. » Pourquoi ? Il ne s’agit pas de couplage, mais d’une spécialisation : c’est un formulaire en charge des données d’une certaine entité tout comme une contrainte de validation est en charge d’un certain type de données.

    Quels sont les bénéfices à ne pas lier un formulaire à une entité ?

    • Article Author
  • Gilles

    Bonjour Fabien,

    Le principe que j’essaie de montrer dans l’article justement c’est de ne pas lier entité et formulaire.

    « Le formulaire est en charge des données d’une certaine entité »
    Pour moi non, l’entité représente le mapping de la table en BDD rien de plus.
    Donc si on veut la mettre à jour, passer par un formulaire nous contraint à ajouter du code pour que le formulaire puisse fonctionner, idem avec les validations.

    Le code de l’entité devrait rester simple et cohérent, et non s’adapter à ce qui vient de l’extérieur.

    Admettons que j’ai un formulaire qui soumets des données et qui sont validées par symfony. Ces données sont ensuite transmises à un handler, qui connait la logique métier du projet et qui va faire un traitement dessus, et seulement à cette étape on va mettre à jour l’entité.

    Le bénéfice c’est qu’on peut facilement tester et identifier qui fait quoi sur une entité. Plus simplement qu’une armée de groupe de validation et de formulaire.

    Pour information c’est en regardant et lisant la pratique du DDD et du clean architecture (et quelques années de tests et d’echec) que j’en suis arrivé à cette approche qui pour l’instant me satisfait.

    Si tu veux en discuter plus je suis dispo sur le slack symfony @GillesG #french 😉

    • Article Author
  • Fabien

    Bonjour Gilles,

    L’entité n’est pas le mapping. L’entité est un objet métier qui est mappé (ou non) à la base de données grâce au mapping qui peut prendre la forme d’annotations.

    Le code de l’entité reste simple et cohérent, puisque que les contraintes de validations ne sont pas du code, mais de simples annotations (ni plus ni moins que des commentaires). Et ces contraintes peuvent même être déclarées hors des classes des entités en utilisant le format YML par exemple.

    Il n’est pas difficile de tester les validateurs et les formulaires avec l’approche « formulaire mappé sur une entité ». Du coup, je ne vois pas vraiment le gain de votre approche, si ce n’est une question d’affinités.

    • Article Author

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Recevez nos articles