Créer ses propres saisies

Cette documentation explique comment créer ses propres saisies pour le plugin Saisies. Elle est valable à partir de la version 3.51.8 du plugin.

On pourra consulter les saisies fournies avec le plugin pour compléter cette documentation.

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é :

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 ;
-  image chemin vers l’image représentant la saisie ;
-  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;
-  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.

Catégories des saisies
Clé informatiqueLibellé humainExemple 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 (affichage conditionnel, message d'avertissement, etc.)>
          nom: 'class'
          label: '<:saisies:option_class_label:>'
          size: 50
      -
        saisie: 'input'
        options:
          nom: 'conteneur_class'
          label: '<:saisies:option_conteneur_class_label:>'
          size: 50
  -
    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: 'affichage'
      label: '<:saisies:option_groupe_affichage:>'
    saisies:
      -  'inclure:saisies/_base/afficher_si.yaml'
  -
    saisie: 'fieldset'
    options:
      nom: 'validation'
      label: '<:saisies:option_groupe_validation:>'
    saisies:
      -  'inclure:saisies/_base/obligatoire.yaml'

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'

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;
}

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 de env.
  • 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
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 fieldset description.
    • 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 fieldset description.
    • Si pas de crochet, pour insérer avant une saisie. Exemple chemin: 'label', pour insérer avant la saisie label.
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_verifier_gel_saisie($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’option data de la saisie, ou à défaut datas, et la transforme si nécessaire en tableau;
  • saisies_aplatir_tableau() qui permet de supprimer les niveaux d’imbrication dans le tableau ;
  • saisies_verifier_gel_saisie, qui vérifie 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.

À 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);
}

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.

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

Footnotes

[1La description des choix peut être passée dans #ENV{data}. #ENV{datas} est possible, mais déprécié.

[2À partir de saisie v4.0.0

Discussion

No discussion

Add a comment

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite / PostgreSQL
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparait.

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.

Who are you?
[Log in]

To show your avatar with your message, register it first on gravatar.com (free et painless) and don’t forget to indicate your Email addresse here.

Enter your comment here

This form accepts SPIP shortcuts {{bold}} {italic} -*list [text->url] <quote> <code> and HTML code <q> <del> <ins>. To create paragraphs, just leave empty lines.

Add a document

Follow the comments: RSS 2.0 | Atom