[FuelPHP] Validation de formulaire et introduction (très légère) aux vues

Salut les kids !

Je vous ai laissé il y a quelques temps dans une tristesse infinie, après vous avoir montré en quoi FuelPHP peut vous aider au quotidien grâce à son outil en ligne de commande Oil. C’est chouette, Oil, ça permet de presque pas bosser, mais parfois, et bien il faut bien justifier un peu son taux journalier petits canailloux, alors on va se remettre au travail, en intégrant une notion de validation de formulaire à notre petit système de publication de news que l’on a scaffoldé comme des oufs gueudins la dernière fois.

Z’êtes prêts les loulous ?

La validation de formulaire, c’est essentiel dans toute application web qui se respecte, car comme on a l’habitude de le dire quand on est développeur : NEVER TRUST USER INPUT.

Alors certes, de nos jours, c’est la mode à la validation de formulaire en JS, je suis le premier à l’utiliser massivement dans la quasi totalité des applications que je développe, mais la validation en js, c’est bien pour l’utilisateur, tandis que la validation en php, c’est bon pour l’application toute entière. Un utilisateur qui désactive Javascript pourrait tout casser le workflow de sa société, c’est mal. Autant utiliser la validation js et la validation php ensemble, on ne sait jamais.

Bref, FuelPHP, comme tout bon framework qui casse des noisettes avec ses fesses, offre une classe permettant de faciliter le traitement des inputs. Nous allons donc ajouter quelques règles sur nos formulaires permettant de créer et d’éditer une news.

Un peu d’anatomie.

La dernière fois que l’on s’est vue, chers bambins, nous n’avons pas disséqué la grenouille pour voir ce qu’il y avait dedans. Pourtant, le code généré par le scaffolding de FuelPHP est intéressant et permet de comprendre le fonctionnement du framework aisément. Voici par exemple l’action qui permet de créer une news, judicieusement nommé action_create (chaque action d’un controller doit d’ailleurs commencer par « action_ ») :

public function action_create($id = null)
	{
		if (Input::method() == 'POST')
		{
			$news = Model_News::factory(array(
				'titre' => Input::post('titre'),
				'permalien' => Input::post('permalien'),
				'contenu' => Input::post('contenu'),
			));

			if ($news and $news->save())
			{
				Session::set_flash('notice', 'Added news #' . $news->id . '.');

				Response::redirect('news');
			}

			else
			{
				Session::set_flash('notice', 'Could not save news.');
			}
		}

		$this->template->title = "News";
		$this->template->content = View::factory('news/create');
}

On remarque d’emblée qu’il y a une validation de formulaire à minima qui est proposée par le scaffolding… enfin… validation de formulaire est un grand mot : On vérifie en fait la présence d’une requête de type POST pour savoir si on peut enregistrer ou pas la news en base de données. Un peu léger, quoi.

Pour arranger ça, on va d’abord créer un objet $val au début de notre action action_create :


$val = Validation::factory();

Grace à cette objet, on va pouvoir créer nos règles de validation. Disons que, pour faire simple…

  • le titre est obligatoire, doit contenir au minimum 10 caractères et ne doit pas dépasser 200 caractère
  • Le permalien est obligatoire
  • Le contenu de la news est obligatoire

On va donc créer les règles suivantes :

$val->add('titre', 'Le titre')->add_rule('required')
		    ->add_rule('min_length', 10)
		    ->add_rule('max_length', 200);

$val->add('permalien', 'Le permalien')->add_rule('required');

$val->add('contenu', 'Le contenu de la news')->add_rule('required');

Maintenant que l’on a défini des règles de validation qui ressemblent à quelque chose, on va pouvoir s’en servir pour valider le formulaire. Voilà le code :


public function action_create($id = null)
 {
 $val = Validation::factory();
 $val->add('titre', 'Le titre')->add_rule('required')
 ->add_rule('min_length', 10)
 ->add_rule('max_length', 200);

 $val->add('permalien', 'Le permalien')->add_rule('required');

 $val->add('contenu', 'Le contenu de la news')->add_rule('required');

 if ($val->run())
 {
 $news = Model_News::factory(array(
 'titre' => Input::post('titre'),
 'permalien' => Input::post('permalien'),
 'contenu' => Input::post('contenu'),
 ));

 if ($news and $news->save())
 {
 Session::set_flash('notice', 'Added news #' . $news->id . '.');

 Response::redirect('news');
 }

 else
 {
 Session::set_flash('notice', 'Could not save news.');
 }
 }
 else
 {
 $this->template->title = "News";
 $this->template->content = View::factory('news/create');
 }
 }

Si vous retournez à votre formulaire, et que vous essayez de valider la création sans rien entrer dans les champs, vous reviendrez automatiquement sur ce formulaire et la news ne sera pas créée. Chouette.

Vous, vous l’avez compris tout de suite car vous êtes juste en dessous de Dieu dans le monde merveilleux de l’Internet. Pour un utilisateur normal, c’est déjà plus compliqué : pas de message d’erreur, l’utilisateur ne sait pas pourquoi il revient sur le formulaire, il est triste, il pense que vous lui en voulez, d’autant plus qu’il a déjà remarqué que vous le regardiez bizarrement dans les couloirs de la Cogip. Bref, l’utilisateur a besoin d’aide, de se sentir aimé. Vous êtes là pour ça.

On va donc afficher les différents messages d’erreur liés à la validation de ce formulaire, pour faire comprendre pourquoi on peut pas enregistrer sa news.

