Episode 4: Builder: formulaire d'ajout

I. Introduction

Lors du précédent épisode, nous avons générer un module CRUD pour notre table auteur.

Nous allons détailler ici la partie formulaire d'ajout.

II. L'action new du module auteurs

Lorsque l'on cliquer sur le lien "new" de notre module précédement généré, on arrive sur le module "auteurs", et l'action "new"
Editer le fichier module/auteur/main.php, regardons la méthode _new()

  
public function _new(){
   $tMessage=$this->processSave();

   $oAuteur=new row_auteur;
  
   $oView
=new _view('auteurs::new');
   $oView->oAuteur=$oAuteur;
  
  
  
   $oPluginXsrf
=new plugin_xsrf();
   $oView->token=$oPluginXsrf->getToken();
   $oView->tMessage=$tMessage;
  
   $this
->oLayout->add('main',$oView);
}
    


Nous voyons ici que l'on récupère dans un premier temps un tableau $tMessage d'une méthode interne "processSave()" (nous y reviendrons après)

On instancie un objet $oAuteur à partir de la classe row_auteur.
Ensuite comme d'habitude nous créons un objet view à partir de notre vue "auteurs::new) (fichier module/auteur/view.new.php)
Puis on lui assigne l'objet $oAuteur précédement créé.

Nous instancions ensuite le plugin plugin_xsrf, que nous utilisons pour assigner un token à notre vue.
Nous assignons le tableau $tMessage récupéré à la première ligne.

Et enfin nous envoyons notre vue enrichier à notre layout (à l'emplacement principal "main")

III. Zoom sur notre vue new

Nous avons vu que nous instancions la vue auteurs::new

  
<?php
$oForm
=new plugin_form($this->oAuteur);
$oForm->setMessage($this->tMessage);
?>
<form action="" method="POST" >
<table class="tb_new">
   <tr>
       <th>Nom</th>
       <td><?php echo $oForm->getInputText('nom')?></td>
   </tr>
   <tr>
       <th>Pr&eacute;nom</th>
       <td><?php echo $oForm->getInputText('prenom')?></td>
   </tr>
   <tr>
       <th></th>
       <td>
           <p>
               <input type="submit" value="Ajouter" /> <a href="<?php echo $this->getLink('auteurs::list')?>">Annuler</a>
           </p>
       </td>
   </tr>
</table>
<?php echo $oForm->getToken('token',$this->token)?>
</form>
   

Dans cette vue, nous retrouvons notre objet $oAuteur ainsi que notre tableau $tMessage précédement assignés.
Nous voyons également la création d'un objet plugin_form, utilisé ensuite pour construire nos différents champs de formulaire.
Exemple:

  
<td><?php echo $oForm->getInputText('nom')?></td>
   

Notez également deux choses: un lien permettant de revenir au tableau listant les enregistrements

  
<a href="<?php echo $this->getLink('auteurs::list')?>">Annuler</a>
    


Et également un code permettant d'afficher le fameux token

  
<?php echo $oForm->getToken('token',$this->token)?>
   

Pour information, le token sert ici à se protéger de la faille xsrf, plus d'informations sur la page de spécialisé sur la sécurité

Il nous reste une chose à voir: ce fameux tableau $tMessage récupéré dans le module, assigné à la vue pour etre passée à l'objet plugin_form.

IV. tableau $tMessage et la méthode processSave()

Dans le module, nous avons vu en amont de l'action _new()

  
public function _new(){
   $tMessage=$this->processSave();
    


Allons voir ce que cette méthode contient:

  
private function processSave(){
   if(!_root::getRequest()->isPost() ){ //si ce n'est pas une requete POST on ne soumet pas
       return null;
   }
  
   $oPluginXsrf
=new plugin_xsrf();
   if(!$oPluginXsrf->checkToken_root::getParam('token') ) ){ //on verifie que le token est valide
       return array('token'=>$oPluginXsrf->getMessage() );
   }

   $iId=_root::getParam('id',null);
   if($iId==null){
       $oAuteur=new row_auteur  
   
}else{
       $oAuteur=model_auteur::getInstance()->findById_root::getParam('id',null) );
   }
  
   $tColumn
=array('nom','prenom');
   foreach($tColumn as $sColumn){
       $oAuteur->$sColumn=_root::getParam($sColumn,null) ;
   }
  
  
   
if($oAuteur->save()){
       //une fois enregistre on redirige (vers la page liste)
       _root::redirect('auteurs::list');
   }else{
       return $oAuteur->getListError();
   }
  
}
    


