Fonctionnement technique de la vérification des affichages conditionnels des saisies

La présente documentation est une documentation technique, qui explique comment, concrètement, le plugin Saisies vérifie les affichages conditionnels des saisies.

Elle est valable à partir de la version 3.26.0 du plugin, qui a réécrit toute la partie Javascript.

On lira au préalable les deux documents de référence :

Vocabulaire

Nous distinguons par la suite :

  • saisie conditionnée, celle qui reçoit un test afficher_si;
  • saisie conditionnante, celles qui sont évaluées dans les afficher_si.

L’affichage d’une saisie conditionnée dépendant de la valeur d’une (ou plusieurs) saisies conditionnantes.

Un test peut être simple (@a@ == 'b') ou complexe. Un test complexe est composé de plusieurs tests simples liés par des opérateurs booléens/des parenthèses (@a@ == 'b' || @a@ == 'c' ).

Le problème

Les conditions d’affichage des saisies doivent être testées :

  • à la volée, en JavaScript, à chaque fois qu’une saisie est modifiée
  • une fois le formulaire posté, en PHP, pour ne pas tenir compte des saisies vides parce que non affichées à cause d’une condition non remplie.

Il faut donc convertir un pseudo langage (celui défini dans l’article “Affichage conditionnel de saisie : syntaxe des tests”) en deux langages, en s’assurant de la cohérence.

Les éléments communs

Le fichier inc/saisies_afficher_si_commun.php contient les fonctions communes pour la vérification.

La fonction de base est saisies_parser_condition_afficher_si().

Elle reçoit une condition de type afficher_si et retourne un tableau listant l’ensemble des tests simples de cette condition. Ce tableau ne se préoccupe ni des parenthèses ni des opérateurs booléens (à l’exception de la négation !).

Pour chaque test simple, le tableau décrit :

  • le test complet ;
  • chacun de ses composants : champ, opérateur, valeur à tester, type de guillemets, négateurs, etc.

Ajouter un nouveau type de test se fait donc d’abord en modifiant cette fonction.

Les fonctions de conversion des conditions afficher_si en PHP/JS :

  • prennnent la condition ($condition);
  • l’analysent via saisies_parser_condition_afficher_si();
  • à partir de cette analyse, remplacent l’ensemble des tests simples par leur équivalent PHP/JS.

Une autre fonction à utiliser : saisies_afficher_si_verifier_syntaxe(). Elle prend deux paramètres :

  • la condition afficher_si;
  • le résultat de saisies_parser_condition_afficher_si()

Cette fonction retourne false s’il y a un problème dans la syntaxe du afficher_si. C’est à dire :

  1. Autres choses que des tests simples, des parenthèses et des opérateurs booléens. En effet, si tel est le cas, cela signifie que la condition afficher_si contient un code arbitraire, ce qui peut être problématique en termes de sécurité. Ce premier test est très rigoureux.
  2. Des problèmes dans l’enchaînement des opérateurs et des parenthèses : nombre non appareillé des parenthèses ouvrantes/fermantes ; opérateurs booléens sans rien à gauche ou à droite ; etc. Ce second test n’est pas exhaustif. En effet, si un faux positif passe, cela n’implique pas l’exécution de code arbitraire, mais juste un échec à effectuer le test.

Côté JavaScript

Depuis la version 3.26.0, chaque saisie conditionnée contient un attribut data-afficher_si au niveau de son conteneur.

Cet attribut se trouve dans le fichier saisies/_base.html, pour la plupart des saisies.
Pour les saisies “autonomes”, qui n’utilisent pas cet attribut, il faut l’insérer dans le squelette, au niveau du conteneur de saisie, de la manière suivante :

  1. [ data-afficher_si="(#ENV*{afficher_si}|saisies_afficher_si_js{#ENV{_saisies}})"]

Cet attribut n’est plus ni moins qu’un bout de code JavaScript, un test pouvant être évalué, et retournant true ou false. Il est calculé via la fonction saisies_afficher_si_js() qui reçoit le test afficher_si et la liste des saisies du formulaire courant.

Cette fonction détermine le test de data-afficher_si en fonction du type des saisies conditionnantes, en faisant appel à des sous fonctions, que nous ne détaillerons pas ici.

