Section: Initialiser un formulaire
« Créer un fichier jforms 1.1 | ^ jForms : des formulaires automatiques | Affichage d'un formulaire » |
− Table des matières
Les données d'un formulaire jforms sont stockées automatiquement par jForms
dans un système de cache. On manipule ces données au travers d'un
objet formulaire, instance d'une classe héritant de
jFormsBase
. Cette classe est générée automatiquement à partir du fichier
XML que vous fournissez. Comme pour les DAOs, elle est stockée dans un fichier cache
évitant de la recréer à chaque utilisation.
Dans les contrôleurs, vous créez, récupérez et détruisez cet
objet formulaire via les méthodes statiques de l'objet jForms
.
Les actions à mettre en oeuvre ¶
Comme il est déjà expliqué dans le guide sur les formulaires classiques, pour faire une gestion complète de la saisie d'un formulaire, la création des actions suivantes est recommandée (les noms utilisés sont juste à titre d'exemple, vous utilisez les noms que vous voulez bien sûr):
- une action "prepare" qui crée avec
jForms
une nouvelle instance d'un objet formulaire. S'il faut pré-remplir le formulaire, cette action devra le faire aussi. Redirection vers "show". - une action "show" qui récupère l'instance du formulaire, toujours avec
l'objet
jForms
, et l'utilise dans un template pour l'afficher avec les éventuelles erreurs de saisie trouvées lors d'une validation précédente. La soumission du formulaire par l'utilisateur dirigera vers l'action "save". - une action "save". l'instance du formulaire est récupérée auprès de
jForms
, et elle est remplie avec les données reçues du navigateur. Elle pourra ensuite lancer la vérification des données dans le formulaire. S'il y a des erreurs, il y aura une redirection vers "show". Sinon on pourra traiter les données (sauvegarde en base de données par exemple) et ensuite rediriger vers "end" - une action "end", qui détruira l'instance du formulaire jforms (ce qui effacera les données correspondantes dans son cache), et affichera éventuellement une page de confirmation, ou alors redirigera vers une autre action quelconque...
Créer une instance d'un formulaire ¶
Avant de pouvoir utiliser jForms, il faut bien sûr créer un fichier xml décrivant le formulaire,
et il faut ensuite avant toute utilisation, qu'une de vos actions crée une
instance de votre formulaire. Cela se fait au moyen de la méthode statique
create
de la classe jForms
. Comme toutes les autres méthodes
statiques de la classe jForms
, elle prend en premier argument le sélecteur
du fichier xml, et un deuxième argument facultatif qui est un identifiant de
l'instance à créer.
En admettant que votre fichier xml soit contact.form.xml
dans le module
"main" :
$form = jForms::create("main~contact");
La variable $form contiendra un objet qui aura pour classe, celle créée
lors de la lecture du fichier XML, et qui hérite de jFormsBase
. Vous
utiliserez ensuite cette variable $form pour manipuler les données du
formulaire.
Dans cet exemple, nous n'indiquons pas le deuxième paramètre. En effet celui-ci ne sert que lorsque l'on veut éditer des informations qui existent déjà. Par exemple, pour un formulaire pour éditer un produit qui est en base de données, on indiquera l'identifiant de ce produit.
Pourquoi ? Avec un navigateur web, l'utilisateur a la possibilité d'ouvrir plusieurs pages à la fois. Il a donc la possibilité d'afficher plusieurs fois la même page qui afficherait par exemple ce formulaire d'édition de produit, mais avec à chaque fois un produit différent. Pour éviter qu'à chaque fois que l'on ouvre cette page, donc qu'à chaque fois que l'on créé une instance du formulaire jForms, on aille écraser les données du même formulaire d'un autre produit ouvert en même temps, on donne un identifiant de formulaire. Ainsi il n'y a pas de collision des données de chaque instance de formulaire. On peut donner ce que l'on veut comme identifiant (une chaine, un nombre), et en général on donne l'identifiant de l'enregistrement SQL quand il s'agit de l'édition de ce genre d'information.
En admettant que votre fichier xml soit product.form.xml
dans le module
shop, voici un exemple de création d'un formulaire pour éditer un produit
existant.
$form = jForms::create("shop~product", $product_id);
Bien sûr, quand il s'agit d'afficher un formulaire vierge pour éditer un nouveau produit, il n'y a pas d'identifiant, et vous n'êtes pas obligé d'en donner un.
$form = jForms::create("shop~product"); // édition d'un nouveau produit
Pour l'exemple précédent avec le formulaire de contact, nous n'indiquons pas d'identifiant, car on émet l'hypothèse ici qu'il s'agit d'un formulaire pour que l'utilisateur envoie une demande de contact : ce sera donc toujours un formulaire vierge.
Initialisation d'un formulaire ¶
Après la création d'un formulaire, il est peut être nécessaire de le pré-remplir.
Initialisation simple ¶
Pour cela, vous utiliserez la méthode setData()
sur l'objet formulaire,
qui accepte en argument, le nom du champ à préremplir, et la valeur à lui donner
:
$form->setData("prenom","Laurent");
Les valeurs peuvent être récupérées d'ailleurs, comme bon vous semble.
Initialisation avec un dao ¶
Cependant, si vous voulez utiliser un dao, il existe un moyen rapide pour
remplir un formulaire. La méthode initFromDao()
permet d'utiliser un DAO
pour remplir plusieurs champs du formulaire. Il suffit d'indiquer à cette
méthode le selecteur du dao à utiliser. Vous pouvez aussi spécifier en deuxième
argument la valeur de la clé primaire si l'identifiant du formulaire ne
correspond pas à la valeur de cette clé (sachant que la valeur peut être un
tableau de valeurs si la clé est sur plusieurs champs). Par défaut donc,
initFromDao()
utilisera la valeur de l'identifiant du formulaire comme
identifiant de l'enregistrement à récupérer.
$form = jForms::create("shop~product", $product_id);
$form->initFromDao("shop~products");
Ici le formulaire sera pré-rempli avec les valeurs de l'enregistrement dont la
clé est $product_id, et le dao "shop~products" sera utilisé pour cette
lecture. Vous pouvez aussi indiquer un objet DAO record à initFromDao()
plutôt qu'un sélecteur.
Cependant, seuls les champs de saisie qui ont le même nom que des propriétés du dao indiqué seront pré-remplis. Les autres resteront vides.
Notez que vous pouvez utiliser plusieurs daos pour pré-remplir les champs. En effet, on peut avoir besoin d'un formulaire qui contient des champs de saisie qui seront stockés dans plusieurs tables.
Initialisation d'un champ à choix multiple ¶
Pour les champs <checkboxes>
et <listbox multiple="true">
, la valeur
à initialiser n'est pas forcément une simple valeur, mais une liste de valeurs
qui correspondent à tous les choix qu'il faut pré-sélectionner. (Attention, on
parle bien ici des valeurs pré sélectionnées, pas de la liste des choix).
On peut donc les initialiser avec setData()
, en leur passant un tableau
contenant les valeurs des choix à présélectionner :
$form->setData('categories', array(5, 8, 10));
En général cependant, ces listes de valeurs sont stockées dans une base de données, dans ce qu'on appelle une table de jointure. C'est à dire une table qui fait la jointure entre deux tables, et dont la clé primaire est constituée de deux clés étrangères, l'une et l'autre appartenant à une autre table. Par exemple, on a une table pour les produits ('products'), une table pour les catégories de produits ('categories'), et si un produit peut appartenir à plusieurs catégories, il faut une table de jointure ('products_categories'), contenant les clés des produits et les clés des catégories qui sont en relation (product_id et category_id).
Pour initialiser la liste ou les cases à cocher, il va donc aller lire dans
cette table 'products_categories' les relations. Il existe pour cela une
méthode, initControlFromDao()
:
$form->initControlFromDao("categories", "shop~products_categories");
Le dao "shop~products_categories" sera utilisé pour lire les valeurs sélectionnées pour le champs catégories. jForms s'attend ici à ce que la première clé déclarée dans le dao corresponde à l'identifiant du produit, et la deuxième clé à l'identifiant des catégories. Si ce n'est pas le cas, il faut alors indiquer les noms de ces clés dans le dao, dans un array à passer en troisième paramètre :
$form->initControlFromDao("categories", "shop~products_categories", array('product_id','category_id'));
Vu qu'il s'agit dans cet exemple de la saisie d'un enregistrement product, et que l'identifiant du formulaire correspond à l'identifiant du produit, la valeur de cet identifiant sera utilisée comme critère de recherche dans la table, pour récupérer les id de catégories correspondantes.
Définir les choix d'un champs à multiple choix ¶
Dans le fichier xml jforms, vous avez vu que pour indiquer la liste des
choix possibles dans un <menulist>
, une <listbox>
, un
<radiobuttons>
ou un <checkboxes>
, vous pouviez indiquer une liste
de valeurs statiques, ou un dao qui servira à récupérer les choix.
Il peut cependant arriver que cela soit insuffisant, et que le remplissage
dépende de critères ou autre. Dans ce cas, vous n'indiquerez pas de balise
<item>
ni d'attribut dao*
dans le fichier xml. Et vous indiquerez la liste
des choix dans votre contrôleur, des manières suivantes.
// récupérez vos données dans un tableau associatif,
$data = array(...);
// on crée un objet implémenté via l'interface jIFormsDatasource2
$datasource = new jFormsStaticDatasource();
$datasource->data = $data
// on récupère le contrôle et on lui indique les données
$form->getControl('nom_du_control')->datasource = $datasource;
$data est un tableau dont les clés sont les valeurs des choix, et les valeurs sont les libellés des choix.
Note : ce remplissage doit se faire dans la même action que celle qui affiche le formulaire. Ces données sont perdues à la fin de l'action.
Activer ou désactiver des champs ¶
Il est possible d'avoir des cas où l'on ne veuille pas afficher certains champs
du formulaire. Vous avez pour cela les méthodes deactivate()
et
isActivated()
. À ces deux méthodes, vous devez indiquer le nom du
contrôle. La deuxième méthode permet de savoir si un champ est activé : on
l'utilisera surtout dans les actions de traitement des données saisies. La
première permet d'activer ou désactiver un champ. On peut lui donner en deuxième
paramètre (facultatif) un booléen qui indique s'il faut désactiver (true) ou
activer (false).
$form->deactivate('nom_du_control');
// équivalent à
$form->deactivate('nom_du_control', true);
// et pour réactiver un contrôle désactivé :
$form->deactivate('nom_du_control', false);
// pour savoir l'état d'activation :
if ($form->isActivated('nom_du_control')) ...
Récupérer une instance d'un formulaire ¶
Dans une action spécifique, vous allez créer un formulaire avec
jForms::create()
, mais dans d'autres actions, vous aurez besoin de
récupérer le formulaire créé, pour en manipuler ses données. Pour cela il y a
deux méthodes statiques de jForms : get()
et fill()
.
La méthode get()
permet de récupérer simplement l'objet formulaire. Comme
pour create()
, vous indiquez un sélecteur :
$form = jForms::get("shop~product");
Si vous aviez donné un identifiant à la création, il faudra le donner aussi ici (récupéré ici à partir des paramètres de la requête http) :
$product_id = $this->param('id');
$form = jForms::get("shop~product", $product_id);
Note : la méthode get()
renvoie null
si le formulaire n'existe pas.
Cela veut probablement dire que l'utilisateur a été à l'url de l'action courante
sans passer par les urls de l'action qui a créé le formulaire. Il faudrait alors
rediriger vers ces actions si $form est null. Ou alors créer directement
le formulaire, ce qui peut être suffisant pour de simples formulaires.
$form = jForms::get("main~contact");
if ($form === null) {
$form = jForms::create("main~contact");
}
La méthode fill()
récupère aussi le formulaire (c'est à dire appel
jForms::get()
), mais exécute aussi une opération supplémentaire : elle
remplit le contenu du formulaire avec les données trouvées en paramètres de la
requête HTTP. En clair, elle est à utiliser lors de la réception du formulaire
rempli par l'utilisateur (voir la section plus loin sur l'utilisation d'un
formulaire après submit).
$product_id = $this->param('id');
$form = jForms::fill("shop~product", $product_id);
Note: l'identifiant (ici id) doit être actuellement récupéré manuellement avant de récupérer le formulaire, mais il est prévu dans les versions ultérieures que cela puisse se faire automatiquement.
Ajouter des champs dynamiquement ¶
On préférera dans la plupart des cas le principe d'activation/désactivation, cela est plus simple à écrire, et en lisant le fichier XML, on a ainsi toute la liste des contrôles possibles.
Cependant, il y a des cas où on ne peut déclarer le composant dans le formulaire, comme par exemple le besoin de créer un nombre indéterminé à l'avance d'un élément précis. Un exemple concret : la saisie de fichiers joints à un article. Le formulaire permet de saisir les données de l'article (son titre, son contenu...), mais aussi d'ajouter des fichiers joints, comme des photos illustrant l'article. Quand on modifie un article, pour chaque photo existante, on voudrait pouvoir avoir un champs pour modifier son titre, un autre pour uploader une nouvelle version de cette photo, et un bouton pour la supprimer. Il faut ainsi créer plusieurs de ces champs de saisies en fonction du nombre de ces photos, sans avoir à en limiter le nombre.
Pour ce genre de cas, il faut alors créer les contrôles "à la main" et les ajouter dans le formulaire.
Le principe est assez simple :
- récupérer le formulaire avec
jForms::get()
oujForms::create()
(mais pasjForms::fill()
, voir plus bas) - instancier un objet qui hérite de
jFormsControl
. Il existe une classe dédiée à chaque type de contrôle :jFormsControlInput
,jFormsControlListbox
,jFormsControlRadiobuttons
,jFormsControlHtmlEditor
, etc. Voir la liste dans la documentation de référence. - ajouter cet objet à l'objet formulaire via la méthode
addControl
, ouaddControlBefore
pour l'ajouter après un autre contrôle existant précis. - vous pouvez ensuite afficher le formulaire, ou le remplir avec les données
en paramètre grâce à la méthode
initFromRequest()
.
Il faut savoir qu'il faut ajouter ces champs à chaque fois que vous créez ou
récupérez le formulaire. En effet, à chaque fois que vous récupérer un
formulaire avec jForms::get()
ou jForms::fill()
, jForms instancie
toujours l'objet form à partir de ce qui est décrit dans le fichier XML (qui est
traduit en classe PHP) et donc sans votre champs. C'est pourquoi il faut ajouter
votre champs non seulement à la creation avant l'affichage, mais aussi avant son
remplissage avec les données soumises.
1 – Ajout du champ à l'initialisation :
$form = jForms::get('myModule~myForm');
$ctrl= new jFormsControlInput('identifiant');
$ctrl->required=true;
$ctrl->datatype->addFacet('maxLength',255);
$ctrl->label='Identifiant';
$ctrl->size=100;
$form->addControl($ctrl);
2 – Gestion après soumission :
$form = jForms::get('myModule~myForm');
$ctrl= new jFormsControlInput('identifiant');
$ctrl->required=true;
$ctrl->datatype->addFacet('maxLength',255);
$ctrl->label='Identifiant';
$ctrl->size=100;
$form->addControl($ctrl);
$form->initFromRequest();
Il est plus esthétique de factoriser la création du champ dans une méthode de
votre contrôleur du type getMyControl()
afin de ne pas dupliquer le code.
- *Attention** : Il ne faut surtout pas utiliser la méthode
fill()
, car cette méthode fait unget()
puis uninitFromRequest()
et ne vous donne donc pas l'opportunité d'ajouter votre champ avant que les données soumises soient stockées dans le formulaire (parinitFromRequest()
).
3 - Pendant le remplissage dynamique d'un contrôle
Si le formulaire contient une liste qui dépend d'un autre contrôle, la liste est remplie via un appel http au contrôleur dédié à jForms.
Lors de cette action, le contrôleur emet un évènement jformsPrepareToFillDynamicList
,
avant de récupérer et renvoyer le contenu de la liste, permettant de préparer
l'objet formulaire avec tous les champs de saisie attendu.
L'évènement contient les paramètres suivants :
form
: l'objet formulaire.controlRef
: l'identifiant du contrôle dont la liste des valeurs sera générée.