[PLUGINS] +maj gis4
[lhc/web/www.git] / www / plugins / saisies / inc / saisies.php
1 <?php
2
3 /**
4 * Gestion de l'affichage des saisies
5 *
6 * @package SPIP\Saisies\Saisies
7 **/
8
9 // Sécurité
10 if (!defined('_ECRIRE_INC_VERSION')) return;
11
12 /*
13 * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies
14 *
15 * saisies_lister_par_nom()
16 * saisies_lister_champs()
17 * saisies_lister_valeurs_defaut()
18 * saisies_charger_champs()
19 * saisies_chercher()
20 * saisies_supprimer()
21 * saisies_inserer()
22 * saisies_deplacer()
23 * saisies_modifier()
24 * saisies_verifier()
25 * saisies_comparer()
26 * saisies_generer_html()
27 * saisies_generer_vue()
28 * saisies_generer_nom()
29 * saisies_inserer_html()
30 * saisies_lister_disponibles()
31 * saisies_autonomes()
32 */
33
34 // Différentes méthodes pour trouver les saisies
35 include_spip('inc/saisies_lister');
36
37 // Différentes méthodes pour manipuler une liste de saisies
38 include_spip('inc/saisies_manipuler');
39
40 // Les outils pour afficher les saisies et leur vue
41 include_spip('inc/saisies_afficher');
42
43 /**
44 * Cherche la description des saisies d'un formulaire CVT dont on donne le nom
45 *
46 * @param string $form Nom du formulaire dont on cherche les saisies
47 * @param array $args Tableau d'arguments du formulaire
48 * @return array Retourne les saisies du formulaire sinon false
49 */
50 function saisies_chercher_formulaire($form, $args){
51 if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)
52 and $saisies = call_user_func_array($fonction_saisies, $args)
53 and is_array($saisies)
54 // On passe les saisies dans un pipeline normé comme pour CVT
55 and $saisies = pipeline(
56 'formulaire_saisies',
57 array(
58 'args' => array('form' => $form, 'args' => $args),
59 'data' => $saisies
60 )
61 )
62 // Si c'est toujours un tableau après le pipeline
63 and is_array($saisies)
64 ){
65 return $saisies;
66 }
67 else{
68 return false;
69 }
70 }
71
72 /**
73 * Cherche une saisie par son id, son nom ou son chemin et renvoie soit la saisie, soit son chemin
74 *
75 * @param array $saisies Un tableau décrivant les saisies
76 * @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
77 * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin
78 * @return array Retourne soit la saisie, soit son chemin, soit null
79 */
80 function saisies_chercher($saisies, $id_ou_nom_ou_chemin, $retourner_chemin=false){
81
82 if (is_array($saisies) and $id_ou_nom_ou_chemin){
83 if (is_string($id_ou_nom_ou_chemin)){
84 $nom = $id_ou_nom_ou_chemin;
85 // identifiant ? premier caractere @
86 $id = ($nom[0] == '@');
87
88 foreach($saisies as $cle => $saisie){
89 $chemin = array($cle);
90 // notre saisie est la bonne ?
91 if ($nom == ($id ? $saisie['identifiant'] : $saisie['options']['nom'])) {
92 return $retourner_chemin ? $chemin : $saisie;
93 // sinon a telle des enfants ? et si c'est le cas, cherchons dedans
94 } elseif (isset($saisie['saisies']) and is_array($saisie['saisies']) and $saisie['saisies']
95 and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))) {
96 return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;
97 }
98
99 }
100 }
101 elseif (is_array($id_ou_nom_ou_chemin)){
102 $chemin = $id_ou_nom_ou_chemin;
103 $saisie = $saisies;
104 // On vérifie l'existence quand même
105 foreach ($chemin as $cle){
106 if (isset($saisie[$cle])) $saisie = $saisie[$cle];
107 else return null;
108 }
109 // Si c'est une vraie saisie
110 if ($saisie['saisie'] and $saisie['options']['nom'])
111 return $retourner_chemin ? $chemin : $saisie;
112 }
113 }
114
115 return null;
116 }
117
118 /**
119 * Génère un nom unique pour un champ d'un formulaire donné
120 *
121 * @param array $formulaire
122 * Le formulaire à analyser
123 * @param string $type_saisie
124 * Le type de champ dont on veut un identifiant
125 * @return string
126 * Un nom unique par rapport aux autres champs du formulaire
127 */
128 function saisies_generer_nom($formulaire, $type_saisie){
129 $champs = saisies_lister_champs($formulaire);
130
131 // Tant que type_numero existe, on incrémente le compteur
132 $compteur = 1;
133 while (array_search($type_saisie.'_'.$compteur, $champs) !== false)
134 $compteur++;
135
136 // On a alors un compteur unique pour ce formulaire
137 return $type_saisie.'_'.$compteur;
138 }
139
140 /**
141 * Crée un identifiant Unique
142 * pour toutes les saisies donnees qui n'en ont pas
143 *
144 * @param Array $saisies Tableau de saisies
145 * @param Bool $regenerer Régénère un nouvel identifiant pour toutes les saisies ?
146 * @return Array Tableau de saisies complété des identifiants
147 */
148 function saisies_identifier($saisies, $regenerer = false) {
149 if (!is_array($saisies)) {
150 return array();
151 }
152 foreach ($saisies as $k => $saisie) {
153 $saisies[$k] = saisie_identifier($saisie, $regenerer);
154 }
155 return $saisies;
156 }
157
158 /**
159 * Crée un identifiant Unique
160 * pour la saisie donnee si elle n'en a pas
161 * (et pour ses sous saisies éventuels)
162 *
163 * @param Array $saisie Tableau d'une saisie
164 * @param Bool $regenerer Régénère un nouvel identifiant pour la saisie ?
165 * @return Array Tableau de la saisie complété de l'identifiant
166 **/
167 function saisie_identifier($saisie, $regenerer = false) {
168 if (!isset($saisie['identifiant']) OR !$saisie['identifiant']) {
169 $saisie['identifiant'] = uniqid('@');
170 } elseif ($regenerer) {
171 $saisie['identifiant'] = uniqid('@');
172 }
173 if (isset($saisie['saisies']) AND is_array($saisie['saisies'])) {
174 $saisie['saisies'] = saisies_identifier($saisie['saisies'], $regenerer);
175 }
176 return $saisie;
177 }
178
179 /**
180 * Vérifier tout un formulaire tel que décrit avec les Saisies
181 *
182 * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies
183 * @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).
184 * @return array Retourne un tableau d'erreurs
185 */
186 function saisies_verifier($formulaire, $saisies_masquees_nulles=true){
187 include_spip('inc/verifier');
188 $erreurs = array();
189 $verif_fonction = charger_fonction('verifier','inc',true);
190
191 if ($saisies_masquees_nulles)
192 $formulaire = saisies_verifier_afficher_si($formulaire);
193
194 $saisies = saisies_lister_par_nom($formulaire);
195 foreach ($saisies as $saisie){
196 $obligatoire = isset($saisie['options']['obligatoire']) ? $saisie['options']['obligatoire'] : '';
197 $champ = $saisie['options']['nom'];
198 $file = ($saisie['saisie'] == 'input' and isset($saisie['options']['type']) and $saisie['options']['type'] == 'file');
199 $verifier = isset($saisie['verifier']) ? $saisie['verifier'] : false;
200
201 // Si le nom du champ est un tableau indexé, il faut parser !
202 if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)){
203 $valeur = _request($separe[1]);
204 preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
205 // On va chercher au fond du tableau
206 foreach($index[1] as $cle){
207 $valeur = isset($valeur[$cle]) ? $valeur[$cle] : null;
208 }
209 }
210 // Sinon la valeur est juste celle du nom
211 else
212 $valeur = _request($champ);
213
214 // Pour la saisie "destinataires" il faut filtrer si jamais on a mis un premier choix vide
215 if ($saisie['saisie'] == 'destinataires') {
216 $valeur = array_filter($valeur);
217 }
218
219 // On regarde d'abord si le champ est obligatoire
220 if ($obligatoire
221 and $obligatoire != 'non'
222 and (
223 ($file and !$_FILES[$champ]['name'])
224 or (!$file and (
225 is_null($valeur)
226 or (is_string($valeur) and trim($valeur) == '')
227 or (is_array($valeur) and count($valeur) == 0)
228 ))
229 )
230 ) {
231 $erreurs[$champ] =
232 (isset($saisie['options']['erreur_obligatoire']) and $saisie['options']['erreur_obligatoire'])
233 ? $saisie['options']['erreur_obligatoire']
234 : _T('info_obligatoire');
235 }
236
237 // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif
238 if ((!isset($erreurs[$champ]) or !$erreurs[$champ]) and is_array($verifier) and $verif_fonction){
239 $normaliser = null;
240 // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur
241 $options = isset($verifier['options']) ? $verifier['options'] : array();
242 if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $options, $normaliser)) {
243 $erreurs[$champ] = $erreur_eventuelle;
244 // S'il n'y a pas d'erreur et que la variable de normalisation a été remplie, on l'injecte dans le POST
245 } elseif (!is_null($normaliser)) {
246 set_request($champ, $normaliser);
247 }
248 }
249 }
250
251 return $erreurs;
252 }
253
254 /**
255 * Applatie une description tabulaire
256 * @param string $tab Le tableau à aplatir
257 * @return $nouveau_tab
258 */
259 function saisies_aplatir_tableau($tab){
260 $nouveau_tab = array();
261 foreach($tab as $entree=>$contenu){
262 if (is_array($contenu)) {
263 foreach ($contenu as $cle => $valeur) {
264 $nouveau_tab[$cle] = $valeur;
265 }
266 } else {
267 $nouveau_tab[$entree] = $contenu;
268 }
269 }
270 return $nouveau_tab;
271 }
272
273 /**
274 * Applatie une description chaînée, en supprimant les sous-groupes.
275 * @param string $chaine La chaîne à aplatir
276 * @return $chaine
277 */
278 function saisies_aplatir_chaine($chaine){
279 return trim(preg_replace("#(?:^|\n)(\*(?:.*)|/\*)\n#i","\n",$chaine));
280 }
281
282 /**
283 * Transforme une chaine en tableau avec comme principe :
284 *
285 * - une ligne devient une case
286 * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur
287 * - si la ligne commence par * alors on commence un sous-tableau
288 * - si la ligne est égale à /*, alors on fini le sous-tableau
289 *
290 * @param string $chaine Une chaine à transformer
291 * @param string $separateur Séparateur utilisé
292 * @return array Retourne un tableau PHP
293 */
294 function saisies_chaine2tableau($chaine, $separateur="\n"){
295 if ($chaine and is_string($chaine)){
296 $tableau = array();
297 $soustab = False;
298 // On découpe d'abord en lignes
299 $lignes = explode($separateur, $chaine);
300 foreach ($lignes as $i=>$ligne){
301 $ligne = trim(trim($ligne), '|');
302 // Si ce n'est pas une ligne sans rien
303 if ($ligne !== ''){
304 // si ca commence par * c'est qu'on va faire un sous tableau
305 if (strpos($ligne,"*")===0) {
306 $soustab=True;
307 $soustab_cle = _T_ou_typo(substr($ligne,1), 'multi');
308 if (!isset($tableau[$soustab_cle])){
309 $tableau[$soustab_cle] = array();
310 }
311 }
312 elseif ($ligne=="/*") {//si on finit sous tableau
313 $soustab=False;
314 }
315 else{//sinon c'est une entrée normale
316 // Si on trouve un découpage dans la ligne on fait cle|valeur
317 if (strpos($ligne, '|') !== false) {
318 list($cle,$valeur) = explode('|', $ligne, 2);
319 // permettre les traductions de valeurs au passage
320 if ($soustab == True){
321 $tableau[$soustab_cle][$cle] = _T_ou_typo($valeur, 'multi');
322 } else {
323 $tableau[$cle] = _T_ou_typo($valeur, 'multi');
324 }
325 }
326 // Sinon on génère la clé
327 else{
328 if ($soustab == True) {
329 $tableau[$soustab_cle][$i] = _T_ou_typo($ligne,'multi');
330 } else {
331 $tableau[$i] = _T_ou_typo($ligne,'multi');
332 }
333 }
334 }
335 }
336 }
337 return $tableau;
338 }
339 // Si c'est déjà un tableau on lui applique _T_ou_typo (qui fonctionne de manière récursive avant de le renvoyer
340 elseif (is_array($chaine)){
341 return _T_ou_typo($chaine, 'multi');
342 } else {
343 return array();
344 }
345 }
346
347 /**
348 * Transforme un tableau en chaine de caractères avec comme principe :
349 *
350 * - une case de vient une ligne de la chaine
351 * - chaque ligne est générée avec la forme cle|valeur
352 * - si une entrée du tableau est elle même un tableau, on met une ligne de la forme *clef
353 * - pour marquer que l'on quitte un sous-tableau, on met une ligne commencant par /*, sauf si on bascule dans un autre sous-tableau.
354 *
355 * @param array $tableau Tableau à transformer
356 * @return string Texte représentant les données du tableau
357 */
358 function saisies_tableau2chaine($tableau){
359 if ($tableau and is_array($tableau)){
360 $chaine = '';
361 $avant_est_tableau = False;
362 foreach($tableau as $cle=>$valeur){
363 if (is_array($valeur)){
364 $avant_est_tableau = True;
365 $ligne=trim("*$cle");
366 $chaine .= "$ligne\n";
367 $chaine .= saisies_tableau2chaine($valeur)."\n";
368 }
369 else{
370 if ($avant_est_tableau == True){
371 $avant_est_tableau = False;
372 $chaine.="/*\n";
373 }
374 $ligne = trim("$cle|$valeur");
375 $chaine .= "$ligne\n";
376 }
377 }
378 $chaine = trim($chaine);
379
380 return $chaine;
381 }
382 // Si c'est déjà une chaine on la renvoie telle quelle
383 elseif (is_string($tableau)){
384 return $tableau;
385 }
386 else{
387 return '';
388 }
389 }
390
391
392
393
394 /**
395 * Transforme une valeur en tableau d'élements si ce n'est pas déjà le cas
396 *
397 * @param mixed $valeur
398 * @return array Tableau de valeurs
399 **/
400 function saisies_valeur2tableau($valeur) {
401 if (is_array($valeur)) {
402 return $valeur;
403 }
404
405 if (!strlen($valeur)) {
406 return array();
407 }
408
409 $t = saisies_chaine2tableau($valeur);
410 if (count($t) > 1) {
411 return $t;
412 }
413
414 // qu'une seule valeur, c'est qu'elle a peut etre un separateur a virgule
415 // et a donc une cle est 0 dans ce cas la d'ailleurs
416 if (isset($t[0])) {
417 $t = saisies_chaine2tableau($t[0], ',');
418 }
419
420 return $t;
421 }
422
423
424 /**
425 * Pour les saisies multiples (type checkbox) proposant un choix alternatif,
426 * retrouve à partir des data de choix proposés
427 * et des valeurs des choix enregistrés
428 * le texte enregistré pour le choix alternatif.
429 *
430 * @param array $data
431 * @param array $valeur
432 * @return string choix_alternatif
433 **/
434 function saisies_trouver_choix_alternatif($data,$valeur) {
435 if (!is_array($valeur)) {
436 $valeur = saisies_chaine2tableau($valeur) ;
437 }
438 if (!is_array($data)) {
439 $data = saisies_chaine2tableau($data) ;
440 }
441 $choix_theorique = array_keys($data);
442 $choix_alternatif = array_values(array_diff($valeur,$choix_theorique));
443 return $choix_alternatif[0];//on suppose que personne ne s'est amusé à proposer deux choix alternatifs
444 }
445
446 /**
447 * Génère une page d'aide listant toutes les saisies et leurs options
448 *
449 * Retourne le résultat du squelette `inclure/saisies_aide` auquel
450 * on a transmis toutes les saisies connues.
451 *
452 * @return string Code HTML
453 */
454 function saisies_generer_aide(){
455 // On a déjà la liste par saisie
456 $saisies = saisies_lister_disponibles();
457
458 // On construit une liste par options
459 $options = array();
460 foreach ($saisies as $type_saisie=>$saisie){
461 $options_saisie = saisies_lister_par_nom($saisie['options'], false);
462 foreach ($options_saisie as $nom=>$option){
463 // Si l'option n'existe pas encore
464 if (!isset($options[$nom])){
465 $options[$nom] = _T_ou_typo($option['options']);
466 }
467 // On ajoute toujours par qui c'est utilisé
468 $options[$nom]['utilisee_par'][] = $type_saisie;
469 }
470 ksort($options_saisie);
471 $saisies[$type_saisie]['options'] = $options_saisie;
472 }
473 ksort($options);
474
475 return recuperer_fond(
476 'inclure/saisies_aide',
477 array(
478 'saisies' => $saisies,
479 'options' => $options
480 )
481 );
482 }
483
484 /**
485 * Le tableau de saisies a-t-il une option afficher_si ?
486 *
487 * @param array $saisies Un tableau de saisies
488 * @return boolean
489 */
490
491 function saisies_afficher_si($saisies) {
492 $saisies = saisies_lister_par_nom($saisies,true);
493 // Dès qu'il y a au moins une option afficher_si, on l'active
494 foreach ($saisies as $saisie) {
495 if (isset($saisie['options']['afficher_si']))
496 return true;
497 }
498 return false;
499 }
500
501
502 /**
503 * Le tableau de saisies a-t-il une option afficher_si_remplissage ?
504 *
505 * @param array $saisies Un tableau de saisies
506 * @return boolean
507 */
508 function saisies_afficher_si_remplissage($saisies) {
509 $saisies = saisies_lister_par_nom($saisies,true);
510 // Dès qu'il y a au moins une option afficher_si_remplissage, on l'active
511 foreach ($saisies as $saisie) {
512 if (isset($saisie['options']['afficher_si_remplissage']))
513 return true;
514 }
515 return false;
516 }
517