Il y a plusieurs méthodes pour afficher les messages d’erreurs. Nous, on va se contenter d’afficher les messages d’erreur via un set_flash. Il faut que vous sachiez que la librairie Validation est suffisamment puissante pour vous permettre de faire le tri entre les champs validés et les champs qui ne respectent pas les règles de validation. On aurait donc pu re-populariser les champs valides sans aucun soucis, mais autant faire à peu près simple pour le moment :

public function action_create($id = null)
	{
		// On commence par créer nos règles de validation
		$val = Validation::factory('news');

		$val->add('titre', 'Le titre')->add_rule('required')
		    ->add_rule('min_length', 10)
		    ->add_rule('max_length', 200);

		$val->add('permalien', 'Le permalien')->add_rule('required');

		$val->add('contenu', 'Le contenu de la news')->add_rule('required');

		// Si on n'a rencontré aucun soucis
		if ($val->run())
		{
			$news = Model_News::factory(array(
				'titre' => Input::post('titre'),
				'permalien' => Input::post('permalien'),
				'contenu' => Input::post('contenu'),
			));

			// Si la sauvegarde s est déroulée correctement
			if ($news and $news->save())
			{
				Session::set_flash('notice', 'Added news #' . $news->id . '.');

				Response::redirect('news');
			}
			else
			{
				Session::set_flash('notice', 'Could not save news.');
			}
		}
		else
		{

			$errors = $val->errors();
			$flash = '';

			foreach($errors as $cle=>$val):
				$flash .= '<li>'.$val.'</li>';
			endforeach;

			if(sizeof($errors)>0):
				Session::set_flash('notice', 'Des erreurs ont été rencontrées : ' . $flash);
			endif;

			$this->template->title = "News";
			$this->template->content = View::factory('news/create');

		}
	}

Vous pouvez voir que l’on a créé une variable $errors, que l’on alimente avec les éventuelles erreurs retournées par la validation de formulaire. Dans cet exemple, je boucle sur les erreurs afin de créer un flash data (Session:set_flash()).  Si on a des erreurs, on les affiche. On ne transmet donc rien à la vue dans ce cas précis.

Si on avait souhaité transmettre nos messages d’erreurs (et pourquoi pas les champs validés), on aura du transmettre quelques variables via $data (par exemple $data['errors'] et transmettre $data à la vue de cette façon :


$this->template->content = View::factory('news/create', $data);

Si vous essayez à nouveau de soumettre un formulaire vide (ou qui ne respecte pas les règles de validation), vous allez désormais avoir vos messages d’erreur :

La modification d’une news reprend le même fonctionnement. A vous de bricoler un peu maintenant.

Quelques mots sur les vues et le template

On n’a pas encore eu l’occasion de manipuler les formulaires, de retoucher le design de notre application, bref, de faire mumuse avec les vues. Dans l’immédiat ce n’est pas vital, mais on va survoler rapidement le sujet.

Dans votre installation, vous avez déjà sans doute jeté un oeil dans fuel/app/views

Ce dossier contient l’ensemble des vues de notre application, classées dans des dossiers qui correspondent à nos contrôleurs. Vous noterez également la présence d’un fichier template.php à la racine du dossiers views. Ce fichier est important, car il sert de… aller, un effort… de TEMPLATE ! BRAVO §§§

Même s’il est tout à fait possible de scinder vos vues en plusieurs fichiers (header, menu, content, footer…), l’avantage du fichier template est qu’il permet de concentrer tout ce qui est générique à chaque page au sein d’un seul fichier. La seule chose essentielle à retenir, c’est que tout ce que vous définirez en output dans vos contrôleurs sera affiché via <?php echo $content; ?>

En ouvrant le dossier news, vous vous rendrez également compte que l’on a un fichier _form.php qui été généré avec le scaffolding. Ce fichier est utilisé par l’action create et l’action edit pour afficher le formulaire. Le code déjà présent dans le fichier permet d’afficher le contenu d’une news lorsque l’on souhaite l’éditer, et affiche un formulaire vide si l’on souhaite créer une news.

La gestion des formulaires dans FuelPHP mérite presque un article à elle toute seule. Vous pouvez notamment générer des formulaires sans taper une ligne de html. Les puristes préfèreront certainement s’occuper de tout ça par eux même, chacun son truc. A titre d’information, voici comment on génère un input de type text :


<?php echo Form::input('titre', Input::post('titre', isset($news) ? $news->titre : '')); ?>

Ce code permet, d’une part, de créer un input de type text dont le name est « titre », mais permet également de repopulariser l’input avec le titre d’une news si l’on est sur un formulaire d’édition (oui, grâce à un opérateur ternaire). Sympa non ?

Et, euh, les ACL ?

J’avais promis que j’en parlerai dans cet article, mais ne précipitons pas les choses les amis. Dans un prochain article, on va d’abord s’amuser à personnaliser un peu notre bousin et nous engager dans la création d’un véritable projet : un gestionnaire de tâches. Ho, ca ne sera pas facile, il y aura du sang, des larmes, de la chique et du molard, mais c’est pour votre bien. Je crois.


Quelques mots sur l'auteur

Je m'appelle Grégory BABONAUX, je suis concepteur développeur web indépendant en Normandie (Dans un axe plus ou moins approximatif situé entre Caen, Rouen, Evreux et Paris). Plus d'informations me concernant sur mon site : www.gregorybabonaux.fr ou sur mon portfolio : www.behance.net/gregorybabonaux


A vous de jouer

(obligatoire) (obligatoire)