Symfony : Gérer un formulaire dans un composant

Dans un projet Symfony, comment gérer la validation d’un formulaire lorsqu’il est dans un composant ? C’est la question que l’on m’a posé cette semaine la semaine dernière (le temps passe vite…).

Tout d’abord, qu’est-ce qu’un composant dans Symfony ? Il s’agit en quelque sorte d’une action qui est réutilisable entre les différents modules de l’application. A la différence des « partials », qui sont « que » des templates, les composants contiennent de la logique : le plus souvent, récupérer un ou plusieurs modèles.

Pour revenir à la question, le problème n’est pas de gérer la validation à proprement parler, Symfony va s’en occuper grâce au forms framework mais plutôt de savoir où envoyer le visiteur une fois le formulaire soumis et comment, à la fin, le rediriger sur la page initiale, celle où il a rempli le formulaire.

Une solution possible est de créer une action spécifique pour valider le formulaire et d’ajouter un champ caché « referer » contenant l’url de la page initiale. Dans le fonctionnement, c’est relativement simple, le formulaire du composant pointe vers l’action et lorsque les données saisies sont valides, l’utilisateur est redirigé vers le valeur du champ « referer ».

Pour les intéressés, vous trouverez ci-dessous le contenu des différents fichiers pour l’utilisation d’un formulaire en composant. C’est prévu pour fonctionner avec Symfony 1.2.

  1. Le formulaire (lib/form/TestForm.class.php)
    < ?php
    class TestForm extends sfForm
    {
    	public function configure()
    	{
    		$this->setWidgets(array(
    			'name'    => new sfWidgetFormInput(),
    			'referer' => new sfWidgetFormInputHidden(),
    		));
    
    		$this->setValidators(array(
    			'name'    => new sfValidatorString(),
    			'referer' => new sfValidatorString(array('required' => false)),
    		));
    
    		$this->widgetSchema->setNameFormat('test-form[%s]');
    	}
    }
  2. Le composant (apps/frontend/modules/mymodule/actions/components.class.php)
    < ?php
    class mymoduleComponents extends sfComponents
    {
    	public function executeTestForm(sfWebRequest $request)
    	{
    		$this->form = new TestForm(array(
    			'referer' => $request->getUri()
    		));
    	}
    }
  3. Le template du composant (apps/frontend/modules/mymodule/templates/_TestForm.php)
    <h2>My Form</h2>
    <form action="<?php echo url_for('test-form') ?>" method="post">
      <table>
        < ?php echo $form ?>
      </table>
      <input type="submit" value="Send" />
    </form>
  4. L’action (apps/frontend/modules/mymodule/actions/actions.class.php)
    < ?php
    class mymoduleActions extends sfActions
    {
    	public function executeTestForm(sfWebRequest $request)
    	{
    		$this->form = new TestForm(array(
    			'referer' => $request->getUri()
    		));
    
    		if ($request->isMethod('post'))
    		{
    			$this->form->bind($request->getParameter($this->form->getName()));
    
    			if ($this->form->isValid())
    			{
    				$this->redirect(
    					$this->form->getValue('referer') ? $this->form->getValue('referer') : 'homepage'
    				);
    			}
    		}
    	}
    }
  5. Le template de l’action (apps/frontend/modules/mymodule/templates/TestFormSuccess.php)
    < ?php include_partial('TestForm', array('form' => $form)) ?>
  6. La règle de routage (apps/frontend/config/routing.yml)
    test-form:
      url:    /test-form
      param:  { module: mymodule, action: TestForm }

Une fois tous les fichiers créés, il ne reste plus qu’à inclure le composant dans un template, par exemple apps/frontend/layout.php, en ajoutant ceci :

< ?php include_component('mymodule', 'TestForm') ?>

Ici, le formulaire ne sert absolument à rien, la valeur saisie n’est pas utilisée. Il s’agit juste d’un exemple pour montrer le principe. ;-)

Note : Attention WordPress à ajouté un espace entre < et ?php

11 réponses sur “Symfony : Gérer un formulaire dans un composant”

  1. Bonjour,

    Tu devrais passer la valeur du referer comme option, comme cela ton formulaire n’est pas lie au sfContext. C’est mieux pour les tests unitaires …

  2. Merci pour ton exemple, par contre je n’arrive pas a redirigé mon user sur sa page d ‘origine si il y a une erreur dans la saisie.Le referer semble vide dans le formulaire semble vide. As-tu une solution?
    merci

  3. Tu veux revenir sur la page d’origine même si il y a (au moins) une erreur. C’est bien ça ?

    Là, c’est bien plus compliqué ! C’est d’ailleurs pour ça que je passe par une action intermédiaire pour valider les données.

    Tu as plusieurs solutions possibles pour faire ça. Elles présentes toutes des avantages et des inconvénients :

    – Solution #1 : Passer les données (erreurs) en session. L’action « intermédiaire » ne fait alors que de la validation (plus d’affichage), puis elle sérialize le form et redirige vers le referer. Le composant récupère le form en session et l’affiche (avec les erreurs donc).

    – Solution #2 : Valider les données dans le composant. L’action « intermédiaire » est supprimé et le composant gère lui-même la validation. Côté HTML, le form pointe toujours sur la page courante. Solution pas très propre et peut créer des conflits si d’autres formulaires sur la page.

    – Solution #3 : Utiliser Javascript et AJAX. Les données sont vérifiées en AJAX avant l’envoi et en cas d’erreurs elles sont affichées sans rechargement de page. Ne fonctionne que si le js est activé mais n’est pas bloquant, les autres passeront toujours par la page intermédiaire.

    Reste à choisir la meilleure solution dans ton cas. La 2e est la plus rapide/simple à mettre en place mais clairement à éviter. La 1ère est plus complexe à mettre en œuvre mais probablement la meilleure des trois. La dernière est un compromis dans entre les deux autres.

  4. Bonjour,
    Peut-etre question bête mais comment le composant sait qu’il doit faire appel à cette action parce que moi il ne rentre pas dans l’action et ne vérifie donc pas mon formulaire ?
    Merci d’avance

    1. C’est la ligne <form action="<?php echo url_for(‘test-form’) ?>" method="post"> qui indique directement au formulaire où il doit « pointer ». Ici sur la route « test-form » (à définir dans le fichier .yml)

      1. Parce que moi j’ai mis <form action=" » method= »post »> pour que s’il y a une erreur il revient sur la page d’origine mais mon problème c’est qu’il ne passe plus par l’action. Comment puis-je faire ?

  5. Bonjour,

    Merci pour ton article. Par contre j’ai une petite question. C’est quoi la raison d’inclure le template partiel dans dans ton fichier : apps/frontend/modules/mymodule/templates/TestFormSuccess.php
    Pacque le composant va utiliser toujours le template pour afficher le form.

    Merci encore pour l’article ;)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

:D :) :o :eek: :( :lol: :wink: :arrow: :idea: :?: :!: :evil: :p