
Intégrer et afficher le formulaire dans un template Twig
Apprenez à instancier un FormType dans un contrôleur Symfony, à le passer à un template Twig, et à utiliser les fonctions Twig `form_start`, `form_widget`, `form_row`, `form_errors`, `form_label`, `form_rest` et `form_end` pour un affichage flexible et pe
Instanciation du formulaire dans le contrôleur
Une fois que vous avez défini votre classe de type de formulaire (par exemple, App\Form\TaskType), la prochaine étape consiste à l'utiliser dans un contrôleur. C'est le contrôleur qui va instancier le formulaire et le passer au template Twig pour affichage. Pour créer un nouveau formulaire, vous utiliserez la méthode createForm() disponible dans les contrôleurs qui étendent AbstractController.
Supposons que nous voulions créer une page pour ajouter une nouvelle tâche. Nous aurons besoin d'une nouvelle action dans notre TaskController et d'une route associée. Appelons cette action newTask() :
namespace App\Controller;
use App\Form\TaskType; // Importez votre classe de type de formulaire
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; // Nécessaire pour gérer la soumission du formulaire
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class TaskController extends AbstractController
{
// ... autres méthodes (index, show)
#[Route('/tache/nouvelle', name: 'app_task_create', methods: ['GET', 'POST'])]
public function newTask(Request $request): Response
{
// 1. Les données initiales du formulaire (optionnel)
// Si c'est un formulaire de création, cela peut être un tableau vide
// ou une nouvelle instance de votre entité (si vous utilisez Doctrine).
$initialData = []; // Pour notre exemple sans entité Doctrine
// Si vous aviez une entité Task : $task = new Task(); $initialData = $task;
// 2. Création de l'instance du formulaire
// Le premier argument est la classe de votre FormType.
// Le second argument (optionnel) sont les données initiales.
$form = $this->createForm(TaskType::class, $initialData);
// 3. Gestion de la soumission (sera détaillé dans une section ultérieure)
// $form->handleRequest($request);
// if ($form->isSubmitted() && $form->isValid()) { ... }
// 4. Passer la "vue" du formulaire au template
// Il est crucial d'appeler createView() sur l'objet formulaire.
return $this->render('task/new.html.twig', [
'taskForm' => $form->createView(),
// 'taskForm' => $form, // Passer $form directement fonctionne aussi dans les versions récentes
]);
}
}Dans cet extrait :
- Nous importons
App\Form\TaskType. $initialDataest un tableau vide car nous créons une nouvelle tâche. Si nous éditions une tâche existante, nous passerions l'objet ou le tableau de cette tâche ici pour pré-remplir le formulaire.$this->createForm(TaskType::class, $initialData)instancie notre formulaire.$form->createView()crée une représentation spéciale du formulaire, appelée "vue de formulaire" (FormView), qui est ensuite passée au template Twig. C'est cet objetFormViewque Twig utilisera pour afficher les différents éléments du formulaire. Dans les versions plus récentes de Symfony, passer directement l'objet$formfonctionne également, car Symfony et Twig peuvent en déduire la vue. Cependant, l'utilisation explicite decreateView()est une pratique bien établie.
Affichage du formulaire dans le template Twig avec les fonctions dédiées
Maintenant que notre contrôleur passe la vue du formulaire au template, nous devons créer ou modifier le template Twig pour afficher ce formulaire. Créons un nouveau fichier templates/task/new.html.twig.
Twig offre un ensemble de fonctions très pratiques pour afficher les formulaires de manière flexible. Les plus importantes sont :
form_start(form_view): Affiche la balise d'ouverture, avec les attributsmethodetactioncorrectement configurés.form_end(form_view, options_array): Affiche la balise de fermetureet tous les champs du formulaire qui n'ont pas encore été affichés explicitement (ce qui est utile pour les champs cachés comme le token CSRF).form_widget(field_view, options_array): Affiche le widget HTML (,,, etc.) pour un champ spécifique du formulaire.form_label(field_view, label_text, options_array): Affiche le libellé () d'un champ.form_errors(form_or_field_view): Affiche les erreurs de validation pour l'ensemble du formulaire ou pour un champ spécifique.form_row(field_view, options_array): Est un raccourci qui affiche le libellé, le widget et les erreurs pour un champ, généralement enveloppés dans une structure HTML (souvent un).form_help(field_view): Affiche le message d'aide d'un champ (si configuré dans le FormType).form(form_view): Affiche l'intégralité du formulaire (tous ses champs, les uns après les autres). C'est rapide mais offre moins de contrôle sur la mise en page.form_rest(form_view): Affiche tous les champs du formulaire qui n'ont pas encore été rendus. C'est particulièrement utile pour s'assurer que les champs cachés (comme le token CSRF) sont bien inclus, surtout si vous rendez les champs individuellement.Voici un exemple de
templates/task/new.html.twigqui affiche notretaskForm:{# templates/task/new.html.twig #} {% extends 'base.html.twig' %} {% block title %}Ajouter une nouvelle tâche{% endblock %} {% block body %} <div class="container mt-4"> <h1>Créer une nouvelle tâche</h1> {# Début du formulaire #} {{ form_start(taskForm, {'attr': {'novalidate': 'novalidate'}}) }} {# novalidate désactive la validation HTML5 navigateur #} {# Affichage des erreurs globales du formulaire (celles non liées à un champ spécifique) #} {{ form_errors(taskForm) }} {# Méthode 1: Afficher chaque champ individuellement pour un contrôle total du HTML #} <div class="mb-3"> {{ form_label(taskForm.title, 'Titre de votre tâche') }} {# On peut surcharger le label ici #} {{ form_widget(taskForm.title, {'attr': {'class': 'form-control form-control-lg', 'placeholder': 'Un titre percutant...'}}) }} {# Ajout de classes CSS et placeholder #} <small class="form-text text-danger">{{ form_errors(taskForm.title) }}</small> {# Erreurs spécifiques au champ titre #} <small class="form-text text-muted">{{ form_help(taskForm.title) }}</small> {# Aide pour le champ titre #} </div> <div class="mb-3"> {{ form_label(taskForm.description) }} {{ form_widget(taskForm.description, {'attr': {'class': 'form-control', 'rows': 6}}) }} <small class="form-text text-danger">{{ form_errors(taskForm.description) }}</small> <small class="form-text text-muted">{{ form_help(taskForm.description) }}</small> </div> {# Si vous avez un champ 'save' de type SubmitType dans votre TaskType : #} {# {{ form_row(taskForm.save) }} ou pour le personnaliser : #} <div class="mb-3"> {{ form_widget(taskForm.save, {'label': 'Créer ma tâche !', 'attr': {'class': 'btn btn-success w-100'}}) }} </div> {# Méthode 2: Utiliser form_row pour chaque champ (moins de HTML à écrire) #} {# {{ form_row(taskForm.title, {'label': 'Titre personnalisé', 'attr': {'class': 'custom-class'}}) }} {{ form_row(taskForm.description) }} {{ form_row(taskForm.save) }} #} {# Méthode 3: Afficher tous les champs d'un coup (le moins de contrôle) #} {# {{ form_widget(taskForm) }} #} {# Ou {{ form(taskForm) }} qui inclut form_start, form_widget et form_end #} {# form_rest(taskForm) est important si vous rendez les champs manuellement pour s'assurer que les champs cachés (comme le token CSRF) sont inclus. Si vous utilisez {{ form_end(taskForm) }}, il appelle form_rest implicitement. Si le bouton submit est le dernier élément et que vous le rendez avec form_widget ou form_row, form_rest peut être placé avant le bouton ou avant form_end. #} {{ form_rest(taskForm) }} {# S'assure que tous les champs non rendus le sont, y compris _token #} {# Fin du formulaire #} {{ form_end(taskForm) }} <p class="mt-3"> <a href="{{ path('app_task_list') }}" class="btn btn-link">Annuler et retourner à la liste</a> </p> </div> {% endblock %}Cette approche vous donne un contrôle fin sur le HTML généré pour chaque partie du formulaire. Vous pouvez ajouter des classes CSS, des attributs HTML, ou réorganiser les éléments comme vous le souhaitez. L'option
'attr'dansform_widgetouform_rowpermet de passer des attributs HTML directement au widget du champ. L'utilisation de Bootstrap (ou de tout autre framework CSS) est ainsi grandement facilitée.En accédant à l'URL
/tache/nouvelle(ou celle que vous avez définie pour votre routeapp_task_create), vous devriez maintenant voir votre formulaire s'afficher, prêt à être rempli par l'utilisateur. La prochaine étape sera de gérer la soumission de ce formulaire dans le contrôleur.