Tous les chemins de fichier ou dossier indiqués correspondent à la notion de chemin SPIP.
Contenu de base d’une saisie
Une saisie se compose, basiquement, de trois éléments :
- l’élément indispensable est le contrôleur, il s’agit d’un squelette indiquant comment doit s’afficher la saisie dans un formulaire ;
- on peut lui adjoindre une vue, il s’agit d’un squelette indiquant comment présenter le résultat de la saisie;
- on peut également lui adjoindre un constructeur, il s’agit d’un fichier .yaml
permettant d’expliquer comment configurer la saisie dans les formulaires permettant de construire des formulaires, par exemple dans Formidable.
Un contrôleur
Définition
Le contrôleur est un squelette <saisie>.html
à placer dans un dossier saisies
.
Ce squelette génère le code html de la saisie. Sauf exception, il ne doit pas contenir le label et les messages d’erreur, ni l’élèment HTML englobant (<div>
ou <li>
selon la version de SPIP) . Ces éléments sont ajoutés automatiquement via le squelette saisies/_base.html
pour la plupart des saisies. Il est toutefois possible de créer des saisies autonomes qui ne dépendent pas de saisies/_base.html
.
Comme tout squelette SPIP, il peut utiliser des boucles, balise, etc. Les réglages de la saisie sont disponibles dans le #ENV
.
Exemple
Voici le contrôleur de la saisie input
, c’est-à-dire le squelette saisies/input.html
.
[(#REM)
Parametres supplementaire :
- ** data : tableau de donnees indice=>valeur
- defaut : valeur par defaut du parametre
- type : type de l'input (defaut: text)
- class : classe(s) css ajoutes a l'input
- size : taille du champ
- maxlength : nombre de caracteres maximum
- disable : champ insaisissable ? 'oui' (defaut : '')
- valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
- autofocus : indique si le champ prend le focus a l'affichage (HTML5 requis)
- placeholder : texte du placeholder
- cle_secrete : l'input est une cle secrete. On n'affiche pas la valeur mais simplement un placeholder indiquant les premiers élèments de la clef secrete
Exemple d'appel :
[(#SAISIE{input,couleur_foncee,
label=<:spa:couleur_foncee:>,
size=7,
data=#ARRAY{
0,valeur0,
1,valeur1,
2,valeur2}})]
]
#SET{type,#ENV{type,text}}
[(#REM) data peut être une chaine qu'on sait décomposer ]
#SET{data, #ENV*{data, #ENV*{datas}}}
#SET{data, #GET{data}|saisies_chaine2tableau}
[(#REM) Pas de HTML5, pas de data]
#SET{data, #HTML5|?{#GET{data}}}
[(#REM) l'attribut autocomplete ne peut avoir pour valeur que on ou off ]
#SET{val_autocomplete, #ARRAY}
#SET{val_autocomplete, #GET{val_autocomplete}|push{on}}
#SET{val_autocomplete, #GET{val_autocomplete}|push{off}}
[(#REM) cle secrete > on modifie le place holder]
#SET{placeholder,''}
[(#ENV{cle_secrete}|oui)
#SET{placeholder,#ENV{valeur_forcee,#ENV{valeur,#ENV{{default}}}|saisies_masquer_cle_secrete}
]
[(#ENV{cle_secrete}|non)
#SET{placeholder,#ENV{placeholder}}
]
[(#REM) permettre de donner un identifiant de list specifique en option de la saisie
]#SET{list_id,#ENV{list}}
[(#REM) Détecter si le tableau est séquentiel ou associatif, pour choisir s'il faut prendre la clé en valeur
]#SET{data_is_sequential,#GET{data}|is_array|?{#GET{data}|array_keys|=={#VAL{0}|range{#GET{data}|count|moins{1}}}}}
<B_selection>
[(#SET{list_id,[(#GET{list_id,[champ_(#ENV{nom})_data]})]})]
<datalist id="#GET{list_id}">
<BOUCLE_selection(POUR){tableau #GET{data}}>
[<option value="(#GET{data_is_sequential}|?{#VALEUR,#CLE}|attribut_html)">[(#VALEUR|attribut_html)]</option>]
</BOUCLE_selection>
</datalist>
</B_selection>
<input type="#GET{type}" name="#ENV{nom}" class="#GET{type}[ (#ENV{class})]" id="champ_[(#ENV{id,#ENV{nom}}|saisie_nom2classe)]"[ list="(#GET{list_id})"][ value="(#ENV{cle_secrete}|?{'',#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}})"][ size="(#ENV{size})"][ maxlength="(#ENV{maxlength})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][ placeholder="(#GET{placeholder})"][(#HTML5|oui)[(#ENV{obligatoire}|et{#ENV{obligatoire}|!={non}}|oui) required="required"][ min="(#ENV{min})"][ max="(#ENV{max})"][ step="(#ENV{step})"][(#ENV{autofocus}|et{#ENV{autofocus}|!={non}}|oui) autofocus="autofocus"]][(#GET{val_autocomplete}|find{#ENV{autocomplete}}|oui) autocomplete="#ENV{autocomplete}"][ aria-describedby="(#ENV{describedby})"][ (#ENV*{attributs})] />
Une vue (facultative)
Définition
La vue correspond à la manière dont est affiché le résultat d’une saisie. Par exemple, pour une saisie de type radio, il faut afficher les valeurs compréhensibles par les humain
e s et non pas la valeur technique brute.La vue d’une saisie est un simple squelette présent dans saisies-vues/<saisie>.html
. Le résultat de la saisie est présent dans #ENV{valeur}
.
Comme pour le contrôleur, le label et le conteneur HTML global se trouve dans saisies-vues/_base.html
et ne doit donc pas être inclus dans saisies-vues/<saisie>.html
.
Exemple
Voici la vue de la saisie radio
, dans le squelette saisies-vues/radio.html
.
[(#REM) data peut être une chaine qu'on sait décomposer ]
#SET{data, #ENV*{data, #ENV*{datas}}|saisies_chaine2tableau}
[(#ENV{cle_ou_valeur,valeur}|=={cle}|?{
[<p>(#ENV{valeur})</p>],
[<p>(#GET{data/#ENV{valeur}})</p>]
})]
Un petit peu d’analyse :
- #ENV{cle_ou_valeur}
est un paramètre passé à la vue. Il permet dans certains cas (par exemple pour l’export de donnée sous forme de tableau) d’afficher la clé informatique plutôt que la valeur humaine ;
- le filtre saisies_chaine2tableau
permet de transformer les chaînes du type :
cle1|valeur1
cle2|valeur2
En tableau PHP du type :
array ('cle1' => 'valeur1', 'cle2' => 'valeur2')
C’est ce qui nous permet de retrouver ensuite la valeur humaine via #GET{data/#ENV{valeur}}
[1].
Un constructeur (facultatif) .yaml
Définition
Le constructeur décrit formellement la saisie et ses options. Il est utilisé :
- pour proposer la saisie dans un formulaire de construction de formulaire (par exemple dans Formidable ou dans l’interface graphique de Champs Extras);
- pour générer automatiquement la page de documentation des saisies.
Le constructeur est fichier saisies/<saisie>.yaml
décrivant la saisie sous forme d’un tableau associatif YAML.
Contenu du constructeur
Les clés du tableau sont les suivantes :
- titre
;
- description
;
- icone
icone représentant la saisie, à chercher d’abord dans le dossier images
du thème, puis, à défaut, à traver find_in_path
;
- categorie
catégorie et position au sein de la catégorie, nous détaillons plus loins l’usage;
- options
tableau décrivant les options possibles pour la saisie, nous détaillons plus loin l’usage;
- options_dev
tableau décrivant les options possible pour la saisies mais qui ne sont accessibles que pour les dev (en PHP/squelettes), et pas à travers l’interface graphique;
- defaut
réglages des options et des vérifications par défaut, nous détaillons plus loin l’usage.
D’autres clés sont possibles pour des usages avancés et sont décrites plus loin dans cet article.
Catégorie
Définition
Chaque saisie peut être affectée à une catégorie. À défaut, elle sera affectée à la catégorie defaut
. Au sein d’une catégorie, les saisies sont classées dans l’ordre suivant :
- par rang, si pas de rang défini, alors tout à la fin;
- puis pour deux catégories du même rang, par ordre alphabétique (sans les accents).
Les catégories livrées en standards sont les suivantes.
Clé informatique | Libellé humain | Exemple de saisie concernée |
---|---|---|
libre | Champ libre | input |
choix | Choix restreint | radio |
structure | Structure | fieldset |
objet | Contenu éditorial | selecteur_article |
defaut | Divers | hidden |
Il est possible d’ajouter ses propres catégories via un pipeline.
Exemple
La saisie email
possède les entrées suivantes dans son .yaml
:
categorie:
type: 'libre'
rang: 10
Tableau d’options du constructeur
L’entrée options
du constructeur décrit les options disponibles. Ces options seront configurables par des saisies dans l’interface de construction de formulaire. Par conséquent, le tableau d’options n’est ni plus ni moins qu’une liste de saisies.
Il est recommandé de le regrouper en fieldset
. On veillera dans la mesure du possible à se conformer à la structure conventionnelle suivante :
options:
-
saisie: 'fieldset'
options:
nom: 'description'
label: '<:saisies:option_groupe_description:>'
saisies:
<tableau de saisies pour les options décrivant la saisie (label, explication, data, etc.)>
-
saisie: 'fieldset'
options:
nom: 'utilisation'
label: '<:saisies:option_groupe_utilisation:>'
saisies:
-
<tableau de saisies pour les options concernant l'utilisation de la saisie (readonly, désactivation, etc.)>
-
saisie: 'fieldset'
options:
nom: 'affichage'
label: '<:saisies:option_groupe_affichage:>'
saisies:
<tableau de saisies pour les options concernant l'affichage de la saisie message d'avertissement, etc.)>
-
saisie: 'fieldset'
options:
nom: 'conditions'
label: '<:saisies:option_groupe_conditions:>'
saisies:
<tableau de saisies pour les conditions d'affichage de la saisie (afficher_si)>
-
saisie: 'fieldset'
options:
nom: 'validation'
label: '<:saisies:option_groupe_validation:>'
saisies:
<tableau de saisies pour les options concernant la validation de la saisie (obligation, message d'erreur d'obligation, message relatif à l'obligation, etc..)>
À noter que certaines options seront automatiquement insérées par les formulaires de constructions de formulaire, si pertinent :
- choix du nom dans le fieldset
description
- option de vérifications dans le fieldset
validation
; - le plugin Interface pour Champs Extra s’occupe automatiquement d’ajouter son fieldset
technique
.
Il ne faut donc pas insérer ces options dans le constructeur .yaml
.
On peut par ailleurs mutualiser le code, pour des options que l’on retrouve sur plusieurs saisies. C’est le cas par exemple pour les options concernant l’obligation et les afficher_si. Il suffit pour ce faire d’utiliser la syntaxe suivante :
- 'inclure:<fichier yaml à inclure>'
Ainsi, les saisies livrés avec le plugin contiennent les lignes suivantes
-
saisie: 'fieldset'
options:
nom: 'conditions'
label: '<:saisies:option_groupe_conditions:>'
saisies:
- 'inclure:saisies/_base/afficher_si.yaml'
-
saisie: 'fieldset'
options:
nom: 'validation'
label: '<:saisies:option_groupe_validation:>'
saisies:
- 'inclure:saisies/_base/obligatoire.yaml'
Les informations spécifiques aux dev
Ainsi qu’expliqué, le constructeur d’une saisie sert à deux choses :
- permettre de configurer la saisie via une interface graphique ;
- documenter les options de la saisie.
Cependant, comment documenter des options qui, en raison de leur caractère technique et/ou pour des raisons de sécurité ne sont disponibles que pour les dev de squelettes/plugins, déclarant des saisies en SPIP/PHP, mais ne sont pas disponibles en interface graphique ?
La solution est simple : le constructeur de saisies peut contenir un tableau supplémentaire options_dev
décrivant les options disponibles uniquement pour les dev.
Ainsi le constructeur de la saisie fieldset
contient le tableau suivant :
options_dev:
- 'inclure:saisies/_base/options_dev.yaml'
-
saisie: 'input'
options:
nom: 'icone'
label: '<:saisies:option_icone_label:>'
explication: '<:saisies:option_icone_explication:>'
-
saisie: 'input'
options:
nom: 'taille_icone'
label: '<:saisies:option_taille_icone_label:>'
On documente ainsi :
- les options de dev commune à l’ensemble des saisies (
- 'inclure:saisies/_base/options_dev.yaml'
); - les options de dev spécifique à la saisie fieldset.
Il peut par ailleurs avoir certaines options où il faut fournir deux explications différentes :
- une pour l’interface graphique;
- une pour les devs.
La première explication se trouve dans la clé explication
, la seconde à la clé explication_dev
.
C’est le cas cas, par exemple, pour décrire les data
d’une saisie de type radio
:
-
saisie: 'textarea'
options:
nom: 'datas'
label: '<:saisies:option_datas_label:>'
explication: '<:saisies:option_datas_sous_groupe_explication:>'
explication_dev: '<:saisies:option_datas_sous_groupe_explication_dev:>'
rows: 10
cols: 50
verifier:
type: 'saisies_option_data'
-
saisie: 'case'
Tableau de réglages par défaut du constructeur
En plus du tableau d’options, le constructeur possède un tableau, défini par la clé defaut
, indiquant les valeurs par défaut :
- des options définies dans le constructeur ;
- des types SQL pour le plugin Interface champs extras, qui n’est qu’une option parmi d’autres ;
- de la vérification à effectuer pour cette saisie.
Exemple
Voici la description des options par défaut pour la saisie email
, dans saisies/email.yaml
:
defaut:
options:
label: '<:saisies:saisie_email_titre:>'
size: 40
# champs extras (definition du champ sql)
sql: "text DEFAULT '' NOT NULL"
verifier:
type: 'email'
Un outil d’analyse
Le plugin Formidable permet d’analyser les réponses. Pour que cette analyse soit pertinente pour une saisie personnalisé, il faut fournir un fichier saisies-analyses/<nom_de_la_saisie>.html
.
Nous renvoyons à l’article «Rendre une saisie analysable par Formidable» pour plus de détail.
Fonctions avancées
Saisies autonomes
Définition
Ainsi que nous l’avions indiqué, la plupart des saisies utilisent pour leur constructeur le squelette saisies/_base.html
et pour leur vue le squelette saisies-vues/_base.html
.
Ces squelettes incluent les éléments que l’on retrouve dans la plupart des saisies :
- conteneur HTML global ;
- label ;
- éventuels messages d’avertissement ou d’erreur ;
- etc.
Toutefois, certaines saisies peuvent être dites “autonomes” et ne pas utiliser les éléments englobants de saisies/_base.html
.
Parmi les saisies livrées avec le plugin, c’est le cas des saisies :
- fieldset
;
- hidden
;
- destinataires
;
- explication
.
Il est possible d’utiliser le pipeline saisies_autonomes
pour ajouter de nouvelles saisies autonomes.
Lorsque l’on créé une saisies autonomes, il faudra veiller :
- à utiliser un conteneur adapté à la version de SPIP que l’on utilise :
-
li
jusqu’à la version 3.0 incluse ; -
div
à partir de la version 3.1. - on pourra utiliser le bout de squelette suivant pour adapter automatiquement :
<[(#ENV{saisies_base_conteneur,#DIV|sinon{li}})]
;
-
- à passer correctement les différentes classes ;
- à intégrer les informations nécessaires au bon fonctionnement de l’affichage conditionnel en mettant dans les attributs du conteneur :
-
[ data-id="(#ENV{id_saisie})"]
; [ data-afficher_si="(#ENV*{afficher_si}|saisies_afficher_si_js{#ENV{_saisies}})"]
;
-
Exemples
Le plugin Gis déclare la saisie carte
via le pipeline saisies_autonomes
:
function gis_saisies_autonomes($flux) {
$flux[] = 'carte';
return $flux;
}
Voici le contrôleur de la saisie fieldset
, dans saisies/fieldset.html
:
#SET{pliable,#ENV{pliable}|et{#ENV{pliable}|!={non}}|?{'pliable', ''}}
#SET{plie,#ENV{plie}|et{#ENV{plie}|!={non}}|?{'plie', ''}}
[(#REM) S'il y a des erreurs pour au moins un des champs internes, on ne plie pas ! ]
#SET{champs_internes, #ENV{saisies}|saisies_lister_par_nom}
#SET{erreurs, #ENV**{erreurs}|sinon{#ARRAY}}
#SET{erreurs_fieldset, #GET{erreurs}|array_intersect_key{#GET{champs_internes}}}
[(#GET{erreurs_fieldset}|oui)
#SET{plie, ''}
]
#SET{erreur_ici,#ENV**{erreurs/#ENV{nom}}}
<[(#ENV{saisies_base_conteneur,#DIV|sinon{li}})] class="fieldset[ fieldset_(#ENV{nom}|saisie_nom2classe)][ (#ENV{conteneur_class,#ENV{li_class}})][ (#ENV{type_saisie}|saisie_type2classe)][ (#GET{pliable})[ (#GET{plie})]]"[ data-id="(#ENV{id_saisie})"][ data-afficher_si="(#ENV*{afficher_si}|saisies_afficher_si_js{#ENV{_saisies}})"]>
#ENV*{inserer_debut}
<fieldset>
[(#ENV{label}|oui)
[(#REM) Récupérer le tag qui sera utilisé pour la légende ]
[(#SET{tag, [(#ENV*{tagfield,<legend>}|inserer_attribut{class,legend})]})]
[(#INCLURE{fond=inclure/fieldset_legend, env}|wrap{#GET{tag}})]
]
[<span class='erreur_message'>(#GET{erreur_ici})</span>]
[<p class='explication'>(#ENV*{explication})</p>]
[<em class='attention'>(#ENV*{attention})</em>]
[(#ENV{saisies}|is_array|oui)
<[(#ENV{saisies_base_conteneur,#DIV|sinon{ul}})] class="editer-groupe">
#INCLURE{fond=#ENV{fond_generer,"inclure/generer_saisies"}, env, saisies=#ENV{saisies}, from_fieldset='on'}
</[(#ENV{saisies_base_conteneur,#DIV|sinon{ul}})]>
]
</fieldset>
#ENV*{inserer_fin}
</[(#ENV{saisies_base_conteneur,#DIV|sinon{li}})]>
et voici sa vue, dans saisies-vues/fieldeset.html
:
[(#ENV{valeur_uniquement}|et{#ENV{valeur_uniquement}|!={non}}|non)
[<h3 class="legend[ (#ENV{vue_class})]">(#ENV{label})</h3>]
]
[(#ENV{saisies}|is_array|oui)
#INCLURE{fond=inclure/voir_saisies, env, from_fieldset='on'}
]
Ajouter de nouvelles catégories — pipeline saisies_lister_categories
Le pipeline saisies_lister_categories
permet d’ajouter (ou le cas échéant, de modifier ou supprimer) une ou plusieurs catégories de saisie.
Par exemple l’association Planète Sciences ajoute une catégorie pour les saisies propres à ses activités, avant toutes les autres catégories
/**
* Ajout d'une catégorie de saisies plasci
* @param array $flux
* @return $flux modifié
**/
function plasci_saisies_lister_categories($flux) {
$plasci = array(
'plasci' => array(
'nom' => _T('plasci:plasci')
)
);
$flux = array_merge($plasci, $flux);//Mettre plasci en premier
return $flux;
}
Nous avons ajouté une catégorie dont la clé est plasci
et dont le nom humain est _T('plasci:plasci')
. Pour l’instant, les catégories n’ont comme seule propriété que leur nom, mais cela pourrait changer à l’avenir.
À noter qu’une sécurité est appliquée, afin de s’assurer que la catégorie defaut
se trouve systématiquement à la fin.
Modifier la liste des saisies proposées — pipeline saisies_lister_disponibles
Il est parfois utile de modifier la liste des saisies proposées, soit pour réaffecter des catégories, soit pour supprimer certaines saisies. Pour ce faire, on peut utiliser le pipeline saisies_lister_disponibles
.
Par exemple, pour alléger son interface, Planète Sciences affecte la saisie evenements
du plugin agenda à la catégorie plasci
, et supprime toutes les saisies de catégorie objet
.
/**
* Met la saisie evenements dans la catégorie plasci
* Supprime toute les saisies objets
* @param array $flux
* @return $flux
**/
function plasci_saisies_lister_disponibles($flux) {
foreach ($flux as $saisie => &$description) {
if ($saisie == 'evenements') {
$description['categorie']['type'] = 'plasci';
$description['categorie']['rang'] = -10;
} elseif (isset($description['categorie']['type']) and $description['categorie']['type'] == 'objet') {
unset($flux[$saisie]);
}
}
return $flux;
}
Modifier les vérifications associables aux saisies — pipeline saisies_verifier_lister_disponibles
Lors de la configuration d’une saisie dans un constructeur de formulaire, il est possible de configurer une ou plusieurs vérifications, grâce au plugin verifier
.
Toutefois, certaines vérifications ne s’appliquent pas, d’un point de vue logique, à certaines saisies. De plus, il peut être pertinent de dire qu’une saisie nécessite automatiquement certaines vérifications.
Par exemple la saisie fichiers
du plugin cvtupload
ne peut obtenir qu’une vérification fichiers
, fournie par le plugin cvtupload
. Il est du reste obligatoire d’utiliser cette vérification. Et enfin, cette vérification fichiers
n’est possible que pour cette saisie fichiers
.
C’est là qu’intervient le pipeline saisies_verifier_lister_disponibles
. Elle reçoit en paramètre args
la saisie, et renvoie en data
la liste des vérifications disponibles et la liste des vérifications obligatoire
. Voici le code du pipeline dans cvtupload
.
/**
* La saisie fichiers ne peut utiliser que la vérification fichiers
* et elle doit obligatoirement l'utiliser
* @param array $flux
* @return $flux
**/
function cvtupload_saisies_verifier_lister_disponibles(array $flux): array {
$args = $flux['args'];
$data = &$flux['data'];
if ($args['saisie'] === 'fichiers') {
$data['disponibles'] = [
'fichiers' => $data['disponibles']['fichiers']
];
$data['obligatoires'] = ['fichiers'];
} else {
unset($data['disponibles']['fichiers']);
}
return $flux;
}
Héritage de saisies
Définition
Il est possible de créer des saisies “héritières” d’une autre saisie. Une telle saisie héritière est simplement une variante de la saisie “mère”, avec simplement quelques réglages différents.
Par exemple la saisie choix_couleur
est un simple héritage de la saisie radio
.
Il est même possible de procéder à des héritages successifs.
L’intérêt du mécanisme d’héritage est d’éviter de répéter les options de la saisie mère dans le constructeur .yaml
de la saisie héritière. On assure ainsi une plus grande cohérence dans les options proposées.
Contrôleur et vue de la saisie héritière
Un contrôleur et une vue étant un squelette, on pourra utiliser <INCLURE>
ou #INCLURE
pour inclure le contrôleur/la vue de la saisie mère.
Deux possibilités s’offrent à nous
- Soit le balisage englobant est spécifique à la saisie héritée, comme pour les saisies
radio
/checkbox
/case
[2]. Dans ce cas la saisie héritière doit être déclarée comme autonome. L’inclusion sera de la forme<INCLURE{fond=saisies/_base,env,type_saisie=<nom de la saisie héritée>,<paramètres predefini par la saisie héritière...>} />
(pour la saisie). On prêtera attention au fait que le type de saisie doit être précisé après le passage deenv
. - Soit le balisage englobant est standard (si l’on hérite par exemple d’une saisie
input
). Dans ce cas, la saisie héritière n’est pas autonome. L’inclusion sera de la forme<INCLURE{fond=saisies/<nom de la saisie héritée>,env,<paramètres predefini par la saisie héritière...>} />
(pour la saisie).
À noter que pour la vue de la saisie, la notion d’autonomie n’a pas de pertinence. On appelera toujours <INCLURE{fond=saisies-vues/<nom de la saisie héritée>,env,<paramètres predefini par la saisie héritière...>} />
.
Constructeur de la saisie héritière
Contrairement au constructeur de la saisie mère, le constructeur de la saisie héritière ne contient pas de tableau d’options, puisque le but est précisément de les hériter de la saisie mère.
Le constructeur de la saisie héritière possède une entrée heritage
. Il s’agit d’un tableau avec les sous entrée suivante :
-
parent
, indiquant la saisie dont on hérite les options; -
enlever_options
; -
modifier_options
; -
ajouter_options
.
Options à enlever
La sous-entrée enlever_options
permet d’enlever des options, listées sous forme de tableau.
heritage:
parent: '<saisie_parente>'
enlever_options:
- 'placeholder'
- 'type'
Options à modifier
La sous entrée modifier_options
permet de modifier des options. Celles-ci sont listées sous forme de tableau. Chaque option est elle-même une saisie. Elle peut cependant contenir deux attributs supplémentaires :
-
nouveau_type_saisie
pour modifier le type de saisie; -
mode
:- si absent ou différent de
'fusionner'
, la nouvelle option remplace intégralement l’ancienne; - si présent et égal à
'fusionner'
:- les propriétés de la nouvelle option viennent remplacer celles de l’ancienne si elles portent le même nom ;
- les propriétés de l’ancienne option sont conservées si elles ne sont pas redéfinies dans la nouvelle;
- les propriétés de la nouvelle option sont ajoutées si elles ne sont pas présentes dans l’ancienne
- si absent ou différent de
Options à ajouter
L’entrée ajouter_options
permet d’ajouter des options. Il s’agit d’un tableau décrivant les options à ajouter sous formes de liste de saisies avec leur paramètres (puisque, rappelez-vous, les options d’une saisie sont elle même décrites sous forme de saisies!). Outre les paramètres standards pour décrire une saisie au sein d’un formulaire (type, options, etc), chaque saisie peut avoir, au choix, l’un des paramètres suivants, pour indiquer où insérer la saisie :
-
inserer_apres
, pour indiquer après quelle saisie insérer notre nouvelle option/saisie; -
inserer_avant
, pour indiquer avant quelle saisie insérer notre nouvelle option/saisie; -
chemin
:- Si entre crochets, la saisie sera insérée à la fin du fieldset entre crochets. Exemple
chemin: '[description]'
, pour insérer à la fin du fieldsetdescription
. - Si entre crochets suivis d’un entier entre crochets, la saisie sera insérée à une position précise dans un fieldset. Exemple : Exemple
chemin: '[description][0]'
, pour insérer au début fin du fieldsetdescription
. - Si pas de crochet, pour insérer avant une saisie. Exemple
chemin: 'label'
, pour insérer avant la saisielabel
.
- Si entre crochets, la saisie sera insérée à la fin du fieldset entre crochets. Exemple
Valeurs par défaut
Dans le constructeur d’une saisie héritière :
- les valeurs de la propriété
defaut
remplacent celle de la saisie mère ; - si une propriété
defaut
est présente uniquement dans la saisie mère, elle est conservée ; - si une propriété
defaut
est présente uniquement dans la saisie héritière, elle est ajoutée.
Exemple
Voici le constructeur de la saisie choix_couleur
définie dans saisies/choix_couleur.yaml
:
titre: '<:saisie_choix_couleur:choix_couleur_titre:>'
description: '<:saisie_choix_couleur:choix_couleur_explication:>'
icone: 'images/saisies_radio.png'
categorie:
type: 'choix'
rang: 10000
heritage:
parent: 'radio'
modifier_options:
-
chemin: 'datas'
mode: 'fusionner'
options:
explication: '<:saisie_choix_couleur:choix_couleur_datas_explication:>'
ajouter_options:
-
saisie: 'fieldset'
inserer_apres: 'validation'
options:
nom: 'analyse'
label: '<:formidable:reponses_analyse:>'
saisies:
-
saisie: 'case'
options:
nom: 'analyse_moyenne_temperature'
label: '<:saisie_choix_couleur:analyse_moyenne_temperature_label:>'
label_case: '<:saisie_choix_couleur:analyse_moyenne_temperature_label_case:>'
-
saisie: 'textarea'
options:
nom: 'temperature_corps_noir'
label: '<:saisie_choix_couleur:temperature_corps_noir_label:>'
explication: '<:saisie_choix_couleur:temperature_corps_noir_explication:>'
defaut: ''
afficher_si: '@analyse_moyenne_temperature@'
verifier:
type: 'saisies_option_data'
defaut:
options:
label: '<:saisie_choix_couleur:choix_couleur_titre:>'
datas:
choix1: '<:saisie_choix_couleur:choix_couleur_defaut_choix1:>'
choix2: '<:saisie_choix_couleur:choix_couleur_defaut_choix2:>'
choix3: '<:saisie_choix_couleur:choix_couleur_defaut_choix3:>'
# champs extras (definition du champ sql)
sql: "text DEFAULT '' NOT NULL"
Voici son contrôleur, dans saisies/choix_couleur.html
:
[(#SET{data,[(#ENV*{data,#ENV*{datas}}|saisies_choix_couleur_preparer_data)]})]
<INCLURE{fond=saisies/_base,env,type_saisie=radio,data=#GET{data}} />
On le voit : on appelle simplement saisies/_base
, en précisant de faire une saisie radio, avec le paramètre data
construit spécifiquement pour la saisie choix_couleur
. La saisie choix_couleur
est déclarée comme saisie autonome.
et voici sa vue dans saisies-vues/choix_couleur.html
:
[(#SET{data,[(#ENV*{data,#ENV*{datas}}|saisies_choix_couleur_preparer_data)]})]
<INCLURE{fond=saisies-vues/radio,env,data=#GET{data}} />
Vérifier les valeurs acceptables
Besoin et emploi
Certaines saisies ont un nombre prédéterminé de valeurs qui peuvent être envoyées au serveur, par exemple :
- les boutons radio ;
- les listes déroulantes ;
- les inputs désactivés ou en lecture seule.
La plupart du temps, nous pouvons faire confiance à l’internaute pour ne pas tenter d’envoyer une autre valeur que les valeurs proposées.
Cependant, dans certains cas il est nécessaire de s’assurer que la valeur envoyée est bien présente parmi les valeurs possibles.
Pour ce faire, il faut dans le tableau de description des saisies avoir une option verifier_valeurs_acceptables
:
$mon_tableau = array(
'0' => array(), // une saisie
'1' => array(), // une autre saisie
'options => array( // un tableau d'option, dont
'verifier_valeurs_acceptables' => true
)
);
Si une telle option est activée, la fonction saisies_verifier()
vérifiera si la valeur postée pour une saisie déterminée correspond aux valeurs prédéterminées.
Pour ce faire, elle s’appuie sur une fonction <saisie>_verifier_valeurs_acceptables
dans le fichier saisies/<saisie>.php
.
Exemple
Par exemple pour la saisie selection
, le fichier saisies/selection.php
contient la fonction suivante :
/**
* Vérifie que la valeur postée
* correspond aux valeurs proposées lors de la config de valeur
* @param string $valeur la valeur postée
* @param array $description la description de la saisie
* @return bool true si valeur ok, false sinon,
**/
function selection_valeurs_acceptables($valeur, $description) {
$options = $description['options'];
if ($valeur == '' and !isset($options['obligatoire'])) {
return true;
}
if (saisies_saisie_est_gelee($description) and isset($options['defaut'])) {
return $valeur == $options['defaut'];
} else {
$data = saisies_trouver_data($description, true);
$data = saisies_aplatir_tableau($data);
$data = array_keys($data);
if (isset($options['disable_choix'])) {
$disable_choix = explode(',', $options['disable_choix']);
$data = array_diff($data, $disable_choix);
}
return (in_array($valeur ,$data));
}
}
Cette fonction fait appel à plusieurs fonctions du plugin Saisies:
-
saisies_trouver_data()
, qui trouve l’optiondata
de la saisie, ou à défautdatas
, et la transforme si nécessaire en tableau; -
saisies_aplatir_tableau()
qui permet de supprimer les niveaux d’imbrication dans le tableau ; -
saisies_saisie_est_gelee()
, qui indique si une saisie est “gelée” c’est-à-dire :- soit avec une option
readonly
activée; - soit avec les deux options suivantes simultanément activées :
-
disable
; -
disable_avec_post
.
-
- soit avec une option
À noter que la plupart du temps, on pourra faire appel à une fonction de vérification des valeurs acceptables déjà définie. Ainsi, la saisie radio
vérifie de la même manière que la saisie selection
les valeurs acceptables :
/**
* Vérifie que la valeur postée
* correspond aux valeurs proposées lors de la config de valeur
* @param string $valeur la valeur postée
* @param array $description la description de la saisie
* @return bool true si valeur ok, false sinon,
**/
function radio_valeurs_acceptables($valeur, $description) {
include_spip('saisies/selection');
// Structurellement, une saisie radio ou une saisie select, c'est un choix parmi N options.
// Donc la vérif des données postées est la même
return selection_valeurs_acceptables($valeur, $description);
}
Indiquer si une saisie peut avoir des enfants
Problématique
Certaines saisies peuvent avoir des enfants. C’est le cas par exemple de la saisie fieldset
et de la saisie conteneur_inline
. Ces enfants sont stockés dans un tableau saisies
à la racine de la saisie mère. Il existe une fonction saisies_saisie_est_avec_sous_saisies()
qui dit si la saisie peut contenir des sous-saisies. Par défaut, on considère qu’une saisie ne peut pas avoir d’enfants. Cependant, pour les saisies qui peuvent avoir des enfants, qu’une instance de cette saisie en ait ou pas, il faut définir une fonction <saisie>_est_avec_sous_saisies()
dans le fichier saisies/<saisie>.php
.
Exemple
Dans le fichier saisies/fieldset.php
, on trouve :
/**
* Un fieldset, c'est une saisie contenante
* @param array $saisie
* @return bool true
**/
function fieldset_est_avec_sous_saisies(array $saisie): bool {
// Type de retour à changer en true lorsqu'on sera dans version de PHP qui l'autorise
return true;
}
Indiquer si une saisie peut avoir recevoir un label/titre
Problématique
La très grande majorité des saisies peuvent recevoir un label ou un titre. Quelques saisies ne peuvent pas, comme la saisie conteneur_inline
. Dans ce cas, il faut le préciser via une fonction spécifique <saisie>_est_labelisable()
dans le fichier saisies/<saisie>.php
. Cela permet à la fonction saisies_saisie_est_labelisable()
de renvoyer la bonne valeur.
Exemple
Dans le fichier saisies/conteneur_inline.php
, on trouve :
/**
* Un conteneur_inline, ca n'a pas de label
* @param array $saisie
* @return bool false
**/
function conteneur_inline_est_labelisable(array $saisie): bool {
// Type de retour à changer en false lorsqu'on sera dans version de PHP qui l'autorise
return false;
}
Retourner le label d’une saisie
Problématique
Par défaut, le label d’une saisie correspond à l’option label
(!). Mais certaines saisies peuvent être plus complexes, par exemple la saisie case
, qui peut avoir à la place de label
un label_case
.
Pour pouvoir afficher correctement le label de la saisie lorsqu’on fait des résumés des saisies, on passe par la fonction saisies_saisie_get_label()
. Cette fonction renvoie par défaut la valeur de l’option label
de la saisie sauf si une fonction <saisie>_get_label()
est disponible dans le fichier saisies/<saisie>.php
Exemple
Le fichier saisies/case.php
contient le code suivant.
/**
* Retourne le label de la saisie case
* Par ordre de priorité le label_case
* sinon le label
* @param array $saisie
* @return string
**/
function case_get_label(array $saisie): string {
$label_case = $saisie['options']['label_case'] ?? '';
if ($label_case) {
return $label_case;
} else {
return $saisie['options']['label'] ?? '';
}
}
Indiquer si une saisie peut recevoir une valeur
Problématique
Par défaut, une saisie correspond à un champ de formulaire. Elle est donc susceptible de recevoir une valeur lors de l’envoi du formulaire. Certaines saisies ne le peuvent pas, car elles se contentent de regrouper des saisies : fieldset
, conteneur_inline
par exemple.
Dans ce cas il faut définir une fonction <saisie>_est_champ()
dans le fichier saisies/<saisie>.php
pour que la fonction globale saisies_saisie_est_champ()
renvoie la bonne valeur.
Exemple
Le fichier saisies/conteneur_inline.php
contient la fonction suivante.
/**
* Un conteneur_inline, ca n'est pas un champ
* @param array $saisie
* @return bool false
**/
function conteneur_inline_est_champ(array $saisie): bool {
// Type de retour à changer en false lorsqu'on sera dans version de PHP qui l'autorise
return false;
}
Des pipelines et outils pour les affichages conditionnels
Les affichages conditionnels permettent d’afficher une saisie en fonction de la valeur d’une autre saisie. Pour ce faire, le plugin Saisies génère dynamiquement du code Javascript et PHP.
La plupart du temps, le plugin Saisies est capable de déterminer automatiquement le code à générer. Il peut cependant arriver qu’il faille l’aider grâce à des pipelines.
Saisies tabulaires — pipeline saisie_est_tabulaire
Définition
La plupart des Saisies renvoient un champ unitaire. Toutefois, certaines saisies renvoient un tableau de données. Tel est le cas :
- de la saisie checkbox
, qui renvoie un tableau des cases cochées;
- de la saisie evenements
du plugin Agenda, qui selon la configuration peut renvoyer un champ unitaire (lorsque le choix est sous forme de boutons radio ou de liste déroulante) ou un tableau de données (lorsque le choix est sous forme de cases à cocher).
Le pipeline saisie_est_tabulaire
doit renvoyer le paramètre data
à true
si la saisie est tabulaire. Ceci permet d’effectuer de manière correcte les vérifications côté PHP.
Exemple
Voici comment le plugin Agenda utilise ce pipeline pour la saisie evenements
.
/**
* Pour la saisie de type événement, indique si les données renvoyées sont tabulaires ou pas
* @param $flux
* @return $flux
**/
function agenda_saisie_est_tabulaire($flux) {
$args = $flux['args'];
if ($args['saisie'] != 'evenements') {
return $flux;
}
if ($args['options']['type_choix'] == 'checkbox') {
$flux['data'] = true;
}
return $flux;
}
Pseudo-saisies — Pipeline saisies_afficher_si_saisies
Définition
Normalement une saisie correspond à un seul champ de formulaire HTML. Il peut cependant arriver que certaines saisies proposent plusieurs champs.
Par exemple, la saisie evenements
du plugin agenda
possède un champ <nom_de_la_saisie>_liste_attente
qui est automatiquement mis à on
si l’internaute sélectionne un évènement pour lequel il ne reste plus de place. Cela peut être utile pour gérer l’inscription à des évènements avec des listes d’attente.
Pour que le test conditionnel sur @<nom_de_la_saisie>_liste_attente@
soit possible, il est nécessaire que le javascript généré connaisse l’existence de ce champ html <nom_de_la_saisie>_liste_attente
.
Pour ce faire, nous devons utiliser le pipeline saisies_afficher_si_saisies
. Celui-ci reçoit un tableau de saisies, et doit renvoyer le même tableau, complété, le cas échéant, de “pseudo-saisies” correspondant aux champs HTML non homonymes aux saisies.
Exemple
Voici comment le plugin Agenda utilise ce pipeline pour gérer le champ <nom_saisie_evenements>_liste_attente
:
/**
* Si on a une saisie de type événement, ajoute, si nécessaire, au tableau de déclaration de saisies la saisie _liste_attente correspondante.
* Utile pour les afficher_si
* @param $flux les saisies
* @return $flux les saisies modifier
**/
function agenda_saisies_afficher_si_saisies($flux) {
//Ne pas refaire 36 fois le calcul
static $old;
static $new;
if ($old == $flux) {
return $new;
}
$old = $flux;
$new = $flux;
include_spip('inc/saisies');
$saisies_evenements = saisies_lister_avec_type($flux, 'evenements');
foreach ($saisies_evenements as $saisie => $description) {
if (isset($description['options']['liste_attente']) and $description['options']['liste_attente']) {
$saisie_inserer = array(
'saisie' => 'evenements_liste_attente',
'options' => array(
'nom' => $description['options']['nom'].'_liste_attente',
'label' => $description['options']['label'].' ('.strtolower(_T('saisie_evenements:liste_attente_label')).')',
'afficher_si' => 'false',
)
);
$new = saisies_inserer_apres($new, $saisie_inserer, $description['options']['nom']);
}
}
return $new;
}
On remarquera l’emploi du test sur une variable statique. Cet emploi est nécessaire pour des raisons de performances, car le pipeline est appelé à chaque fois qu’une saisie possède un affichage conditionnel.
Créer les tests d’afficher_si spécifiques à certains types de saisie
Cette partie est très technique. Rares sont les personnes qui auront besoin de s’en servir, car ce qui est livré avec le plugin saisies fonctionne dans 99,99% des usages.
Problématique
Il est aisé côté PHP de vérifier qu’un test d’afficher_si
est bien valide. En effet, les données que reçoit PHP lors d’une requête se retrouvent forcément dans _$_POST
ou $_FILES
. C’est pourquoi, pour l’heure, le plugin ne prévoit pas que l’on puisse ajouter des réglages spécifiques à certains types de saisies.
Côte Javascript, les structures de données sont parfois plus complexe. Depuis la version 3.50.0 du plugin, la détection des tests javascript à effectuer marchent dans 99% des cas. Chaque test individuel est remplacé par un appel à la fonction JavaScript saisies_afficher_si()
qui reçoit en argument un tableau décrivant les composants de ce texte (champ à tester, valeur à tester, opérateur, etc.).
Pour certains type de saisies toutefois, on peut imaginer de brancher sur un autre tests Javascript. Il faut pour cela créer une fonction saisies_afficher_si_js_<type_de_saisie>()
dans saisies_afficher_si_js/<type_de_saisie>.php
. Cette fonction reçoit en entrée l’analyse syntaxique formelle du test, sous forme de tableau, et retourne en sortie une code évaluable par Javascript
Exemple
C’est par exemple le cas de la saisies fichiers
du plugin CVT-Upload, puisqu’il s’agit de tester combien de fichiers on s’apprête à envoyer.
Pour ce faire, le plugin définit dans le fichier saisies_afficher_si_js/fichiers.php
une fonction saisies_afficher_si_js_fichiers.php
. Celle-ci génère un code JS capable d’évaluer le test portant sur une saisies fichiers
en fonction de la structure des objets JS pour les input
de type file
.
Lien avec Champs Extras
Le plugin Champs Extras propose des affichages par défaut pour les différentes saisies, ainsi que des modalités par défaut de serialisation en base pour les saisies qui renvoient plusieurs valeurs.
Il est toutefois possible de proposer des exceptions pour certaines saisies.
#LISTER_VALEURS
Pour rappel, #LISTER_VALEURS
permet de lister les valeurs d’un champ extra.
Il est possible de créer une fonction champs_extras_calculer_balise_LISTER_VALEURS_<type_de_saisie>()
pour définir un retour différent. La fonction est à placer dans un fichier champs_extras/calculer_balise_lister_valeurs_<type_de_saisie>.php
. Elle est appelée via charger_fonction
.
Exemple
Le plugin Saisies propose dans champs_extras/calculer_balise_lister_valeurs_choix_grille.php
la fonction suivante :
/**
* Déclaration de la balise LISTER_VALEURS pour la saisie <span class="base64" title="PGNvZGUgY2xhc3M9J3NwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lJyBkaXI9J2x0cic+Y2hvaXhfZ3JpbGxlPC9jb2RlPg=="></span>
* @param string $objet
* Type d'objet
* @param string $colonne
* Nom de la colonne SQL
* @param string $cles
* Valeurs enregistrées pour ce champ dans la bdd pour l'objet en cours
* @return array|string vide
* Tableau de type 'Clé de ligne|Valeur de ligne' => 'Ligne en valeur humaine|Valeur de ligne en humain'.
* Par ex 'Ligne1|Colonne1' => 'Ma première ligne|Ma première colonne'
**/
function champs_extras_calculer_balise_LISTER_VALEURS_choix_grille($objet, $colonne, $cles) {
if (
$options = calculer_balise_CHAMP_EXTRA($objet, $colonne)
and isset($options['data_rows'])
and isset($options['data_cols'])
) {
$data_rows = saisies_chaine2tableau($options['data_rows']);
$data_cols = saisies_chaine2tableau($options['data_cols']);
$retour = [];
$valeurs = saisies_chaine2tableau($cles);
foreach ($valeurs as $cle => $valeur) {
if (is_array($valeur)) {
$colonne_humaine = join('|',
array_map(
function ($i) use ($data_cols) {
return $data_cols[$i];
},
$valeur
)
);
$retour["$cle|".join('|', $valeur)] = $data_rows[$cle].'|'.$colonne_humaine;
} else {
$retour["$cle|$valeur"] = $data_rows[$cle].'|'.$data_cols[$valeur];
}
}
return $retour;
} else {
return '';
}
}
Sérialisation
Pour une saisie renvoyant plusieurs valeurs (type tableau), il faut serialiser, c’est-à-dire transformer en chaîne de caractère, pour stocker en base. Par défaut champs extras serialise en séparant les valeurs par une virgule. Ce n’est toutefois pas toujours adapté.
Il est possible de définir dans un fichier champs_extras/serialiser_<type_de_saisie>.php
une fonction champs_extras_serialiser_<type_de_saisie>()
pour définir un autre mode de sérialisation.
Exemple
Le plugin saisies définit une sérialisation spécifique pour la saisie choix_grille
. On trouve dans champs_extras/serialiser_choix_grille.php
la fonction suivante :
/**
* Sérialise les réponses à un champ extra de type <span class="base64" title="PGNvZGUgY2xhc3M9J3NwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lJyBkaXI9J2x0cic+Y2hvaXhfZ3JpbGxlPC9jb2RlPg=="></span> pour encodage en base.
* @param array $extra
* La valeur reçue en POST
* @param array $saisie
* La description de la saisie
* @return string
* Forme serialisé, en l'occurence avec saisies_tableau2chaine
**/
function champs_extras_serialiser_choix_grille($extra, $saisie) {
include_spip('inc/saisies');
return saisies_tableau2chaine($extra);
}
Saisies obsolètes
Définition
Il est possible de déclarer une saisie comme obsolète dans le constructeur .yaml
.
Une saisie obsolète n’est plus proposée à la construction d’un formulaire. En revanche les saisies déjà présentes dans le formulaire continuent d’exister.
Pour indiquer une saisie comme obsolète, il suffit de mettre l’attribut obsolete
à true
dans le .yaml
:
Exemple
Un exemple de saisie obsolète est la saisie oui_non
, qu’il convient de remplacer par une saisie radio
avec des intitulés explicites.
titre: '<:saisies:saisie_oui_non_titre:>'
description: '<:saisies:saisie_oui_non_explication:>'
icone: 'images/saisies_oui_non.png'
obsolete: true
No discussion
Add a comment
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Follow the comments:
|
