-<?php\r
-\r
-/**\r
- * Gestion de l'affichage des saisies\r
- *\r
- * @package SPIP\Saisies\Saisies\r
-**/\r
-\r
-// Sécurité\r
-if (!defined('_ECRIRE_INC_VERSION')) return;\r
-\r
-/*\r
- * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies\r
- *\r
- * saisies_lister_par_nom()\r
- * saisies_lister_champs()\r
- * saisies_lister_valeurs_defaut()\r
- * saisies_charger_champs()\r
- * saisies_chercher()\r
- * saisies_supprimer()\r
- * saisies_inserer()\r
- * saisies_deplacer()\r
- * saisies_modifier()\r
- * saisies_verifier()\r
- * saisies_comparer()\r
- * saisies_generer_html()\r
- * saisies_generer_vue()\r
- * saisies_generer_nom()\r
- * saisies_inserer_html()\r
- * saisies_lister_disponibles()\r
- * saisies_autonomes()\r
- */\r
-\r
-// Différentes méthodes pour trouver les saisies\r
-include_spip('inc/saisies_lister');\r
-\r
-// Différentes méthodes pour manipuler une liste de saisies\r
-include_spip('inc/saisies_manipuler');\r
-\r
-// Les outils pour afficher les saisies et leur vue\r
-include_spip('inc/saisies_afficher');\r
-\r
-/**\r
- * Cherche la description des saisies d'un formulaire CVT dont on donne le nom\r
- *\r
- * @param string $form Nom du formulaire dont on cherche les saisies\r
- * @param array $args Tableau d'arguments du formulaire\r
- * @return array Retourne les saisies du formulaire sinon false\r
- */\r
-function saisies_chercher_formulaire($form, $args){\r
- if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)\r
- and $saisies = call_user_func_array($fonction_saisies, $args)\r
- and is_array($saisies)\r
- // On passe les saisies dans un pipeline normé comme pour CVT\r
- and $saisies = pipeline(\r
- 'formulaire_saisies',\r
- array(\r
- 'args' => array('form' => $form, 'args' => $args),\r
- 'data' => $saisies\r
- )\r
- )\r
- // Si c'est toujours un tableau après le pipeline\r
- and is_array($saisies)\r
- ){\r
- return $saisies;\r
- }\r
- else{\r
- return false;\r
- }\r
-}\r
-\r
-/**\r
- * Cherche une saisie par son id, son nom ou son chemin et renvoie soit la saisie, soit son chemin\r
- *\r
- * @param array $saisies Un tableau décrivant les saisies\r
- * @param unknown_type $id_ou_nom_ou_chemin L'identifiant ou le nom de la saisie à chercher ou le chemin sous forme d'une liste de clés\r
- * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin\r
- * @return array Retourne soit la saisie, soit son chemin, soit null\r
- */\r
-function saisies_chercher($saisies, $id_ou_nom_ou_chemin, $retourner_chemin=false){\r
-\r
- if (is_array($saisies) and $id_ou_nom_ou_chemin){\r
- if (is_string($id_ou_nom_ou_chemin)){\r
- $nom = $id_ou_nom_ou_chemin;\r
- // identifiant ? premier caractere @\r
- $id = ($nom[0] == '@');\r
-\r
- foreach($saisies as $cle => $saisie){\r
- $chemin = array($cle);\r
- // notre saisie est la bonne ?\r
- if ($nom == ($id ? $saisie['identifiant'] : $saisie['options']['nom'])) {\r
- return $retourner_chemin ? $chemin : $saisie;\r
- // sinon a telle des enfants ? et si c'est le cas, cherchons dedans\r
- } elseif (isset($saisie['saisies']) and is_array($saisie['saisies']) and $saisie['saisies']\r
- and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))) {\r
- return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;\r
- }\r
-\r
- }\r
- }\r
- elseif (is_array($id_ou_nom_ou_chemin)){\r
- $chemin = $id_ou_nom_ou_chemin;\r
- $saisie = $saisies;\r
- // On vérifie l'existence quand même\r
- foreach ($chemin as $cle){\r
- if (isset($saisie[$cle])) $saisie = $saisie[$cle];\r
- else return null;\r
- }\r
- // Si c'est une vraie saisie\r
- if ($saisie['saisie'] and $saisie['options']['nom'])\r
- return $retourner_chemin ? $chemin : $saisie;\r
- }\r
- }\r
- \r
- return null;\r
-}\r
-\r
-/**\r
- * Génère un nom unique pour un champ d'un formulaire donné\r
- *\r
- * @param array $formulaire\r
- * Le formulaire à analyser \r
- * @param string $type_saisie\r
- * Le type de champ dont on veut un identifiant \r
- * @return string\r
- * Un nom unique par rapport aux autres champs du formulaire\r
- */\r
-function saisies_generer_nom($formulaire, $type_saisie){\r
- $champs = saisies_lister_champs($formulaire);\r
- \r
- // Tant que type_numero existe, on incrémente le compteur\r
- $compteur = 1;\r
- while (array_search($type_saisie.'_'.$compteur, $champs) !== false)\r
- $compteur++;\r
- \r
- // On a alors un compteur unique pour ce formulaire\r
- return $type_saisie.'_'.$compteur;\r
-}\r
-\r
-/**\r
- * Crée un identifiant Unique\r
- * pour toutes les saisies donnees qui n'en ont pas \r
- *\r
- * @param Array $saisies Tableau de saisies\r
- * @param Bool $regenerer Régénère un nouvel identifiant pour toutes les saisies ?\r
- * @return Array Tableau de saisies complété des identifiants\r
- */\r
-function saisies_identifier($saisies, $regenerer = false) {\r
- if (!is_array($saisies)) {\r
- return array();\r
- }\r
- foreach ($saisies as $k => $saisie) {\r
- $saisies[$k] = saisie_identifier($saisie, $regenerer);\r
- }\r
- return $saisies;\r
-}\r
-\r
-/**\r
- * Crée un identifiant Unique\r
- * pour la saisie donnee si elle n'en a pas\r
- * (et pour ses sous saisies éventuels)\r
- *\r
- * @param Array $saisie Tableau d'une saisie\r
- * @param Bool $regenerer Régénère un nouvel identifiant pour la saisie ?\r
- * @return Array Tableau de la saisie complété de l'identifiant\r
-**/\r
-function saisie_identifier($saisie, $regenerer = false) {\r
- if (!isset($saisie['identifiant']) OR !$saisie['identifiant']) {\r
- $saisie['identifiant'] = uniqid('@');\r
- } elseif ($regenerer) {\r
- $saisie['identifiant'] = uniqid('@');\r
- }\r
- if (isset($saisie['saisies']) AND is_array($saisie['saisies'])) {\r
- $saisie['saisies'] = saisies_identifier($saisie['saisies'], $regenerer);\r
- }\r
- return $saisie;\r
-}\r
-\r
-/**\r
- * Vérifier tout un formulaire tel que décrit avec les Saisies\r
- *\r
- * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies\r
- * @param bool $saisies_masquees_nulles Si TRUE, les saisies masquées selon afficher_si ne seront pas verifiées, leur valeur étant forcée a NULL. Cette valeur NULL est transmise à traiter (via set_request).\r
- * @return array Retourne un tableau d'erreurs\r
- */\r
-function saisies_verifier($formulaire, $saisies_masquees_nulles=true){\r
- include_spip('inc/verifier');\r
- $erreurs = array();\r
- $verif_fonction = charger_fonction('verifier','inc',true);\r
-\r
- if ($saisies_masquees_nulles)\r
- $formulaire = saisies_verifier_afficher_si($formulaire);\r
- \r
- $saisies = saisies_lister_par_nom($formulaire);\r
- foreach ($saisies as $saisie){\r
- $obligatoire = isset($saisie['options']['obligatoire']) ? $saisie['options']['obligatoire'] : '';\r
- $champ = $saisie['options']['nom'];\r
- $file = ($saisie['saisie'] == 'input' and isset($saisie['options']['type']) and $saisie['options']['type'] == 'file');\r
- $verifier = isset($saisie['verifier']) ? $saisie['verifier'] : false;\r
-\r
- // Si le nom du champ est un tableau indexé, il faut parser !\r
- if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)){\r
- $valeur = _request($separe[1]);\r
- preg_match_all('/\[([\w]+)\]/', $separe[2], $index);\r
- // On va chercher au fond du tableau\r
- foreach($index[1] as $cle){\r
- $valeur = isset($valeur[$cle]) ? $valeur[$cle] : null;\r
- }\r
- }\r
- // Sinon la valeur est juste celle du nom\r
- else\r
- $valeur = _request($champ);\r
- \r
- // Pour la saisie "destinataires" il faut filtrer si jamais on a mis un premier choix vide\r
- if ($saisie['saisie'] == 'destinataires') {\r
- $valeur = array_filter($valeur);\r
- }\r
- \r
- // On regarde d'abord si le champ est obligatoire\r
- if ($obligatoire\r
- and $obligatoire != 'non'\r
- and (\r
- ($file and !$_FILES[$champ]['name'])\r
- or (!$file and (\r
- is_null($valeur)\r
- or (is_string($valeur) and trim($valeur) == '')\r
- or (is_array($valeur) and count($valeur) == 0)\r
- ))\r
- )\r
- ) {\r
- $erreurs[$champ] =\r
- (isset($saisie['options']['erreur_obligatoire']) and $saisie['options']['erreur_obligatoire'])\r
- ? $saisie['options']['erreur_obligatoire']\r
- : _T('info_obligatoire');\r
- }\r
-\r
- // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif\r
- if ((!isset($erreurs[$champ]) or !$erreurs[$champ]) and is_array($verifier) and $verif_fonction){\r
- $normaliser = null;\r
- // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur\r
- $options = isset($verifier['options']) ? $verifier['options'] : array();\r
- if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $options, $normaliser)) {\r
- $erreurs[$champ] = $erreur_eventuelle;\r
- // S'il n'y a pas d'erreur et que la variable de normalisation a été remplie, on l'injecte dans le POST\r
- } elseif (!is_null($normaliser)) {\r
- set_request($champ, $normaliser);\r
- }\r
- }\r
- }\r
- \r
- return $erreurs;\r
-}\r
-\r
-/**\r
- * Applatie une description tabulaire\r
- * @param string $tab Le tableau à aplatir\r
- * @return $nouveau_tab\r
- */\r
-function saisies_aplatir_tableau($tab){\r
- $nouveau_tab = array();\r
- foreach($tab as $entree=>$contenu){\r
- if (is_array($contenu)) {\r
- foreach ($contenu as $cle => $valeur) {\r
- $nouveau_tab[$cle] = $valeur;\r
- }\r
- } else {\r
- $nouveau_tab[$entree] = $contenu;\r
- }\r
- }\r
- return $nouveau_tab;\r
-}\r
-\r
-/**\r
- * Applatie une description chaînée, en supprimant les sous-groupes.\r
- * @param string $chaine La chaîne à aplatir\r
- * @return $chaine\r
- */\r
-function saisies_aplatir_chaine($chaine){\r
- return trim(preg_replace("#(?:^|\n)(\*(?:.*)|/\*)\n#i","\n",$chaine));\r
-}\r
-\r
-/**\r
- * Transforme une chaine en tableau avec comme principe :\r
- * \r
- * - une ligne devient une case\r
- * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur\r
- * - si la ligne commence par * alors on commence un sous-tableau\r
- * - si la ligne est égale à /*, alors on fini le sous-tableau\r
- * \r
- * @param string $chaine Une chaine à transformer\r
- * @param string $separateur Séparateur utilisé\r
- * @return array Retourne un tableau PHP\r
- */\r
-function saisies_chaine2tableau($chaine, $separateur="\n"){\r
- if ($chaine and is_string($chaine)){\r
- $tableau = array();\r
- $soustab = False;\r
- // On découpe d'abord en lignes\r
- $lignes = explode($separateur, $chaine);\r
- foreach ($lignes as $i=>$ligne){\r
- $ligne = trim(trim($ligne), '|');\r
- // Si ce n'est pas une ligne sans rien\r
- if ($ligne !== ''){\r
- // si ca commence par * c'est qu'on va faire un sous tableau\r
- if (strpos($ligne,"*")===0) {\r
- $soustab=True;\r
- $soustab_cle = _T_ou_typo(substr($ligne,1), 'multi');\r
- if (!isset($tableau[$soustab_cle])){\r
- $tableau[$soustab_cle] = array();\r
- }\r
- }\r
- elseif ($ligne=="/*") {//si on finit sous tableau\r
- $soustab=False;\r
- }\r
- else{//sinon c'est une entrée normale\r
- // Si on trouve un découpage dans la ligne on fait cle|valeur\r
- if (strpos($ligne, '|') !== false) {\r
- list($cle,$valeur) = explode('|', $ligne, 2);\r
- // permettre les traductions de valeurs au passage\r
- if ($soustab == True){\r
- $tableau[$soustab_cle][$cle] = _T_ou_typo($valeur, 'multi');\r
- } else {\r
- $tableau[$cle] = _T_ou_typo($valeur, 'multi');\r
- }\r
- }\r
- // Sinon on génère la clé\r
- else{\r
- if ($soustab == True) {\r
- $tableau[$soustab_cle][$i] = _T_ou_typo($ligne,'multi');\r
- } else {\r
- $tableau[$i] = _T_ou_typo($ligne,'multi');\r
- }\r
- }\r
- }\r
- }\r
- }\r
- return $tableau;\r
- }\r
- // Si c'est déjà un tableau on lui applique _T_ou_typo (qui fonctionne de manière récursive avant de le renvoyer\r
- elseif (is_array($chaine)){\r
- return _T_ou_typo($chaine, 'multi');\r
- } else {\r
- return array();\r
- }\r
-}\r
-\r
-/**\r
- * Transforme un tableau en chaine de caractères avec comme principe :\r
- * \r
- * - une case de vient une ligne de la chaine\r
- * - chaque ligne est générée avec la forme cle|valeur\r
- * - si une entrée du tableau est elle même un tableau, on met une ligne de la forme *clef\r
- * - pour marquer que l'on quitte un sous-tableau, on met une ligne commencant par /*, sauf si on bascule dans un autre sous-tableau.\r
- *\r
- * @param array $tableau Tableau à transformer\r
- * @return string Texte représentant les données du tableau\r
- */\r
-function saisies_tableau2chaine($tableau){\r
- if ($tableau and is_array($tableau)){\r
- $chaine = '';\r
- $avant_est_tableau = False;\r
- foreach($tableau as $cle=>$valeur){\r
- if (is_array($valeur)){\r
- $avant_est_tableau = True;\r
- $ligne=trim("*$cle");\r
- $chaine .= "$ligne\n";\r
- $chaine .= saisies_tableau2chaine($valeur)."\n";\r
- }\r
- else{ \r
- if ($avant_est_tableau == True){\r
- $avant_est_tableau = False;\r
- $chaine.="/*\n";\r
- }\r
- $ligne = trim("$cle|$valeur");\r
- $chaine .= "$ligne\n";\r
- }\r
- }\r
- $chaine = trim($chaine);\r
- \r
- return $chaine;\r
- }\r
- // Si c'est déjà une chaine on la renvoie telle quelle\r
- elseif (is_string($tableau)){\r
- return $tableau;\r
- }\r
- else{\r
- return '';\r
- }\r
-}\r
-\r
-\r
-\r
-\r
-/**\r
- * Transforme une valeur en tableau d'élements si ce n'est pas déjà le cas\r
- *\r
- * @param mixed $valeur\r
- * @return array Tableau de valeurs\r
-**/\r
-function saisies_valeur2tableau($valeur) {\r
- if (is_array($valeur)) {\r
- return $valeur;\r
- }\r
-\r
- if (!strlen($valeur)) {\r
- return array();\r
- }\r
-\r
- $t = saisies_chaine2tableau($valeur);\r
- if (count($t) > 1) {\r
- return $t;\r
- }\r
-\r
- // qu'une seule valeur, c'est qu'elle a peut etre un separateur a virgule\r
- // et a donc une cle est 0 dans ce cas la d'ailleurs\r
- if (isset($t[0])) {\r
- $t = saisies_chaine2tableau($t[0], ',');\r
- }\r
-\r
- return $t;\r
-}\r
-\r
-\r
-/**\r
- * Pour les saisies multiples (type checkbox) proposant un choix alternatif,\r
- * retrouve à partir des data de choix proposés\r
- * et des valeurs des choix enregistrés\r
- * le texte enregistré pour le choix alternatif.\r
- *\r
- * @param array $data\r
- * @param array $valeur\r
- * @return string choix_alternatif\r
-**/\r
-function saisies_trouver_choix_alternatif($data,$valeur) {\r
- if (!is_array($valeur)) {\r
- $valeur = saisies_chaine2tableau($valeur) ;\r
- }\r
- if (!is_array($data)) {\r
- $data = saisies_chaine2tableau($data) ;\r
- }\r
- $choix_theorique = array_keys($data);\r
- $choix_alternatif = array_values(array_diff($valeur,$choix_theorique));\r
- return $choix_alternatif[0];//on suppose que personne ne s'est amusé à proposer deux choix alternatifs\r
-}\r
-\r
-/**\r
- * Génère une page d'aide listant toutes les saisies et leurs options\r
- *\r
- * Retourne le résultat du squelette `inclure/saisies_aide` auquel\r
- * on a transmis toutes les saisies connues.\r
- * \r
- * @return string Code HTML\r
- */\r
-function saisies_generer_aide(){\r
- // On a déjà la liste par saisie\r
- $saisies = saisies_lister_disponibles();\r
-\r
- // On construit une liste par options\r
- $options = array();\r
- foreach ($saisies as $type_saisie=>$saisie){\r
- $options_saisie = saisies_lister_par_nom($saisie['options'], false);\r
- foreach ($options_saisie as $nom=>$option){\r
- // Si l'option n'existe pas encore\r
- if (!isset($options[$nom])){\r
- $options[$nom] = _T_ou_typo($option['options']);\r
- }\r
- // On ajoute toujours par qui c'est utilisé\r
- $options[$nom]['utilisee_par'][] = $type_saisie;\r
- }\r
- ksort($options_saisie);\r
- $saisies[$type_saisie]['options'] = $options_saisie;\r
- }\r
- ksort($options);\r
-\r
- return recuperer_fond(\r
- 'inclure/saisies_aide',\r
- array(\r
- 'saisies' => $saisies,\r
- 'options' => $options\r
- )\r
- );\r
-}\r
-\r
-/**\r
- * Le tableau de saisies a-t-il une option afficher_si ?\r
- *\r
- * @param array $saisies Un tableau de saisies\r
- * @return boolean\r
- */\r
-\r
-function saisies_afficher_si($saisies) {\r
- $saisies = saisies_lister_par_nom($saisies,true);\r
- // Dès qu'il y a au moins une option afficher_si, on l'active\r
- foreach ($saisies as $saisie) {\r
- if (isset($saisie['options']['afficher_si']))\r
- return true;\r
- }\r
- return false;\r
-}\r
-\r
-\r
-/**\r
- * Le tableau de saisies a-t-il une option afficher_si_remplissage ?\r
- *\r
- * @param array $saisies Un tableau de saisies\r
- * @return boolean\r
- */\r
-function saisies_afficher_si_remplissage($saisies) {\r
- $saisies = saisies_lister_par_nom($saisies,true);\r
- // Dès qu'il y a au moins une option afficher_si_remplissage, on l'active\r
- foreach ($saisies as $saisie) {\r
- if (isset($saisie['options']['afficher_si_remplissage']))\r
- return true;\r
- }\r
- return false;\r
-}\r
-\r
+<?php
+
+/**
+ * Gestion de l'affichage des saisies
+ *
+ * @package SPIP\Saisies\Saisies
+**/
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) {
+ return;
+}
+
+/*
+ * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies
+ *
+ * saisies_lister_par_nom()
+ * saisies_lister_champs()
+ * saisies_lister_valeurs_defaut()
+ * saisies_charger_champs()
+ * saisies_chercher()
+ * saisies_supprimer()
+ * saisies_inserer()
+ * saisies_deplacer()
+ * saisies_modifier()
+ * saisies_verifier()
+ * saisies_comparer()
+ * saisies_generer_html()
+ * saisies_generer_vue()
+ * saisies_generer_nom()
+ * saisies_inserer_html()
+ * saisies_lister_disponibles()
+ * saisies_autonomes()
+ */
+
+// Différentes méthodes pour trouver les saisies
+include_spip('inc/saisies_lister');
+
+// Différentes méthodes pour manipuler une liste de saisies
+include_spip('inc/saisies_manipuler');
+
+// Les outils pour afficher les saisies et leur vue
+include_spip('inc/saisies_afficher');
+
+/**
+ * Cherche la description des saisies d'un formulaire CVT dont on donne le nom
+ *
+ * @param string $form Nom du formulaire dont on cherche les saisies
+ * @param array $args Tableau d'arguments du formulaire
+ * @return array Retourne les saisies du formulaire sinon false
+ */
+function saisies_chercher_formulaire($form, $args) {
+ if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)
+ and $saisies = call_user_func_array($fonction_saisies, $args)
+ and is_array($saisies)
+ // On passe les saisies dans un pipeline normé comme pour CVT
+ and $saisies = pipeline(
+ 'formulaire_saisies',
+ array(
+ 'args' => array('form' => $form, 'args' => $args),
+ 'data' => $saisies
+ )
+ )
+ // Si c'est toujours un tableau après le pipeline
+ and is_array($saisies)
+ ) {
+ return $saisies;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Cherche une saisie par son id, son nom ou son chemin et renvoie soit la saisie, soit son chemin
+ *
+ * @param array $saisies Un tableau décrivant les saisies
+ * @param unknown_type $id_ou_nom_ou_chemin L'identifiant ou le nom de la saisie à chercher ou le chemin sous forme d'une liste de clés
+ * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin
+ * @return array Retourne soit la saisie, soit son chemin, soit null
+ */
+function saisies_chercher($saisies, $id_ou_nom_ou_chemin, $retourner_chemin = false) {
+ if (is_array($saisies) and $id_ou_nom_ou_chemin) {
+ if (is_string($id_ou_nom_ou_chemin)) {
+ $nom = $id_ou_nom_ou_chemin;
+ // identifiant ? premier caractere @
+ $id = ($nom[0] == '@');
+
+ foreach ($saisies as $cle => $saisie) {
+ $chemin = array($cle);
+ // notre saisie est la bonne ?
+ if ($nom == ($id ? $saisie['identifiant'] : $saisie['options']['nom'])) {
+ return $retourner_chemin ? $chemin : $saisie;
+ // sinon a telle des enfants ? et si c'est le cas, cherchons dedans
+ } elseif (isset($saisie['saisies']) and is_array($saisie['saisies']) and $saisie['saisies']
+ and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))) {
+ return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;
+ }
+ }
+ } elseif (is_array($id_ou_nom_ou_chemin)) {
+ $chemin = $id_ou_nom_ou_chemin;
+ $saisie = $saisies;
+ // On vérifie l'existence quand même
+ foreach ($chemin as $cle) {
+ if (isset($saisie[$cle])) {
+ $saisie = $saisie[$cle];
+ } else {
+ return null;
+ }
+ }
+ // Si c'est une vraie saisie
+ if ($saisie['saisie'] and $saisie['options']['nom']) {
+ return $retourner_chemin ? $chemin : $saisie;
+ }
+ }
+ }
+
+ return null;
+}
+
+/**
+ * Génère un nom unique pour un champ d'un formulaire donné
+ *
+ * @param array $formulaire
+ * Le formulaire à analyser
+ * @param string $type_saisie
+ * Le type de champ dont on veut un identifiant
+ * @return string
+ * Un nom unique par rapport aux autres champs du formulaire
+ */
+function saisies_generer_nom($formulaire, $type_saisie) {
+ $champs = saisies_lister_champs($formulaire);
+
+ // Tant que type_numero existe, on incrémente le compteur
+ $compteur = 1;
+ while (array_search($type_saisie.'_'.$compteur, $champs) !== false) {
+ $compteur++;
+ }
+
+ // On a alors un compteur unique pour ce formulaire
+ return $type_saisie.'_'.$compteur;
+}
+
+/**
+ * Crée un identifiant Unique
+ * pour toutes les saisies donnees qui n'en ont pas
+ *
+ * @param Array $saisies Tableau de saisies
+ * @param Bool $regenerer Régénère un nouvel identifiant pour toutes les saisies ?
+ * @return Array Tableau de saisies complété des identifiants
+ */
+function saisies_identifier($saisies, $regenerer = false) {
+ if (!is_array($saisies)) {
+ return array();
+ }
+ foreach ($saisies as $k => $saisie) {
+ $saisies[$k] = saisie_identifier($saisie, $regenerer);
+ }
+ return $saisies;
+}
+
+/**
+ * Crée un identifiant Unique
+ * pour la saisie donnee si elle n'en a pas
+ * (et pour ses sous saisies éventuels)
+ *
+ * @param Array $saisie Tableau d'une saisie
+ * @param Bool $regenerer Régénère un nouvel identifiant pour la saisie ?
+ * @return Array Tableau de la saisie complété de l'identifiant
+**/
+function saisie_identifier($saisie, $regenerer = false) {
+ if (!isset($saisie['identifiant']) or !$saisie['identifiant']) {
+ $saisie['identifiant'] = uniqid('@');
+ } elseif ($regenerer) {
+ $saisie['identifiant'] = uniqid('@');
+ }
+ if (isset($saisie['saisies']) and is_array($saisie['saisies'])) {
+ $saisie['saisies'] = saisies_identifier($saisie['saisies'], $regenerer);
+ }
+ return $saisie;
+}
+
+/**
+ * Vérifier tout un formulaire tel que décrit avec les Saisies
+ *
+ * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies
+ * @param bool $saisies_masquees_nulles Si TRUE, les saisies masquées selon afficher_si ne seront pas verifiées, leur valeur étant forcée a NULL. Cette valeur NULL est transmise à traiter (via set_request).
+ * @return array Retourne un tableau d'erreurs
+ */
+function saisies_verifier($formulaire, $saisies_masquees_nulles = true) {
+ include_spip('inc/verifier');
+ $erreurs = array();
+ $verif_fonction = charger_fonction('verifier', 'inc', true);
+
+ if ($saisies_masquees_nulles) {
+ $formulaire = saisies_verifier_afficher_si($formulaire);
+ }
+
+ $saisies = saisies_lister_par_nom($formulaire);
+ foreach ($saisies as $saisie) {
+ $obligatoire = isset($saisie['options']['obligatoire']) ? $saisie['options']['obligatoire'] : '';
+ $champ = $saisie['options']['nom'];
+ $file = ($saisie['saisie'] == 'input' and isset($saisie['options']['type']) and $saisie['options']['type'] == 'file');
+ $verifier = isset($saisie['verifier']) ? $saisie['verifier'] : false;
+
+ // Si le nom du champ est un tableau indexé, il faut parser !
+ if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)) {
+ $valeur = _request($separe[1]);
+ preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
+ // On va chercher au fond du tableau
+ foreach ($index[1] as $cle) {
+ $valeur = isset($valeur[$cle]) ? $valeur[$cle] : null;
+ }
+ } else {
+ // Sinon la valeur est juste celle du nom
+ $valeur = _request($champ);
+ }
+
+ // Pour la saisie "destinataires" il faut filtrer si jamais on a mis un premier choix vide
+ if ($saisie['saisie'] == 'destinataires') {
+ $valeur = array_filter($valeur);
+ }
+
+ // On regarde d'abord si le champ est obligatoire
+ if ($obligatoire
+ and $obligatoire != 'non'
+ and (
+ ($file and !$_FILES[$champ]['name'])
+ or (!$file and (
+ is_null($valeur)
+ or (is_string($valeur) and trim($valeur) == '')
+ or (is_array($valeur) and count($valeur) == 0)
+ ))
+ )
+ ) {
+ $erreurs[$champ] =
+ (isset($saisie['options']['erreur_obligatoire']) and $saisie['options']['erreur_obligatoire'])
+ ? $saisie['options']['erreur_obligatoire']
+ : _T('info_obligatoire');
+ }
+
+ // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif
+ if ((!isset($erreurs[$champ]) or !$erreurs[$champ]) and is_array($verifier) and $verif_fonction) {
+ $normaliser = null;
+ // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur
+ $options = isset($verifier['options']) ? $verifier['options'] : array();
+ if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $options, $normaliser)) {
+ $erreurs[$champ] = $erreur_eventuelle;
+ // S'il n'y a pas d'erreur et que la variable de normalisation a été remplie, on l'injecte dans le POST
+ } elseif (!is_null($normaliser)) {
+ set_request($champ, $normaliser);
+ }
+ }
+ }
+
+ return $erreurs;
+}
+
+/**
+ * Applatie une description tabulaire
+ * @param string $tab Le tableau à aplatir
+ * @return $nouveau_tab
+ */
+function saisies_aplatir_tableau($tab) {
+ $nouveau_tab = array();
+ foreach ($tab as $entree => $contenu) {
+ if (is_array($contenu)) {
+ foreach ($contenu as $cle => $valeur) {
+ $nouveau_tab[$cle] = $valeur;
+ }
+ } else {
+ $nouveau_tab[$entree] = $contenu;
+ }
+ }
+ return $nouveau_tab;
+}
+
+/**
+ * Applatie une description chaînée, en supprimant les sous-groupes.
+ * @param string $chaine La chaîne à aplatir
+ * @return $chaine
+ */
+function saisies_aplatir_chaine($chaine) {
+ return trim(preg_replace("#(?:^|\n)(\*(?:.*)|/\*)\n#i", "\n", $chaine));
+}
+
+/**
+ * Transforme une chaine en tableau avec comme principe :
+ *
+ * - une ligne devient une case
+ * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur
+ * - si la ligne commence par * alors on commence un sous-tableau
+ * - si la ligne est égale à /*, alors on fini le sous-tableau
+ *
+ * @param string $chaine Une chaine à transformer
+ * @param string $separateur Séparateur utilisé
+ * @return array Retourne un tableau PHP
+ */
+function saisies_chaine2tableau($chaine, $separateur = "\n") {
+ if ($chaine and is_string($chaine)) {
+ $tableau = array();
+ $soustab = false;
+ // On découpe d'abord en lignes
+ $lignes = explode($separateur, $chaine);
+ foreach ($lignes as $i => $ligne) {
+ $ligne = trim(trim($ligne), '|');
+ // Si ce n'est pas une ligne sans rien
+ if ($ligne !== '') {
+ // si ca commence par * c'est qu'on va faire un sous tableau
+ if (strpos($ligne, '*') === 0) {
+ $soustab=true;
+ $soustab_cle = _T_ou_typo(substr($ligne, 1), 'multi');
+ if (!isset($tableau[$soustab_cle])) {
+ $tableau[$soustab_cle] = array();
+ }
+ } elseif ($ligne == '/*') {//si on finit sous tableau
+ $soustab=false;
+ } else {
+ //sinon c'est une entrée normale
+ // Si on trouve un découpage dans la ligne on fait cle|valeur
+ if (strpos($ligne, '|') !== false) {
+ list($cle,$valeur) = explode('|', $ligne, 2);
+ // permettre les traductions de valeurs au passage
+ if ($soustab == true) {
+ $tableau[$soustab_cle][$cle] = _T_ou_typo($valeur, 'multi');
+ } else {
+ $tableau[$cle] = _T_ou_typo($valeur, 'multi');
+ }
+ } else {
+ // Sinon on génère la clé
+ if ($soustab == true) {
+ $tableau[$soustab_cle][$i] = _T_ou_typo($ligne, 'multi');
+ } else {
+ $tableau[$i] = _T_ou_typo($ligne, 'multi');
+ }
+ }
+ }
+ }
+ }
+ return $tableau;
+ } elseif (is_array($chaine)) {
+ // Si c'est déjà un tableau on lui applique _T_ou_typo (qui fonctionne de manière récursive avant de le renvoyer
+ return _T_ou_typo($chaine, 'multi');
+ } else {
+ return array();
+ }
+}
+
+/**
+ * Transforme un tableau en chaine de caractères avec comme principe :
+ *
+ * - une case de vient une ligne de la chaine
+ * - chaque ligne est générée avec la forme cle|valeur
+ * - si une entrée du tableau est elle même un tableau, on met une ligne de la forme *clef
+ * - pour marquer que l'on quitte un sous-tableau, on met une ligne commencant par /*, sauf si on bascule dans un autre sous-tableau.
+ *
+ * @param array $tableau Tableau à transformer
+ * @return string Texte représentant les données du tableau
+ */
+function saisies_tableau2chaine($tableau) {
+ if ($tableau and is_array($tableau)) {
+ $chaine = '';
+ $avant_est_tableau = false;
+ foreach ($tableau as $cle => $valeur) {
+ if (is_array($valeur)) {
+ $avant_est_tableau = true;
+ $ligne=trim("*$cle");
+ $chaine .= "$ligne\n";
+ $chaine .= saisies_tableau2chaine($valeur)."\n";
+ } else {
+ if ($avant_est_tableau == true) {
+ $avant_est_tableau = false;
+ $chaine.="/*\n";
+ }
+ $ligne = trim("$cle|$valeur");
+ $chaine .= "$ligne\n";
+ }
+ }
+ $chaine = trim($chaine);
+
+ return $chaine;
+ } elseif (is_string($tableau)) {
+ // Si c'est déjà une chaine on la renvoie telle quelle
+ return $tableau;
+ } else {
+ return '';
+ }
+}
+
+/**
+ * Transforme une valeur en tableau d'élements si ce n'est pas déjà le cas
+ *
+ * @param mixed $valeur
+ * @return array Tableau de valeurs
+**/
+function saisies_valeur2tableau($valeur) {
+ if (is_array($valeur)) {
+ return $valeur;
+ }
+
+ if (!strlen($valeur)) {
+ return array();
+ }
+
+ $t = saisies_chaine2tableau($valeur);
+ if (count($t) > 1) {
+ return $t;
+ }
+
+ // qu'une seule valeur, c'est qu'elle a peut etre un separateur a virgule
+ // et a donc une cle est 0 dans ce cas la d'ailleurs
+ if (isset($t[0])) {
+ $t = saisies_chaine2tableau($t[0], ',');
+ }
+
+ return $t;
+}
+
+/**
+ * Pour les saisies multiples (type checkbox) proposant un choix alternatif,
+ * retrouve à partir des data de choix proposés
+ * et des valeurs des choix enregistrés
+ * le texte enregistré pour le choix alternatif.
+ *
+ * @param array $data
+ * @param array $valeur
+ * @return string choix_alternatif
+**/
+function saisies_trouver_choix_alternatif($data, $valeur) {
+ if (!is_array($valeur)) {
+ $valeur = saisies_chaine2tableau($valeur) ;
+ }
+ if (!is_array($data)) {
+ $data = saisies_chaine2tableau($data) ;
+ }
+ $choix_theorique = array_keys($data);
+ $choix_alternatif = array_values(array_diff($valeur, $choix_theorique));
+ return $choix_alternatif[0];//on suppose que personne ne s'est amusé à proposer deux choix alternatifs
+}
+
+/**
+ * Génère une page d'aide listant toutes les saisies et leurs options
+ *
+ * Retourne le résultat du squelette `inclure/saisies_aide` auquel
+ * on a transmis toutes les saisies connues.
+ *
+ * @return string Code HTML
+ */
+function saisies_generer_aide() {
+ // On a déjà la liste par saisie
+ $saisies = saisies_lister_disponibles();
+
+ // On construit une liste par options
+ $options = array();
+ foreach ($saisies as $type_saisie => $saisie) {
+ $options_saisie = saisies_lister_par_nom($saisie['options'], false);
+ foreach ($options_saisie as $nom => $option) {
+ // Si l'option n'existe pas encore
+ if (!isset($options[$nom])) {
+ $options[$nom] = _T_ou_typo($option['options']);
+ }
+ // On ajoute toujours par qui c'est utilisé
+ $options[$nom]['utilisee_par'][] = $type_saisie;
+ }
+ ksort($options_saisie);
+ $saisies[$type_saisie]['options'] = $options_saisie;
+ }
+ ksort($options);
+
+ return recuperer_fond(
+ 'inclure/saisies_aide',
+ array(
+ 'saisies' => $saisies,
+ 'options' => $options
+ )
+ );
+}
+
+/**
+ * Le tableau de saisies a-t-il une option afficher_si ?
+ *
+ * @param array $saisies Un tableau de saisies
+ * @return boolean
+ */
+
+function saisies_afficher_si($saisies) {
+ $saisies = saisies_lister_par_nom($saisies, true);
+ // Dès qu'il y a au moins une option afficher_si, on l'active
+ foreach ($saisies as $saisie) {
+ if (isset($saisie['options']['afficher_si'])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**
+ * Le tableau de saisies a-t-il une option afficher_si_remplissage ?
+ *
+ * @param array $saisies Un tableau de saisies
+ * @return boolean
+ */
+function saisies_afficher_si_remplissage($saisies) {
+ $saisies = saisies_lister_par_nom($saisies, true);
+ // Dès qu'il y a au moins une option afficher_si_remplissage, on l'active
+ foreach ($saisies as $saisie) {
+ if (isset($saisie['options']['afficher_si_remplissage'])) {
+ return true;
+ }
+ }
+ return false;
+}