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

Catégories : DéveloppementPHP

11 commentaires

Thomas R. · 22 juin 2009 à 11:25

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 …

Fabien · 22 juin 2009 à 13:35

Bonjour,

Merci ! J’ai modifié l’article en conséquence.

Amo__ · 29 juin 2009 à 18:02

Merci pour le post, c’est bon mangez-en !

taka · 1 novembre 2010 à 18:45

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

Locbel · 10 mars 2011 à 23:52

Super merci pour le tuto :)

z3yo · 2 juin 2011 à 09:41

Salut, super tuto :)
Mais je reste dans le cas de taka, As-tu une solution à nous proposer ?

Fabien · 6 juin 2011 à 22:15

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.

Flo · 1 août 2011 à 15:29

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

    Fabien · 1 août 2011 à 23:05

    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)

      Flo · 2 août 2011 à 15:24

      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 ?

Mohamed · 13 décembre 2011 à 17:37

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

Articles similaires

Développement

Installer et utiliser NodeJS et le module Less sur Mac OS X

Connaissez-vous LESS ? Il s’agit d’une sur-couche de CSS apportant son lot d’améliorations pour faciliter l’écriture de feuille de styles. LESS vous permettra par exemple de définir des fonctions ou des variables que vous pourrez Lire la suite…

Développement

Installer Apache 2, MySQL 5 et PHP 5.3 sur Mac OS 10.7 Lion avec MacPort

Bien que Apache et PHP soient pré-installés sur Mac OS X, j’évite depuis plusieurs années de les utiliser. Au départ pour un problème de compilation d’une extension PHP, aujourd’hui pour ne plus être dépendant d’Apple Lire la suite…

Développement

Utiliser l’extension Taggable de Doctrine avec Symfony 1.3/1.4

Jusqu’à symfony 1.2, si vous vouliez ajouter facilement de nouvelles fonctionnalités au framework PHP5 il fallait se diriger vers son importante base de plugins. Avec symfony 1.3 et 1.4, bien sûr vous pouvez toujours compter Lire la suite…