Inclure un formulaire sur plusieurs pages sans dupliquer l’inclusion dans tous les contrôleurs | KeiruaProd
Je suis développeur web freelance et propose des formations à Symfony2 ! Contactez-moi pour en discuter.

J’ai récemment reçu un mail me demandant si je savais comment résoudre un problème assez intéressant: afficher un formulaire de contact sur toute les pages dans le footer, mais sans le code associé au formulaire dans tous les contrôleurs.

Dans le cas d’un formulaire où il y a une logique de traitement derrière pour utiliser les données et non pas seulement les afficher, le problème en contient en fait 2 :

  • Comment afficher dans une vue des éléments qui doivent être générés par un contrôleur mais qui sont toujours les mêmes, sans devoir les passer en argument de chaque méthode du contrôleur ?
  • Comment traiter un formulaire comme il se doit alors que le code du contrôleur principal de la page ne contient pas de code de gestion du formulaire en question ?

La solution ? Une bonne partie de la réponse se trouve dans la fonction render de Twig. Cette fonction nous permet d’exécuter le code d’un contrôleur directement depuis la vue. Dans notre cas, nous allons créer une méthode de contrôleur qui se charge de créer un formulaire de contact, et l’appeler depuis la vue.

Commençons donc par créer notre modèle de page, qui va nous servir par la suite à créer des pages (très simples) où se trouve le formulaire :

{% block title %}{% endblock %}

{% block content %}{% endblock %}

Dans ce modèle, dans le div « main » se trouve ce que pourrait contenir votre page pour une vrai utilisation, et le footer contient l’appel à la méthode renderFooterAction () de la classe PageController de KeiruaProdApplicationBundle. Son contenu est limité au maximum, pour ne créer que le formulaire de contact et générer le code html associé. Pour gagner du temps, je suppose que vous avez déjà créé une entité ContactMessage associée à la classe de formulaire ContactMessageType, que votre base de donnée est correctement configurée et que vous avez bien spécificié les namespace :

// dans KeiruaProd\ApplicationBundle\Controller\PageController.php
public function renderFooterAction()
{
$entity = new ContactMessage();
$form = $this->createForm(new ContactMessageType(), $entity);

return $this->render('KeiruaProdApplicationBundle:common:footer.html.twig', array (
'form' => $form->createView()
));
}

Cette méthode n’est pas associée à une url (elle est uniquement appelée depuis la vue), il n’est donc pas nécessaire de créer une route pour elle. footer.html.twig contient seulement le code HTML associé à l’affichage du formulaire à partir des informations fournies par le contrôleur appelant :


{{ form_widget(form) }}
{{ form_rest(form) }}

Comme vous pouvez le voir, ce formulaire redirige vers la route KeiruaProdApplicationBundle_pagemerci dont je vais préciser le contenu. Nous allons en effet créer 2 pages (pour l’exemple), basées sur le modèle de template qui a été présenté plus haut. La page /unepage est un peu le modèle de n’importe quel page de votre site, et lorsque l’on valide le formulaire, on se retrouve sur la page de remerciements /merci. Bien évidemment, vous pouvez en créer autant que vous le voulez.

# dans KeiruaProd\ApplicationBundle\config\routing.yml
KeiruaProdApplicationBundle_unepage:
pattern: /unepage
defaults: { _controller: KeiruaProdApplicationBundle:Page:index }
KeiruaProdApplicationBundle_pagemerci:
pattern: /merci
defaults: { _controller: KeiruaProdApplicationBundle:Page:merci }

Le code de la méthode est des plus simples, et c’est justement ce que nous cherchons à faire : afficher une page préciser que nous voulons inclure un formulaire. Nous allons nous contenter d’afficher une simple page :


// dans KeiruaProd\ApplicationBundle\Controller\PageController.php
public function indexAction()
{
return $this->render('KeiruaProdApplicationBundle:Page:index.html.twig');
}

Mais dans page.html.twig, nous allons hériter de pagemodel.html.twig


{% extends 'KeiruaProdApplicationBundle:common:pagemodel.html.twig '%}

{% block title %}Une page{% endblock %}
{% block content %}Contenu de la page{% endblock %}

Faisons quelque chose de similaire pour la page de remerciements :


{% extends 'KeiruaProdApplicationBundle:common:pagemodel.html.twig '%}

{% block title %}Merci{% endblock %}
{% block content %}Merci d'avoir envoye un message !{% endblock %}

Dans ces 2 pages, nous n’avons pas écrit de code pour afficher de formulaire. Le code associé est hérité de pagemodel.html.twig. Dans le contrôleur pour la page d’index, nous n’avons pas créé le formulaire à afficher, mais il est tout même affiché. Par contre pour le sauvegarder, il est nécessaire que le contrôleur associé à la page de remerciements contiennent un peu de code pour le manipuler, de traiter le formulaire qui a été soumis pour sauvegarder l’entité ContactMessage associée dans la base de données.


// dans KeiruaProd\ApplicationBundle\Controller\PageController.php
public function merciAction()
{
$entity = new ContactMessage();

$request = $this->getRequest();
$form = $this->createForm(new ContactMessageType(), $entity);
$form->bindRequest($request);

// On sauvegarde
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($entity);
$em->flush();
}
// et on affiche la page de remerciements
return $this->render('KeiruaProdApplicationBundle:Page:merci.html.twig');
}

Et voila ! Dans les 2 pages le formulaire est affiché, et nous n’avons pas besoin d’écrire à chaque fois le code associé à son affichage. Pour inclure le formulaire dans les nouvelles pages qui le requièrent et gérer par la suite son traitement, il suffit désormais que les nouvelles pages héritent de notre modèle de page pagemodel.html.twig, ou plus directement, qu’ils appellent la méthode renderFooterAction directement.

2 Réponses à “Inclure un formulaire sur plusieurs pages sans dupliquer l’inclusion dans tous les contrôleurs”

  1. Shad0ko Dit:

    La fonction render est en effet très pratique. Je l’utilise lorsque j’ai des parties de templates autonomes, qui sont informatives et dépendent de l’utilisateur connecté;

  2. theShadoO Dit:

    C’est effectivement ce que j’utilise assez souvent sur l’application que nous migrons en symfony2 car ils veulent un maximum de composant réutilisable (si on pouvait leur délivrer des glaçons en même temps ils ne seraient pas satisfaits non plus).

    J’utilise aussi les macro de twig permettant une réutilisation des snipetts template. Mais bon je bute encore sur la création d’un bundle autonome et plus simple d’implémentation sur nos applis.

    J’ai réalisé un bundle de gridForm autonome. Permettant de générer, depuis une requête SQL (pardon DQL lol) un datagrid ou bien un même formulaire de CRUD avec ses champs. ou bien tout simplement les deux le tout en Ajax et Bootstrap. Selon l’objet des colonnes en rapport à leurs types je génère les champs du formulaires adéquates selon leur type en base. Il reste encore certain bugs à corriger mais c’est bien galère 🙁

    Donc là actuellement je peut générer en deux secondes une fois les requêtes établie du controller le formulaire et le datagrid. Le formulaire est généré selon des onglets on besoin.

    Si tu connais une façon propre de créer un bundle autonome en ayant toutes sa structure template et métier sur une implémentation façile je suis preneur

Répondre

Unable to load the Are You a Human PlayThru™. Please contact the site owner to report the problem.