Le script afficher_si.js.html, chargé en même temps qu’un formulaire :

  • est à l’affût des changements sur les saisies du formulaire (.change());
  • si un changement a lieu sur une saisie conditionnante, recherche les saisies conditionnées, en regardant les attributs data-afficher_si;
  • execute (via eval()) le test de data-afficher_si;
  • en fonction du résultat, affiche ou masque la saisie conditionnante et modifie la classe entre afficher_si_visible et afficher_si_masque;
  • pour les saisies conditionnées définies comme obligatoires, bascule, si besoin, l’attribut required. En effet, si la saisie est masquée, il faut supprimer l’attribut, pour que les navigateurs ne disent pas qu’un champ masqué est obligatoire. Mais il faut le rétablir lorsque la saisie est reaffichée. Un drapeau data-afficher-si-required est utilisé pour conserver en mémoire l’information;
  • en outre, au chargement du formulaire, le script teste l’ensemble des data-afficher_si et masque le cas échéant les saisies.

Ainsi, lors d’un changement dans le formulaire, seules les saisies conditionnées par la saisie conditionnante modifiée sont testées. Un seul script est chargé pour l’ensemble des formulaires [1].

À noter que le JavaScript est généré à partir d’un squelette, pour tenir compte des constantes _SAISIES_AFFICHER_SI_JS_SHOW et _SAISIES_AFFICHER_SI_JS_HIDE.

Côté PHP

La fonction saisies_verifier_afficher_si() prend la description des saisies d’un formulaire, et, pour les saisies conditionnées dont la condition n’est pas rempli :

  • Si le second paramètre $env est fourni, supprime la saisie conditionnée de la description;
  • Si le second paramètre n’est pas fourni, supprime la valeur de la saisie de $_REQUEST.

Pour ce faire, elle utilise la fonction saisies_evaluer_afficher_si(), qui reçoit la condition de la saisie conditionnée, et les paramètres d’environnement.

Cette dernière fonction, appelle saisies_transformer_condition_afficher_si(), laquelle en s’appuyant sur la fonction saisies_parser_condition_afficher_si() transforme la condition afficher_si en une condition PHP évaluable (via eval).

saisies_transformer_condition_afficher_si() fait elle-même appelle à d’autres fonctions selon le type de saisie conditionnante à tester, selon les opérateurs, etc.

Compléments

Un certain nombre de tests unitaires, via le plugin “TestBuilder” ont été définis.

Dans certains cas, très spécifique, une saisie peut comporter en réalité deux champs. C’est par exemple le cas pour la saisie Evenements qui possède un sous champ <saisie>_liste_attente. Pour que des tests conditionnels soient possibles sur ces sous champ, qui ne sont pas à proprement parler des saisies, il faut utiliser le pipeline agenda_saisies_afficher_si_js_saisies_form, ajouté dans la version 3.27.0. Ceci permet à afficher_si_js de prendre en compte cette pseudo-saisie lorsqu’il génère le test conditionnel.

Comme ce pipeline est appelé à chaque saisie conditionnée d’un formulaire, il est bon d’utiliser des variables statiques pour ne pas faire 36 fois le calcul.

Exemple avec le sous champ liste_attente de la saisie evenement du plugin agenda.

/**
 * 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_js_saisies_form($flux) {
 
	//Ne pas refaire 36 fois le calcul
	static $old;
	static $new;
	if ($old == $flux) {
		return $new;
	}
	$old = $flux;
	include_spip('inc/saisies');
	$saisies_par_type = saisies_lister_par_type($flux);
	if (isset($saisies_par_type['evenements'])) {
		foreach ($saisies_par_type['evenements'] as $saisie => $description) {
			$saisie_inserer = array(
				'saisie' => 'evenements_liste_attente',
				'options' => array('nom'=>$saisie.'_liste_attente')
			);
			$flux = saisies_inserer($flux, $saisie_inserer);
		}
	}
	$new = $flux;
	return $flux;
}

Footnotes

[1Ces deux points n’étaient pas vrais avant la version 3.26.0 du plugin, qui générait un JavaScript spécifique par formulaire.

updated on 13 September 2019

Discussion

Aucune discussion

Comment on this article

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