En amont de cette méthode, on vérifie si la requête web est de type post, si ce n'est pas le cas, le formulaire n'a pas été soumis, la méthode ne renvoit rien.

Ensuite, on instancie l'objet plugin_xsrf pour vérifier que le jeton est valide*.
* la page de spécialisé sur la sécurité

On récupère l'id de l'auteur: si il est vidé, on est dans le cas d'un ajout, sinon on est dans le cadre d'une modification.
Dans notre cas présent de l'action _new(), on a l'id non renseigné (premier cas)

  
$iId
=_root::getParam('id',null);
if(
$iId==null){
   $oAuteur=new row_auteur  
}else{
    


On instancie un objet row_auteur vide
Puis on boucle sur les champs du formulaire pour les renseigner sur l'objet à partir des paramètres soumis via le formulaire.

  
$tColumn
=array('nom','prenom');
foreach(
$tColumn as $sColumn){
   $oAuteur->$sColumn=_root::getParam($sColumn,null) ;
}
    


Enfin on éssaie d'enregistrer:

  
if($oAuteur->save()){
   //une fois enregistre on redirige (vers la page liste)
   _root::redirect('auteurs::list');
    


Si cela se passe bien, on redirige vers la page contenant le tableau des auteurs.
Sinon

  
}else{
   return $oAuteur->getListError();
}
    


On retourne le tableau des erreurs.

Qui pour rappel était récupéré dans notre méthode _new() dans un tableau $tMessage

  
public function _new(){
   $tMessage=$this->processSave();
    


Puis assigné à notre vue

  
$oView
->tMessage=$tMessage;
    


Enfin celui-ci était chargé dans l'objet plugin_form

  
<?php
$oForm
=new plugin_form($this->oAuteur);
$oForm->setMessage($this->tMessage);
    



V. Gestion d'enregistrement: ajout de contraintes

Actuellement, on peut ajouter un auteur sans nom ni prénom ce qui n'est pas cohérent

Nous allons ajouter une contrainte pour obliger à renseigner un nom et prénom.
Editez le fichier model model/model_auteur.php
Regardons la class row_auteur

  
class row_auteur extends abstract_row{
  
   
protected $sClassModel='model_auteur';
  
   
/*exemple jointure
   public function findAuteur(){
       return model_auteur::getInstance()->findById($this->auteur_id);
   }
   */
   /*exemple test validation*/
   private function getCheck(){
       $oPluginValid=new plugin_valid($this->getTab());
      
      
       
/* renseigner vos check ici
       $oPluginValid->isEqual('champ','valeurB','Le champ n\est pas &eacute;gal &agrave; '.$valeurB);
       $oPluginValid->isNotEqual('champ','valeurB','Le champ est &eacute;gal &agrave; '.$valeurB);
       $oPluginValid->isUpperThan('champ','valeurB','Le champ n\est pas sup&eacute; &agrave; '.$valeurB);
       $oPluginValid->isUpperOrEqualThan('champ','valeurB','Le champ n\est pas sup&eacute; ou &eacute;gal &agrave; '.$valeurB);
       $oPluginValid->isLowerThan('champ','valeurB','Le champ n\est pas inf&eacute;rieur &agrave; '.$valeurB);
       $oPluginValid->isLowerOrEqualThan('champ','valeurB','Le champ n\est pas inf&eacute;rieur ou &eacute;gal &agrave; '.$valeurB);
       $oPluginValid->isEmpty('champ','Le champ n\'est pas vide');
       $oPluginValid->isNotEmpty('champ','Le champ ne doit pas &ecirc;tre vide');
       $oPluginValid->isEmailValid('champ','L\email est invalide');
       $oPluginValid->matchExpression('champ','/[0-9]/','Le champ n\'est pas au bon format');
       $oPluginValid->notMatchExpression('champ','/[a-zA-Z]/','Le champ ne doit pas &ecirc;tre a ce format');
       */

       return $oPluginValid;
   }

   public function isValid(){
       return $this->getCheck()->isValid();
   }
   public function getListError(){
       return $this->getCheck()->getListError();
   }
   public function save(){
       if(!$this->isValid()){
           return false;
       }
       parent::save();
       return true;
   }

}
    


On peut voir ici, qu'à l'appel de la méthode save() de notre objet, on vérifie la cohérence via la méthode getCheck()

  
public function isValid(){
   return $this->getCheck()->isValid();
}
public function 
getListError(){
   return $this->getCheck()->getListError();
}
public function 
save(){
   if(!$this->isValid()){
       return false;
   }
   parent::save();
   return true;
}
    


Pour rappel, dans le cas ou cette méthode retournerai false, on appelle getListError()

  
if($oAuteur->save()){
   //une fois enregistre on redirige (vers la page liste)
   _root::redirect('auteurs::list');
}else{
   return $oAuteur->getListError();
}
    



VI. Zoom sur la méthode getCheck()


  
private function getCheck(){
   $oPluginValid=new plugin_valid($this->getTab());
  
  
   
/* renseigner vos check ici
   $oPluginValid->isEqual('champ','valeurB','Le champ n\est pas &eacute;gal &agrave; '.$valeurB);
   $oPluginValid->isNotEqual('champ','valeurB','Le champ est &eacute;gal &agrave; '.$valeurB);
   $oPluginValid->isUpperThan('champ','valeurB','Le champ n\est pas sup&eacute; &agrave; '.$valeurB);
   $oPluginValid->isUpperOrEqualThan('champ','valeurB','Le champ n\est pas sup&eacute; ou &eacute;gal &agrave; '.$valeurB);
   $oPluginValid->isLowerThan('champ','valeurB','Le champ n\est pas inf&eacute;rieur &agrave; '.$valeurB);
   $oPluginValid->isLowerOrEqualThan('champ','valeurB','Le champ n\est pas inf&eacute;rieur ou &eacute;gal &agrave; '.$valeurB);
   $oPluginValid->isEmpty('champ','Le champ n\'est pas vide');
   $oPluginValid->isNotEmpty('champ','Le champ ne doit pas &ecirc;tre vide');
   $oPluginValid->isEmailValid('champ','L\email est invalide');
   $oPluginValid->matchExpression('champ','/[0-9]/','Le champ n\'est pas au bon format');
   $oPluginValid->notMatchExpression('champ','/[a-zA-Z]/','Le champ ne doit pas &ecirc;tre a ce format');
   */

   return $oPluginValid;
}
    


Vous avez ici des exemples de contraintes commentée. Ici nous souhaitons que les champs nom et prénom ne soient pas vide, nous allons ajouter ces deux contraintes ainsi

  
private function getCheck(){
   $oPluginValid=new plugin_valid($this->getTab());
   $oPluginValid->isNotEmpty('nom','Le nom ne doit pas &ecirc;tre vide');
   $oPluginValid->isNotEmpty('prenom','Le pr&eacute;nom ne doit pas &ecirc;tre vide');

   return $oPluginValid;
}
    


Pour préciser: le premier champ est le nom du champ en base de données, et le second paramètre le message d'erreur en cas de contrainte non respectée.
En validant le formulaire vide, on voit ici les deux messages d'erreur:


Pour information, les contraintes étant ajoutée sur la classe modèle, toute action enregistrant via cette classe un auteur se devra de respectées cette méthode getCheck, que ce soit en web, webservice, ligne de commande...