Zend Framework, Formulaire et Base de donnée, partie 1

Hello,
On va voir aujourd’hui comment construire et gérer un formulaire, ajouter les données récupéré dans une base de données, afficher ces données, et enfin modifier et supprimer celles-ci. En gros, on va utiliser les propriétés CRUD de Zend Framework en y associant une base de donnée et un formulaire.
P.S. : Pendant la rédaction de ce tuto, je me suis rendu compte qu’il allait être beaucoup trop gros, du coup j’ai décidé de le couper en deux parties, une première sur la création du formulaire et l’ajout en base, une deuxième sur la l’affichage, la modification et la suppression.
Sommaire
- Partie 1
- Partie 2
Préparation de la base de donnée :
CREATE TABLE IF NOT EXISTS `Budget`.`users` ( `idUser` INT NOT NULL AUTO_INCREMENT , `nom` VARCHAR(20) NULL , `prenom` VARCHAR(20) NULL , `email` VARCHAR(30) NULL , `active` INT NULL , `level` INT NULL , `password` BIGINT NOT NULL , PRIMARY KEY (`idUser`) ) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 PACK_KEYS = DEFAULT
Comme on a vu dans un précédant tutoriel, il faut créer une classe qui va nous mapper les informations de la table (ORM du Zend Framework).
<?php
class Model_DbTable_Users extends Zend_Db_Table_Abstract {
protected $_name = 'users';
protected $_primary = array('idUser');
}
Préparation du formulaire
Il existe plusieurs façons de faire un formulaire : soit en utilisant des tableaux php, des objets php, un fichier xml etc… Pour ma part j’utilise des objets php et j’implémente pour chaque formulaire la classe Zend_Form (je vais y revenir). Pour plus de clarté dans mon arborescence de fichiers, je place tous mes formulaires, dans le dossier : application/models/Form/ et comme ce formulaire ci concerne l’ajout et/ou la modification d’un utilisateur, mon fichier User.php est dans le dossier : application/models/Form/User. Donc le fichier de base doit ressembler à ça :
<?php
class Model_Form_User_User extends Zend_Form {
public function init() {
}
}
Comme on peut le voir, il faut étendre la classe Zend_Form, et mettre tout notre code qui ajoute des éléments dans la méthode init(). Ce code sera directement exécuter lors de la création d’un nouveau formulaire. Mais on va très vite ajouter des éléments à notre formulaire, sinon il ne va pas servir à grand chose. On peut, par exemple, ajouter un champ input texte grâce a ce code (le principe reste le même pour tous les types d’éléments) :
$champText = new Zend_Form_Element_Text('champText');
$champText->setLabel('un champ texte')
->setRequired(true)
->addValidator('notEmpty')
->addFilter('StripTags')
->addFilter('StringTrim');
On commence par créer un nouvel élément de type input texte, puis on ajoute un label, on ajoute ensuite un validateur qui (dans ce cas) oblige la valeur à être rempli, puis on ajoute deux filtres. Il existe un grand nombre de validateurs et de filtres. On en verra quelques un ici. Mais comme on peut se douter, on va très souvent répéter le même code. Donc on peut se créer une petite classe qui ne va servir qu’a ajouter un champ de type input texte : (application/models/Form/EText.php)
<?php
/**
* @author lyrix
*
*/
class Model_Form_EText extends Zend_Form_Element_Text {
public function __construct($options = null,$label){
parent::__construct($options);
$this->setLabel($label)
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim');
}
}
Voilà, je vous donne maintenant une partie du code du formulaire et j’explique les points nouveaux.
<?php
class Model_Form_User_User extends Zend_Form {
public function init() {
$this->setName ( 'add_user' );
$id = new Zend_Form_Element_Hidden ( 'idUser' );
$nom = new Model_Form_EText ( 'nom', 'form_user_add_name' );
$prenom = new Model_Form_EText ( 'prenom', 'form_user_add_firstname' );
$email = new Model_Form_EText ( 'email', 'form_user_add_mail' );
$email->addValidator ( 'EmailAddress' )->addValidator ( new Zend_Validate_Db_NoRecordExists ( 'users', 'email' ) );
$password = new Zend_Form_Element_Password ( 'password' );
$password->setLabel ( 'form_user_add_password' )->addFilter ( 'StripTags' )->addFilter ( 'StringTrim' )->setRequired ( true );
$password2 = new Zend_Form_Element_Password ( 'password2' );
$password2->setLabel ( 'form_user_add_password2' )->addFilter ( 'StripTags' )->addFilter ( 'StringTrim' );
$active = new Zend_Form_Element_Checkbox ( 'active' );
$active->setLabel ( 'form_user_add_enable' )->addFilter ( 'StripTags' )->addFilter ( 'StringTrim' )->setValue ( 1 );
$level = new Zend_Form_Element_Select ( 'level' );
$level->setLabel ( 'form_user_add_level' )->addFilter ( 'StripTags' )->addFilter ( 'StringTrim' );
$levelOptions = array ();
for($i = 0; $i <= 9; $i ++) {
$levelOptions [$i] = array ('key' => $i, 'value' => $i );
}
$level->addMultiOptions ( $levelOptions );
$submit = new Zend_Form_Element_Submit ( 'submit' );
$submit->setAttrib ( 'id', 'submitbutton' )->setLabel ( 'form_user_add_submit' );
$elements = array ($id, $nom, $prenom, $email, $password, $password2, $active, $level, $submit );
$this->addElements ( $elements );
}
}
?>
Pour commencer je donne un nom a mon formulaire, ce qui peut être pratique pour le retrouver, en effet le nom du formulaire correspond a son id dans le code html et css. On peut aussi ajouter d’autre options, comme l’action du controller, mais dans notre cas, le formulaire et sa page de destination (l’action) sont les mêmes, donc on pas besoin de le définir.
Ensuite, comme on peut le voir, on crée plusieurs éléments :
- l’id qui est un élément de type hidden, qui nous servira lors des mises à jour d’un utilisateur.
- nom, prenom qui sont des éléments de type Etext, les éléments qu’on a crée un peu plus haut.
- Le champ email est aussi un champs de type Etext,
- On a ajouter un validateur d’adresse mail, pratique, le boulot est déjà fait ! ( ->addValidator (‘EmailAddress’) )
- On ajoute un second validateur qui vérifie que l’adresse mail n’est pas déjà dans la base de donnée ( addValidator (new Zend_Validate_Db_NoRecordExists (‘users’,'email’)) ). Le premier paramètre est le nom de la table, le second l’attribut qui doit être unique.
- De type Select
- On ajoute dans un tableau des correspondances key = > value qui représentent les options du select
- On ajoute le tableau au select
Les labels ne sont pas très significatifs ou user-friendly, c’est normale, j’utilise la traduction du zend framework. Enfin il ne reste plus qu’a ajouter tous ces éléments dans le formulaire lui même et le tours est joué, on a notre formulaire. Je tiens a rappelé qu’il existe vraiment un grand nombre de façon de fabriquer un formulaire, d’ajouter des filtres, des validateurs. Il y a quelques exemples ici, mais je ne peux pas faire un exemple pour chaque cas. Je vous recommande donc d’aller faire un tour sur sur le doc du zf.
Affichage du formulaire
Je ne vais pas m’occuper ici de styler le formulaire. Juste de l’afficher comme il vient. Par défaut zf utilise ce qu’on appel des décorateurs, il est possible de les personnaliser, mais ce n’est pas le but ici. Vous pouvez aller faire un tours sur le site de dator pour avoir un exemple de ce qu’on peut faire (même si je ne suis pas fan de sa technique, mais elle reste valide à 100% … huhu). Pour les décorateurs, le code a ajouter / modifier doit se trouver dans la classe qui fabrique notre formulaire.
Donc il va falloir éditer la vu qui affichera le formulaire. Chez moi c’est application/modules/Frontend/views/scripts/user/index.phtml car c’est le controller userController.php qui va être appelé ici. Voilà a quoi doit ressembler la vues au minimum :
if (isset($this->formUser)){ ?>
<h2><?php echo $this->translate('view_user_add')?> : </h2>
<?php echo $this->formUser;
}
On fait une simple vérification pour voir sur le formulaire a bien était envoyé par le controller à la vue et on l’affiche.
Le controller du formulaire
Bon on arrive la gestion du controller de notre formulaire. Je vous livre le code et je l’explique ensuite : (application/modules/Frontend/controllers/UserController.php)
<?php
class UserController extends Zend_Controller_Action
{
public function indexAction(){
$form = new Model_Form_User_User();
$this->view->formUser = $form;
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$users = new Model_DbTable_Users();
$row = $users->createRow();
$row->nom = $form->getValue('nom');
$row->prenom = $form->getValue('prenom');
$row->email = $form->getValue('email');
$row->password = md5($form->getValue('password'));
$row->active = $form->getValue('active');
$row->level = $form->getValue('level');
$result = $row->save();
//On gere le resultat et l'action qui s'en suit.
$form->reset();
}
}
}
}
Petit apercu avant de continuer
$form = new Model_Form_User_User(); $this>view->formUser = $form;
On commence par instancier la classe du formulaire et on le donne à la vue. A partir de ce moment on peut déjà tester si notre formulaire s’affiche bien. Bien entendu ça ne sert a rien de cliquer sur envoyer, ça ne fonctionnera pas ! Comme on a pu le voir plus haut, la page de destination du formulaire est elle même. Donc le controller est le même. C’est donc dans la même méthode du même controller qu’on teste en premier si notre formulaire est valide et qu’ensuite on traite le résultat.
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
}
On commence avec le IF pour voir si il y a eu des données de type POST, POST étant le type d’envoi par défaut pour les formulaires. On peut bien entendu envoyer notre formulaire en GET en modifiant la classe user.php. Ensuite on récupère nos données.
if ($form->isValid($formData)) {
}
Ce point est très intéressant, car il va automatiquement voir si notre formulaire est valide. C’est a dire qu’il va exécuter chaque validateurs de nos élement composant le formulaire. Si il y a au moins une erreur la validation ne passera pas, mais zf va automatiquement refaire notre formulaire en reprenant les valeurs insérer, et en ajouter un message ou il y a eu des erreurs (par exemple « la valeur est requise »). Ici encore on peut personnaliser le message. Dans mon cas j’utilise encore une fois la traduction. Bon et si le formulaire est valide ?
$users = new Model_DbTable_Users();
$row = $users->createRow();
$row->nom = $form->getValue('nom');
$row->prenom = $form->getValue('prenom');
$row->email = $form->getValue('email');
$row->password = md5($form->getValue('password'));
$row->active = $form->getValue('active');
$row->level = $form->getValue('level');
$result = $row->save();
Comme on veut (à la base) que notre formulaire nous serve à ajouter des utilisateurs en base, et bien on reprend le même code que dans le tutoriel sur la gestion des BDD ; On instancie la classe Model_DbTable_Users, on crée un nouvelle ligne, on ajoute tous nos champs, et enfin on sauvegarde. Bien entendu, on peut mettre la ligne $row->save() dans un bloque try-catch, mais si on a bien fait notre boulot sur les validateurs, normalement, il n’y a pas besoin.
$form->reset();
Enfin on remet a zéro notre formulaire, c’est a dire qu’on vide tout les champs. On peut par la suite ajouter un message (pour l’ergonomie) qui s’affichera expliquant que l’ajout s’est bien effectué. Ici c’est donc juste un passage de variable à la vue. Voilà notre formulaire fonctionne mais il y reste encore des choses a voir.
Double vérification du password ; Validation avec données.
Du fait qu’il faille vérifier que l’utilisateur a bien rentré deux fois le même password, on va avoir besoin d’au moins un des deux password. On va donc redéfinir la méthode isValid de la classe Model_Form_User_User qui étend Zend_Form je vous rappel. Cette classe, comme on a vu plus haut, est systématiquement appelé, et elle appel à son tour tous les validateurs de tous les éléments. On va utiliser pour vérifier que l’utilisateur a bien rentré deux fois le même password grâce une classe de validation réalisé par l’ami dator :
class App_Validate_PasswordMatch extends Zend_Validate_Abstract
{
const PASSWORD_MISMATCH = 'passwordMismatch';
protected $_compare;
protected $_messageTemplates = array(
self::PASSWORD_MISMATCH => "PASSWORD_MISMATCH"
);
public function __construct($compare){
$this->_compare = $compare;
}
public function isValid($value){
$this->_setValue((string) $value);
if ($value !== $this->_compare) {
$this->_error(self::PASSWORD_MISMATCH);
return false;
}
return true;
}
}
On peut la mettre en bas de la classe Model_Form_User_User, ça ne pose pas de problème. Du coup il ne nous reste plus qu’a l’utiliser :
public function isValid($data)
{
$this->getElement('password')->addValidator(new App_Validate_PasswordMatch($data['password2']));
if ($this->getElement('email')->getValue() == $data['email']){
$this->getElement('email')->removeValidator ( "Zend_Validate_Db_NoRecordExists" );
}
return parent::isValid($data);
}
On commence par récupérer l’élément password, auquel on ajoute notre validateur personnalisé en lui donnée comme paramètre le password2 rentré par l’utilisateur. Ensuite on appelle la méthode « classique ».
Conclusion
Et voilà, on a finit avec notre formulaire. On peut bien sur l’améliorer et surtout le rendre plus joli. Je vous redonnerai tous les fichiers nécessaires lors de la deuxième
et on peut continuer avec la 2eme partie : affichage, modification et suppression.
Articles en rapport :
- Zend Framework, Formulaire et Base de donnée, partie 2
- Gerer l’authentification avec Zend_Auth du Zend Framework
- Comment bien démarrer un projet Zend Framework grâce aux Zend_Tool
- Zend Framework
- Application de site E-Commerce [Code-Source]


Là ou ce serai intéressant c’est de générer tout ca surtout
Qu’est-ce que tu veux dire pas générer tout ca ? tu voudrais que le formulaire ce construise tout seul ? c’est possible, mais je ne vois pas trop comment faire pour que zend identifie tout seul que le champ email doit etre unique, que password doit etre chiffrer etc …
Tu ne déclares pas de méthode (setMethod(‘post’)) dans ta classe Model_Form_User_User?
Non non, je ne vois pas trop a quoi cela pourait servir. Pourquoi fait tu ca toi ?
Dans ton code comment sait t-on que les données du formulaire seront envoyées en post?
Grace au controller :
if ($this->_request->isPost()) {
Ce code regarde si il y a eu des données en post
Puis ensuite il tente des les valider. Donc il y a forcement eu des donnée en POST
Facile non ?
Je pensais qu’il fallait préciser le format des données (ici post) dans le modèle pour que justement on puisse les récupérer dans le controlleur en précisant isPost. Je sais pas si je suis clair
;
Je vois ce que tu veux dire. Par défaut les données sont envoyé en post. Mais c’est vrai qu’on peut forcer le model à les envoyer en GET. C’est comme on veut
$this->(‘post’);
Ou :
$this->get’);
C’était ca ta question ?
Oui voila c’était ma question.En faite je ne savais pas que par défaut c’était en post.Merci de tes précisions et merci pour tes tutos
Je me bats avec les formulaire de Zend depuis des heures… mon soucis c’est que quand je clique sur le bouton de validation de mon formulaire, il ne se passe rien… mais alors rien de rien!
Si tu est dans une architecture mvc et que tu fais ce que j’ai décris plus haut, il ne devrait pas y avoir de problème.
Moi j’ai choisit d’utiliser la meme page pour l’affichage du formulaire et pour l’action de celui ci. Si tu veux, tu peux definir une autre page pour ton action, et au moins tu verras si à la suite d’un clique, ton navigateur change de page.
Sinon une question bete, as-tu bien fait la controller ? car en gros c’est lui qui gère tout !
Sinon a la fin de la partie 2 tu as un liens pour télécharger les fichiers : http://blog.lyrixx.info/wp-content/uploads/2009/11/formulaire.zip
Il ce peut que tout ne colle pas pile poile, étant donnée que ces fichiers viennent d’un projet perso … Mais dans la globalité, ca marche
Question subsidiaire…
Comment fait-on pour changer les messages qui sont afficher en cas d’erreur?? Est-il possible de surcharger la function de base de Zend?
J’ai aussi un soucis avec le mécanisme de vérification des mails.. la function ne marche pas chez moi.. à suivre..
tu peux utiliser la méthode de traduction pour changer les messages d’erreur
Merci.. je vais essayer ça
hello,
Je me demandais comment on faisait pour vérifier la présence de doublon dans la base de données?
Parce que la, le formulaire ne vérifie pas la présence de doublon non?
Merci!
Déja dans la base de donnée, j’utilise des clés primaires et des uniques la ou j’en ai besoin.
Sinon grâce au validateur Zend_Validate_Db_NoRecordExists, je vérifie qu’il n’y ai pas de doublons
voila
Merci pour cette réponse et ce billet !
j’ai crée un formulaire et quand j’essaie de l’afficher j’ai une erreur:
Fatal error: Class ‘Client_Form’ not found in /home/vincent/sites/gts/application/controllers/ClientController.php on line 13
Merci pour ton aide
Tu as surement mal nommer tes dossiers ou tes classes.
Regarde ce tutos la : http://blog.lyrixx.info/zend/zend-comment-utiliser-un-model/
Bonjour/Bonsoir Lyrixx,
J e travaille sur un projet web avec zend et je voulait savoir si c’est possible d’utiliser deux sur une seule vue en utilisant $this->view car j’ai $this->view->form , $this->view->form1 ,$this->view->form1 est affiché et l’autre non.
merci d’avnce à bientôt
oui, tu peux passer plusieurs variables a ta vue. il faut que tu pense a toutes les afficher dans la vue.
Salut!
pourquoi ne crées-tu pas directement le dossier forms dans le dossier application.
Le framework charge automatiquement les class qui sont dans ce dossier. Bien sûr les noms des fichiers doivent respecter les conventions de Zend et les noms de class ( class Form_Monformulaire).
Je sais je sais, je suis justement en train de preparer un nouveau tuto la dessus
Bonjour Greg,
ton bloc est trés pertinent.ça aide beaucoup.
j’essaye d’utiliser ce ke tu décrit pour programmer avec Zend Framework dont je suis un débutant.Je regarde aussi les commentaires.
Merçi une fois de plus Greg.
Merci beaucoup Iywa
ca fait plaisir
Merçi pour le tuto c’est pratique.
Voilà l’erreur kil m’affiche kan j’exécute:
Fatal error: Uncaught exception ‘Zend_Controller_Dispatcher_Exception’ with message ‘Invalid controller specified (index)’ in C:\wamp\www\TestZend\library\Zend\Controller\Dispatcher\Standard.php:241 Stack trace: #0 C:\wamp\www\TestZend\library\Zend\Controller\Front.php(934): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http)) #1 C:\wamp\www\TestZend\index.php(35): Zend_Controller_Front->dispatch() #2 {main} thrown in C:\wamp\www\TestZend\library\Zend\Controller\Dispatcher\Standard.php on line 241
Et à la ligne 35 de mon code index.php g ça :$frontController->dispatch();
CA veut dire que tu essaies d’aller sur un controller qui n’existe pas. vu que c’est le index, a mon avis c’est ton .htaccess qui n’est pas bon ou alors ton fichier de config de apache…
Bonjour,
j’ai regardé le fichier .htaccess mé il n’y a rien.C’est le mm fichier que j’utilise chaque fois.Pour la configuration d’apache j’utilise WampSever j’ai fait la configuration nécessaire ( décommenté le mod_rewrite et mettre à All tous les none de AllowOverride).Je pense c’est la configuration à faire.
Cordialement Lywa
Bonjour,
j’ai du faire une erreur quelque part. Même avec les fichiers de http://blog.lyrixx.info/wp-content/uploads/2009/11/formulaire.zip , j’ai ces erreurs qui s’affichent :
Fatal error: Uncaught exception ‘Zend_Controller_Dispatcher_Exception’ with message ‘Invalid controller specified (error)’ in /home/aurelien/NetBeansProjects/Budget/library/Zend/Controller/Dispatcher/Standard.php:242 Stack trace: #0 /home/aurelien/NetBeansProjects/Budget/library/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http)) #1 /home/aurelien/NetBeansProjects/Budget/library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch() #2 /home/aurelien/NetBeansProjects/Budget/application/Bootstrap.php(7): Zend_Application_Bootstrap_Bootstrap->run() #3 /home/aurelien/NetBeansProjects/Budget/library/Zend/Application.php(366): Bootstrap->run() #4 /home/aurelien/NetBeansProjects/Budget/public/index.php(26): Zend_Application->run() #5 {main} thrown in /home/aurelien/NetBeansProjects/Budget/library/Zend/Controller/Dispatcher/Standard.php on line 242
je pense que cela vient du bootstrap.php. Auriez vous une idée ?
Je précise que je n’ai pas touché à la config de mon apache qui m’afficher tres bien la page de Zend et que je n’ai pas touché au .htaccess
Bonsoir,
N aurais tu pas interverti les valeurs label et la valeur « for » (celle entre les parentheses lors de l instanciation de l objet d’element de formulaire) :
$password = new Zend_Form_Element_Password ( ‘password’ );
$password->setLabel ( ‘form_user_add_password’ )
Car dans ma vue les labels sont intervertis ce qui est pas top j ai des noms de labels de type :
‘form_user_add_password
Ah oui. En fait je n’ai pas inversé ! C’est juste que ce code vient d’un projet, et que j’ai fait des copiers / collers peut etre un peu trop rapidement. En fait j’utilise Zend_Translate, qui me permet de faire de la traduction. D’ou les espece de code (« form_user_add_password »)
Voila