source: spip-zone/_plugins_/saisies/inc/saisies.php @ 48038

Last change on this file since 48038 was 48038, checked in by rastapopoulos@…, 10 years ago

oups c'était pas la bonne variable

File size: 34.5 KB
Line 
1<?php
2
3// Sécurité
4if (!defined("_ECRIRE_INC_VERSION")) return;
5
6/*
7 * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies
8 *
9 * saisies_lister_par_nom()
10 * saisies_lister_champs()
11 * saisies_lister_valeurs_defaut()
12 * saisies_charger_champs()
13 * saisies_chercher()
14 * saisies_supprimer()
15 * saisies_inserer()
16 * saisies_deplacer()
17 * saisies_modifier()
18 * saisies_verifier()
19 * saisies_comparer()
20 * saisies_generer_html()
21 * saisies_generer_vue()
22 * saisies_generer_nom()
23 * saisies_inserer_html()
24 * saisies_lister_disponibles()
25 * saisies_autonomes()
26 */
27
28
29/*
30 * Prend la description complète du contenu d'un formulaire et retourne
31 * les saisies "à plat" classées par nom.
32 *
33 * @param array $contenu Le contenu d'un formulaire
34 * @param bool $avec_conteneur Indique si on renvoie aussi les saisies ayant des enfants, comme les fieldset
35 * @return array Un tableau avec uniquement les saisies
36 */
37function saisies_lister_par_nom($contenu, $avec_conteneur=true){
38        $saisies = array();
39       
40        if (is_array($contenu)){
41                foreach ($contenu as $ligne){
42                        if (is_array($ligne)){
43                                if (array_key_exists('saisie', $ligne) and (!is_array($ligne['saisies']) or $avec_conteneur)){
44                                        $saisies[$ligne['options']['nom']] = $ligne;
45                                }
46                                if (is_array($ligne['saisies'])){
47                                        $saisies = array_merge($saisies, saisies_lister_par_nom($ligne['saisies']));
48                                }
49                        }
50                }
51        }
52       
53        return $saisies;
54}
55
56
57
58/*
59 * Prend la description complète du contenu d'un formulaire et retourne
60 * les saisies "à plat" classées par type de saisie.
61 * $saisie['input']['input_1'] = $saisie
62 *
63 * @param array $contenu Le contenu d'un formulaire
64 * @return array Un tableau avec uniquement les saisies
65 */
66function saisies_lister_par_type($contenu) {
67        $saisies = array();
68       
69        if (is_array($contenu)){
70                foreach ($contenu as $ligne){
71                        if (is_array($ligne)){
72                                if (array_key_exists('saisie', $ligne) and (!is_array($ligne['saisies']))){
73                                        $saisies[ $ligne['saisie'] ][ $ligne['options']['nom'] ] = $ligne;
74                                }
75                                if (is_array($ligne['saisies'])){
76                                        $saisies = array_merge($saisies, saisies_lister_par_type($ligne['saisies']));
77                                }
78                        }
79                }
80        }
81       
82        return $saisies;
83}
84
85
86
87/*
88 * Prend la description complète du contenu d'un formulaire et retourne
89 * une liste des noms des champs du formulaire.
90 *
91 * @param array $contenu Le contenu d'un formulaire
92 * @return array Un tableau listant les noms des champs
93 */
94function saisies_lister_champs($contenu, $avec_conteneur=true){
95        $saisies = saisies_lister_par_nom($contenu, $avec_conteneur);
96        return array_keys($saisies);
97}
98
99/*
100 * Prend la description complète du contenu d'un formulaire et retourne
101 * une liste des valeurs par défaut des champs du formulaire.
102 *
103 * @param array $contenu Le contenu d'un formulaire
104 * @return array Un tableau renvoyant la valeur par défaut de chaque champs
105 */
106function saisies_lister_valeurs_defaut($contenu){
107        $contenu = saisies_lister_par_nom($contenu, false);
108        $defaut = array();
109        foreach ($contenu as $champs => $ligne)
110                $defaut[$champs]  = isset($ligne['options']['defaut']) ? $ligne['options']['defaut'] : ''; 
111        return $defaut;
112}
113
114
115/*
116 * A utiliser dans une fonction charger d'un formulaire CVT,
117 * cette fonction renvoie le tableau de contexte correspondant
118 * de la forme $contexte['nom_champ'] = ''
119 *
120 * @param array $contenu Le contenu d'un formulaire (un tableau de saisies)
121 * @return array Un tableau de contexte
122 */
123function saisies_charger_champs($contenu) {
124        // array_fill_keys est disponible uniquement avec PHP >= 5.2.0
125        // return array_fill_keys(saisies_lister_champs($contenu, false), '');
126        $champs = array();
127        foreach (saisies_lister_champs($contenu, false) as $champ)
128                $champs[$champ] = '';
129        return $champs;
130}
131
132/*
133 * Cherche la description des saisies d'un formulaire CVT dont on donne le nom
134 *
135 * @param string $form Nom du formulaire dont on cherche les saisies
136 * @return array Retourne les saisies du formulaire sinon false
137 */
138function saisies_chercher_formulaire($form, $args){
139        if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)
140                and $saisies = call_user_func_array($fonction_saisies, $args)
141                and is_array($saisies)
142        ){
143                // On passe les saisies dans un pipeline normé comme pour CVT
144                $saisies = pipeline(
145                        'formulaire_saisies',
146                        array(
147                                'args' => array('form' => $form, 'args' => $args),
148                                'data' => $saisies
149                        )
150                );
151                return $saisies;
152        }
153        else
154                return false;
155}
156
157/*
158 * Cherche une saisie par son nom ou son chemin et renvoie soit la saisie, soit son chemin
159 *
160 * @param array $saisies Un tableau décrivant les saisies
161 * @param unknown_type $nom_ou_chemin Le nom de la saisie à chercher ou le chemin sous forme d'une liste de clés
162 * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin
163 * @return array Retourne soit la saisie, soit son chemin, soit null
164 */
165function saisies_chercher($saisies, $nom_ou_chemin, $retourner_chemin=false){
166        if (is_array($saisies) and $nom_ou_chemin){
167                if (is_string($nom_ou_chemin)){
168                        $nom = $nom_ou_chemin;
169                        foreach($saisies as $cle => $saisie){
170                                $chemin = array($cle);
171                                if ($saisie['options']['nom'] == $nom)
172                                        return $retourner_chemin ? $chemin : $saisie;
173                                elseif ($saisie['saisies'] and is_array($saisie['saisies']) and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))){
174                                        return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;
175                                }
176                        }
177                }
178                elseif (is_array($nom_ou_chemin)){
179                        $chemin = $nom_ou_chemin;
180                        $saisie = $saisies;
181                        // On vérifie l'existence quand même
182                        foreach ($chemin as $cle){
183                                $saisie = $saisie[$cle];
184                        }
185                        // Si c'est une vraie saisie
186                        if ($saisie['saisie'] and $saisie['options']['nom'])
187                                return $retourner_chemin ? $chemin : $saisie;
188                }
189        }
190       
191        return null;
192}
193
194/*
195 * Supprimer une saisie dont on donne le nom ou le chemin
196 *
197 * @param array $saisies Un tableau décriant les saisies
198 * @param unknown_type $nom_ou_chemin Le nom de la saisie à supprimer ou son chemin sous forme d'une liste de clés
199 * @return array Retourne le tableau modifié décrivant les saisies
200 */
201function saisies_supprimer($saisies, $nom_ou_chemin){
202        // Si la saisie n'existe pas, on ne fait rien
203        if ($chemin = saisies_chercher($saisies, $nom_ou_chemin, true)){
204                // La position finale de la saisie
205                $position = array_pop($chemin);
206       
207                // On va chercher le parent par référence pour pouvoir le modifier
208                $parent =& $saisies;
209                foreach($chemin as $cle){
210                        $parent =& $parent[$cle];
211                }
212               
213                // On supprime et réordonne
214                unset($parent[$position]);
215                $parent = array_values($parent);
216        }
217       
218        return $saisies;
219}
220
221/*
222 * Insère une saisie à une position donnée
223 *
224 * @param array $saisies Un tableau décrivant les saisies
225 * @param array $saisie La saisie à insérer
226 * @param array $chemin La position complète où insérer la saisie
227 * @return array Retourne le tableau modifié des saisies
228 */
229function saisies_inserer($saisies, $saisie, $chemin=array()){
230        // On vérifie quand même que ce qu'on veut insérer est correct
231        if ($saisie['saisie'] and $saisie['options']['nom']){
232                // Par défaut le parent c'est la racine
233                $parent =& $saisies;
234                // S'il n'y a pas de position, on va insérer à la fin du formulaire
235                if (!$chemin){
236                        $position = count($parent);
237                }
238                elseif (is_array($chemin)){
239                        $position = array_pop($chemin);
240                        foreach ($chemin as $cle){
241                                // Si la clé est un conteneur de saisies "saisies" et qu'elle n'existe pas encore, on la crée
242                                if ($cle == 'saisies' and !isset($parent[$cle]))
243                                        $parent[$cle] = array();
244                                $parent =& $parent[$cle];
245                        }
246                        // On vérifie maintenant que la position est cohérente avec le parent
247                        if ($position < 0) $position = 0;
248                        elseif ($position > count($parent)) $position = count($parent);
249                }
250                // Et enfin on insère
251                array_splice($parent, $position, 0, array($saisie));
252        }
253       
254        return $saisies;
255}
256
257
258
259/*
260 * Duplique une saisie (ou groupe de saisie)
261 * en placant la copie a la suite de la saisie d'origine.
262 * Modifie automatiquement les identifiants des saisies
263 *
264 * @param array $saisies Un tableau décrivant les saisies
265 * @param unknown_type $nom_ou_chemin Le nom ou le chemin de la saisie a dupliquer
266 * @return array Retourne le tableau modifié des saisies
267 */
268function saisies_dupliquer($saisies, $nom_ou_chemin){
269        // On récupère le contenu de la saisie à déplacer
270        $saisie = saisies_chercher($saisies, $nom_ou_chemin);
271        if ($saisie) {
272                list($clone) = saisies_transformer_noms_auto($saisies, array($saisie));
273                // insertion apres quoi ?
274                $chemin_validation = saisies_chercher($saisies, $nom_ou_chemin, true);
275                // 1 de plus pour mettre APRES le champ trouve
276                $chemin_validation[count($chemin_validation)-1]++;
277
278                $saisies = saisies_inserer($saisies, $clone, $chemin_validation);
279        }
280
281        return $saisies;
282}
283
284
285/*
286 * Déplace une saisie existante autre part
287 *
288 * @param array $saisies Un tableau décrivant les saisies
289 * @param unknown_type $nom_ou_chemin Le nom ou le chemin de la saisie à déplacer
290 * @param string $ou Le nom de la saisie devant laquelle on déplacera OU le nom d'un conteneur entre crochets [conteneur]
291 * @return array Retourne le tableau modifié des saisies
292 */
293function saisies_deplacer($saisies, $nom_ou_chemin, $ou){
294        // On récupère le contenu de la saisie à déplacer
295        $saisie = saisies_chercher($saisies, $nom_ou_chemin);
296       
297        // Si on l'a bien trouvé
298        if ($saisie){
299                // On cherche l'endroit où la déplacer
300                // Si $ou est vide, c'est à la fin de la racine
301                if (!$ou){
302                        $saisies = saisies_supprimer($saisies, $nom_ou_chemin);
303                        $chemin = array(count($saisies));
304                }
305                // Si l'endroit est entre crochet, c'est un conteneur
306                elseif (preg_match('/^\[([\w]*)\]$/', $ou, $match)){
307                        $parent = $match[1];
308                        // Si dans les crochets il n'y a rien, on met à la fin du formulaire
309                        if (!$parent){
310                                $saisies = saisies_supprimer($saisies, $nom_ou_chemin);
311                                $chemin = array(count($saisies));
312                        }
313                        // Sinon on vérifie que ce conteneur existe
314                        elseif (saisies_chercher($saisies, $parent, true)){
315                                // S'il existe on supprime la saisie et on recherche la nouvelle position
316                                $saisies = saisies_supprimer($saisies, $nom_ou_chemin);
317                                $parent = saisies_chercher($saisies, $parent, true);
318                                $chemin = array_merge($parent, array('saisies', 1000000));
319                        }
320                        else
321                                $chemin = false;
322                }
323                // Sinon ça sera devant un champ
324                else{
325                        // On vérifie que le champ existe
326                        if (saisies_chercher($saisies, $ou, true)){
327                                // S'il existe on supprime la saisie et on recherche la nouvelle position
328                                $saisies = saisies_supprimer($saisies, $nom_ou_chemin);
329                                $chemin = saisies_chercher($saisies, $ou, true);
330                        }
331                        else
332                                $chemin = false;
333                }
334               
335                // Si seulement on a bien trouvé un nouvel endroit où la placer, alors on déplace
336                if ($chemin)
337                        $saisies = saisies_inserer($saisies, $saisie, $chemin);
338        }
339       
340        return $saisies;
341}
342
343/*
344 * Modifie une saisie
345 *
346 * @param array $saisies Un tableau décrivant les saisies
347 * @param unknown_type $nom_ou_chemin Le nom ou le chemin de la saisie à modifier
348 * @param array $modifs Le tableau des modifications à apporter à la saisie
349 * @return Retourne le tableau décrivant les saisies, mais modifié
350 */
351function saisies_modifier($saisies, $nom_ou_chemin, $modifs){
352        $chemin = saisies_chercher($saisies, $nom_ou_chemin, true);
353        $position = array_pop($chemin);
354        $parent =& $saisies;
355        foreach ($chemin as $cle){
356                $parent =& $parent[$cle];
357        }
358       
359        // On récupère le type, le nom et les enfants tels quels
360        $modifs['saisie'] = $parent[$position]['saisie'];
361        $modifs['options']['nom'] = $parent[$position]['options']['nom'];
362        if (is_array($parent[$position]['saisies'])) $modifs['saisies'] = $parent[$position]['saisies'];
363       
364        // On remplace tout
365        $parent[$position] = $modifs;
366       
367        // Cette méthode ne marche pas trop
368        //$parent[$position] = array_replace_recursive($parent[$position], $modifs);
369       
370        return $saisies;
371}
372
373/*
374 * Transforme tous les noms du formulaire avec un preg_replace
375 *
376 * @param array $saisies Un tableau décrivant les saisies
377 * @param string $masque Ce que l'on doit chercher dans le nom
378 * @param string $remplacement Ce par quoi on doit remplacer
379 * @return array Retourne le tableau modifié des saisies
380 */
381function saisies_transformer_noms($saisies, $masque, $remplacement){
382        if (is_array($saisies)){
383                foreach ($saisies as $cle => $saisie){
384                        $saisies[$cle]['options']['nom'] = preg_replace($masque, $remplacement, $saisie['options']['nom']);
385                        if (is_array($saisie['saisies']))
386                                $saisies[$cle]['saisies'] = saisies_transformer_noms($saisie['saisies'], $masque, $remplacement);
387                }
388        }
389       
390        return $saisies;
391}
392
393
394
395/*
396 * Transforme les noms d'une liste de saisie pour qu'ils soient
397 * uniques dans le formulaire donne.
398 *
399 * @param array $formulaire Le formulaire à analyser
400 * @param array $saisies Un tableau décrivant les saisies.
401 * @return array Retourne le tableau modifié des saisies
402 */
403function saisies_transformer_noms_auto($formulaire, $saisies){
404
405        if (is_array($saisies)){
406                foreach ($saisies as $cle => $saisie){
407                        $saisies[$cle]['options']['nom'] = saisies_generer_nom($formulaire, $saisie['saisie']);
408                        // il faut prendre en compte dans $formulaire les saisies modifiees
409                        // sinon on aurait potentiellement 2 champs successifs avec le meme nom.
410                        // on n'ajoute pas les saisies dont les noms ne sont pas encore calculees.
411                        $new = $saisies[$cle];
412                        unset($new['saisies']);
413                        $formulaire[] = $new;
414                       
415                        if (is_array($saisie['saisies']))
416                                $saisies[$cle]['saisies'] = saisies_transformer_noms_auto($formulaire, $saisie['saisies']);
417                }
418        }
419
420        return $saisies;
421}
422
423
424/*
425 * Vérifier tout un formulaire tel que décrit avec les Saisies
426 *
427 * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies
428 * @return array Retourne un tableau d'erreurs
429 */
430function saisies_verifier($formulaire){
431        include_spip('inc/verifier');
432        $erreurs = array();
433        $verif_fonction = charger_fonction('verifier','inc',true);
434       
435        $saisies = saisies_lister_par_nom($formulaire);
436        foreach ($saisies as $saisie){
437                $obligatoire = $saisie['options']['obligatoire'];
438                $champ = $saisie['options']['nom'];
439                $file = ($saisie['saisie'] == 'input' and $saisie['options']['type'] == 'file');
440                $verifier = $saisie['verifier'];
441
442                // Si le nom du champ est un tableau indexé, il faut parser !
443                if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)){
444                        $valeur = _request($separe[1]);
445                        preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
446                        // On va chercher au fond du tableau
447                        foreach($index[1] as $cle){
448                                $valeur = $valeur[$cle];
449                        }
450                }
451                // Sinon la valeur est juste celle du nom
452                else
453                        $valeur = _request($champ);
454               
455                // On regarde d'abord si le champ est obligatoire
456                if ($obligatoire
457                        and $obligatoire != 'non'
458                        and (
459                                ($file and !$_FILES[$champ]['name'])
460                                or (!$file and (
461                                        is_null($valeur)
462                                        or (is_string($valeur) and trim($valeur) == '')
463                                        or (is_array($valeur) and count($valeur) == 0)
464                                ))
465                        )
466                )
467                        $erreurs[$champ] = _T('info_obligatoire');
468               
469                // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif
470                if (!$erreurs[$champ] and is_array($verifier) and $verif_fonction){
471                        // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur
472                        if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $verifier['options']))
473                                $erreurs[$champ] = $erreur_eventuelle;
474                }
475        }
476       
477        return $erreurs;
478}
479
480/*
481 * Compare deux tableaux de saisies pour connaitre les différences
482 * @param array $saisies_anciennes Un tableau décrivant des saisies
483 * @param array $saisies_nouvelles Un autre tableau décrivant des saisies
484 * @param bool $avec_conteneur Indique si on veut prendre en compte dans la comparaison les conteneurs comme les fieldsets
485 * @return array Retourne le tableau des saisies supprimées, ajoutées et modifiées
486 */
487function saisies_comparer($saisies_anciennes, $saisies_nouvelles, $avec_conteneur=true){
488        $saisies_anciennes = saisies_lister_par_nom($saisies_anciennes, $avec_conteneur);
489        $saisies_nouvelles = saisies_lister_par_nom($saisies_nouvelles, $avec_conteneur);
490       
491        // Les saisies supprimées sont celles qui restent dans les anciennes quand on a enlevé toutes les nouvelles
492        $saisies_supprimees = array_diff_key($saisies_anciennes, $saisies_nouvelles);
493        // Les saisies ajoutées, c'est le contraire
494        $saisies_ajoutees = array_diff_key($saisies_nouvelles, $saisies_anciennes);
495        // Il reste alors les saisies qui ont le même nom
496        $saisies_restantes = array_intersect_key($saisies_anciennes, $saisies_nouvelles);
497        // Dans celles-ci, celles qui sont modifiées sont celles dont la valeurs est différentes
498        $saisies_modifiees = array_udiff($saisies_nouvelles, $saisies_restantes, 'saisies_comparer_rappel');
499        // Et enfin les saisies qui ont le même nom et la même valeur
500        $saisies_identiques = array_diff_key($saisies_restantes, $saisies_modifiees);
501       
502        return array(
503                'supprimees' => $saisies_supprimees,
504                'ajoutees' => $saisies_ajoutees,
505                'modifiees' => $saisies_modifiees,
506                'identiques' => $saisies_identiques
507        );
508}
509
510/*
511 * Compare deux saisies et indique si elles sont égales ou pas
512 */
513function saisies_comparer_rappel($a, $b){
514        if ($a === $b) return 0;
515        else return 1;
516}
517
518
519/**
520 * Retourne si une saisie peut être affichée.
521 * On s'appuie sur l'éventuelle clé "editable" du $champ.
522 * Si editable vaut :
523 *  absent : le champ est éditable
524 *  1, le champ est éditable
525 *  0, le champ n'est pas éditable
526 * -1, le champ est éditable s'il y a du contenu dans le champ (l'environnement)
527 *     ou dans un de ses enfants (fieldsets)
528 *
529 * @param $champ tableau de description de la saisie
530 * @param $env environnement transmis à la saisie, certainement l'environnement du formulaire
531 * @param $utiliser_editable false pour juste tester le cas -1
532 *
533 * @return bool la saisie est-elle éditable ?
534**/
535function saisie_editable($champ, $env, $utiliser_editable=true) {
536        if ($utiliser_editable) {
537                // si le champ n'est pas éditable, on sort.
538                if (!isset($champ['editable'])) {
539                        return true;
540                }
541                $editable = $champ['editable'];
542
543                if ($editable > 0) {
544                        return true;
545                }
546                if ($editable == 0) {
547                        return false;
548                }
549        }
550
551        // cas -1
552        // name de la saisie
553        if (isset($champ['options']['nom'])) {
554                // si on a le name dans l'environnement, on le teste
555                $nom = $champ['options']['nom'];
556                if (isset($env[$nom])) {
557                        return $env[$nom] ? true : false ;
558                }
559        }
560        // sinon, si on a des sous saisies
561        if (isset($champ['saisies']) and is_array($champ['saisies'])) {
562                foreach($champ['saisies'] as $saisie) {
563                        if (saisie_editable($saisie, $env, false)) {
564                                return true;
565                        }
566                }
567        }
568       
569        // aucun des paramètres demandés n'avait de contenu
570        return false;
571       
572}
573
574
575/*
576 * Génère une saisie à partir d'un tableau la décrivant et de l'environnement
577 * Le tableau doit être de la forme suivante :
578 * array(
579 *              'saisie' => 'input',
580 *              'options' => array(
581 *                      'nom' => 'le_name',
582 *                      'label' => 'Un titre plus joli',
583 *                      'obligatoire' => 'oui',
584 *                      'explication' => 'Remplissez ce champ en utilisant votre clavier.'
585 *              )
586 * )
587 */
588function saisies_generer_html($champ, $env=array()){
589        // Si le parametre n'est pas bon, on genere du vide
590        if (!is_array($champ))
591                return '';
592
593        // Si la saisie n'est pas editable, on sort aussi.
594        if (!saisie_editable($champ, $env)) {
595                return '';
596        }
597       
598        $contexte = array();
599       
600        // On sélectionne le type de saisie
601        $contexte['type_saisie'] = $champ['saisie'];
602       
603        // Peut-être des transformations à faire sur les options textuelles
604        $options = $champ['options'];
605
606       
607        foreach ($options as $option => $valeur){
608                $options[$option] = _T_ou_typo($valeur, 'multi');
609        }
610       
611        // On ajoute les options propres à la saisie
612        $contexte = array_merge($contexte, $options);
613       
614        // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
615        if(isset($contexte['env']) or is_array($champ['saisies'])){
616                unset($contexte['env']);
617               
618                // À partir du moment où on passe tout l'environnement, il faut enlever certains éléments qui ne doivent absolument provenir que des options
619                unset($env['inserer_debut']);
620                unset($env['inserer_fin']);
621                $saisies_disponibles = saisies_lister_disponibles();
622                if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){
623                        $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
624                        foreach ($options_a_supprimer as $option_a_supprimer){
625                                unset($env[$option_a_supprimer]);
626                        }
627                }
628               
629                $contexte = array_merge($env, $contexte);
630        }
631        // Sinon on ne sélectionne que quelques éléments importants
632        else{
633                // On récupère la liste des erreurs
634                $contexte['erreurs'] = $env['erreurs'];
635        }
636       
637        // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
638        // Si le nom du champ est un tableau indexé, il faut parser !
639        if (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){
640                $contexte['valeur'] = $env[$separe[1]];
641                preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
642                // On va chercher au fond du tableau
643                foreach($index[1] as $cle){
644                        $contexte['valeur'] = $contexte['valeur'][$cle];
645                }
646        }
647        // Sinon la valeur est juste celle du nom
648        else
649                $contexte['valeur'] = $env[$contexte['nom']];
650       
651        // Si ya des enfants on les remonte dans le contexte
652        if (is_array($champ['saisies']))
653                $contexte['saisies'] = $champ['saisies'];
654       
655        // On génère la saisie
656        return recuperer_fond(
657                'saisies/_base',
658                $contexte
659        );
660}
661
662/*
663 * Génère une vue d'une saisie
664 *
665 * @param array $saisie Un tableau décrivant une saisie
666 * @param array $env L'environnement, contenant normalement la réponse à la saisie
667 * @param array $env_obligatoire
668 * @return string Retour le HTML des vues
669 */
670function saisies_generer_vue($saisie, $env=array(), $env_obligatoire=array()){
671        // Si le paramètre n'est pas bon, on génère du vide
672        if (!is_array($saisie))
673                return '';
674       
675        $contexte = array();
676       
677        // On sélectionne le type de saisie
678        $contexte['type_saisie'] = $saisie['saisie'];
679       
680        // Peut-être des transformations à faire sur les options textuelles
681        $options = $saisie['options'];
682        foreach ($options as $option => $valeur){
683                $options[$option] = _T_ou_typo($valeur, 'multi');
684        }
685       
686        // On ajoute les options propres à la saisie
687        $contexte = array_merge($contexte, $options);
688       
689        // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
690        if(isset($contexte['env']) or is_array($saisie['saisies'])){
691                unset($contexte['env']);
692               
693                // À partir du moment où on passe tout l'environnement, il faut enlever
694                // certains éléments qui ne doivent absolument provenir que des options
695                $saisies_disponibles = saisies_lister_disponibles();
696                if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){
697                        $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
698                        foreach ($options_a_supprimer as $option_a_supprimer){
699                                unset($env[$option_a_supprimer]);
700                        }
701                }
702               
703                $contexte = array_merge($env, $contexte);
704        }
705       
706        // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
707       
708        // On regarde en priorité s'il y a un tableau listant toutes les valeurs
709        if ($env['valeurs'] and is_array($env['valeurs']) and isset($env['valeurs'][$contexte['nom']])){
710                $contexte['valeur'] = $env['valeurs'][$contexte['nom']];
711        }
712        // Si le nom du champ est un tableau indexé, il faut parser !
713        elseif (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){
714                $contexte['valeur'] = $env[$separe[1]];
715                preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
716                // On va chercher au fond du tableau
717                foreach($index[1] as $cle){
718                        $contexte['valeur'] = $contexte['valeur'][$cle];
719                }
720        }
721        // Sinon la valeur est juste celle du nom
722        else
723                $contexte['valeur'] = $env[$contexte['nom']];
724       
725        // Si ya des enfants on les remonte dans le contexte
726        if (is_array($saisie['saisies']))
727                $contexte['saisies'] = $saisie['saisies'];
728
729        if (is_array($env_obligatoire)) {
730                $contexte = array_merge($contexte, $env_obligatoire);
731        }
732        // On génère la saisie
733        return recuperer_fond(
734                'saisies-vues/_base',
735                $contexte
736        );
737}
738
739/*
740 * Génère un nom unique pour un champ d'un formulaire donné
741 *
742 * @param array $formulaire Le formulaire à analyser
743 * @param string $type_saisie Le type de champ dont on veut un identifiant
744 * @return string Un nom unique par rapport aux autres champs du formulaire
745 */
746function saisies_generer_nom($formulaire, $type_saisie){
747        $champs = saisies_lister_champs($formulaire);
748       
749        // Tant que type_numero existe, on incrémente le compteur
750        $compteur = 1;
751        while (array_search($type_saisie.'_'.$compteur, $champs) !== false)
752                $compteur++;
753       
754        // On a alors un compteur unique pour ce formulaire
755        return $type_saisie.'_'.$compteur;
756}
757
758/**
759 * Insère du HTML au début ou à la fin d'une saisie
760 *
761 * @param array $saisie La description d'une seule saisie
762 * @param string $insertion Du code HTML à insérer dans la saisie
763 * @param string $ou L'endroit où insérer le HTML : "debut" ou "fin"
764 * @return array Retourne la description de la saisie modifiée
765 */
766function saisies_inserer_html($saisie, $insertion, $ou='fin'){
767        if (!in_array($ou, array('debut', 'fin')))
768                $ou = 'fin';
769       
770        if ($ou == 'debut')
771                $saisie['options']['inserer_debut'] = $insertion.$saisie['options']['inserer_debut'];
772        elseif ($ou == 'fin')
773                $saisie['options']['inserer_fin'] = $saisie['options']['inserer_fin'].$insertion;
774       
775        return $saisie;
776}
777
778/*
779 * Liste toutes les saisies configurables (ayant une description)
780 *
781 * @return array Un tableau listant des saisies et leurs options
782 */
783function saisies_lister_disponibles(){
784        static $saisies = null;
785       
786        if (is_null($saisies)){
787                $saisies = array();
788                $liste = find_all_in_path('saisies/', '.+[.]yaml$');
789               
790                if (count($liste)){
791                        foreach ($liste as $fichier=>$chemin){
792                                $type_saisie = preg_replace(',[.]yaml$,i', '', $fichier);
793                                $dossier = str_replace($fichier, '', $chemin);
794                                // On ne garde que les saisies qui ont bien le HTML avec !
795                                if (file_exists("$dossier$type_saisie.html")
796                                        and (
797                                                is_array($saisie = saisies_charger_infos($type_saisie))
798                                        )
799                                ){
800                                        $saisies[$type_saisie] = $saisie;
801                                }
802                        }
803                }
804        }
805       
806        return $saisies;
807}
808
809/**
810 * Charger les informations contenues dans le yaml d'une saisie
811 *
812 * @param string $type_saisie Le type de la saisie
813 * @return array Un tableau contenant le YAML décodé
814 */
815function saisies_charger_infos($type_saisie){
816        include_spip('inc/yaml');
817        $fichier = find_in_path("saisies/$type_saisie.yaml");
818        $saisie = yaml_decode_file($fichier);
819        if (is_array($saisie)){
820                $saisie['titre'] = $saisie['titre'] ? _T_ou_typo($saisie['titre']) : $type_saisie;
821                $saisie['description'] = $saisie['description'] ? _T_ou_typo($saisie['description']) : '';
822                $saisie['icone'] = $saisie['icone'] ? find_in_path($saisie['icone']) : '';
823        }
824        return $saisie;
825}
826
827/*
828 * Quelles sont les saisies qui se débrouillent toutes seules, sans le _base commun
829 *
830 * @return array Retourne un tableau contenant les types de saisies qui ne doivent pas utiliser le _base.html commun
831 */
832function saisies_autonomes(){
833        $saisies_autonomes = pipeline(
834                'saisies_autonomes',
835                array(
836                        'fieldset',
837                        'hidden',
838                        'destinataires', 
839                        'explication'
840                )
841        );
842       
843        return $saisies_autonomes;
844}
845
846/*
847 * Transforme une chaine en tableau avec comme principe :
848 * - une ligne devient une case
849 * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur
850 *
851 * @param string $chaine Une chaine à transformer
852 * @return array Retourne un tableau PHP
853 */
854function saisies_chaine2tableau($chaine, $separateur="\n"){
855        if ($chaine and is_string($chaine)){
856                $tableau = array();
857                // On découpe d'abord en lignes
858                $lignes = explode($separateur, $chaine);
859                foreach ($lignes as $i=>$ligne){
860                        $ligne = trim(trim($ligne), '|');
861                        // Si ce n'est pas une ligne sans rien
862                        if ($ligne !== ''){
863                                // Si on trouve un découpage dans la ligne on fait cle|valeur
864                                if (strpos($ligne, '|') !== false){
865                                        list($cle,$valeur) = explode('|', $ligne, 2);
866                                        $tableau[$cle] = $valeur;
867                                }
868                                // Sinon on génère la clé
869                                else{
870                                        $tableau[$i] = $ligne;
871                                }
872                        }
873                }
874                return $tableau;
875        }
876        // Si c'est déjà un tableau on le renvoie tel quel
877        elseif (is_array($chaine)){
878                return $chaine;
879        }
880        else{
881                return array();
882        }
883}
884
885/*
886 * Transforme un tableau en chaine de caractères avec comme principe :
887 * - une case de vient une ligne de la chaine
888 * - chaque ligne est générée avec la forme cle|valeur
889 */
890function saisies_tableau2chaine($tableau){
891        if ($tableau and is_array($tableau)){
892                $chaine = '';
893       
894                foreach($tableau as $cle=>$valeur){
895                        $ligne = trim("$cle|$valeur");
896                        $chaine .= "$ligne\n";
897                }
898                $chaine = trim($chaine);
899       
900                return $chaine;
901        }
902        // Si c'est déjà une chaine on la renvoie telle quelle
903        elseif (is_string($tableau)){
904                return $tableau;
905        }
906        else{
907                return '';
908        }
909}
910
911/*
912 * Génère une page d'aide listant toutes les saisies et leurs options
913 */
914function saisies_generer_aide(){
915        // On a déjà la liste par saisie
916        $saisies = saisies_lister_disponibles();
917       
918        // On construit une liste par options
919        $options = array();
920        foreach ($saisies as $type_saisie=>$saisie){
921                $options_saisie = saisies_lister_par_nom($saisie['options'], false);
922                foreach ($options_saisie as $nom=>$option){
923                        // Si l'option n'existe pas encore
924                        if (!isset($options[$nom])){
925                                $options[$nom] = _T_ou_typo($option['options']);
926                        }
927                        // On ajoute toujours par qui c'est utilisé
928                        $options[$nom]['utilisee_par'][] = $type_saisie;
929                }
930                ksort($options_saisie);
931                $saisies[$type_saisie]['options'] = $options_saisie;
932        }
933        ksort($options);
934       
935        return recuperer_fond(
936                'inclure/saisies_aide',
937                array(
938                        'saisies' => $saisies,
939                        'options' => $options
940                )
941        );
942}
943
944/*
945 * Génère, à partir d'un tableau de saisie le code javascript ajouté à la fin de #GENERER_SAISIES
946 * pour produire un affichage conditionnel des saisies avec une option afficher_si.
947 *
948 * @param array $saisies Un tableau de saisies
949 * @param string $id_form Un identifiant unique pour le formulaire
950 * @return text
951 */
952function saisies_generer_js_afficher_si($saisies,$id_form){
953        $i = 0;
954        $saisies = saisies_lister_par_nom($saisies,true);
955        $code = '';
956        $code .= '$(document).ready(function(){';
957                $code .= 'verifier_saisies_'.$id_form.' = function(form){';
958                                foreach ($saisies as $saisie) {
959                                        if (isset($saisie['options']['afficher_si'])) {
960                                                $i++;
961                                                switch ($saisie['saisie']) {
962                                                        case 'fieldset':
963                                                                $class_li = 'fieldset_'.$saisie['options']['nom'];
964                                                                break;
965                                                        case 'explication':
966                                                                $class_li = 'explication_'.$saisie['options']['nom'];
967                                                                break;
968                                                        default:
969                                                                $class_li = 'editer_'.$saisie['options']['nom'];
970                                                }
971                                                $condition = $saisie['options']['afficher_si'];
972                                                // On gère le cas @plugin:non_plugin@
973                                                preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
974                                                foreach ($matches[1] as $plug) {
975                                                        if (defined('_DIR_PLUGIN_'.strtoupper($plug)))
976                                                                $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
977                                                        else
978                                                                $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
979                                                }
980                                                // On gère le cas @config:plugin:meta@ suivi d'un test
981                                                preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);
982                                                foreach ($matches[1] as $plugin) {
983                                                        $config = lire_config($plugin);
984                                                        $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);
985                                                }
986                                                // On transforme en une condition valide
987                                                preg_match_all('#@(.+)@#U', $condition, $matches);
988                                                foreach ($matches[1] as $nom) {
989                                                        switch($saisies[$nom]['saisie']) {
990                                                                case 'radio':
991                                                                case 'oui_non':
992                                                                        $condition = preg_replace('#@'.$nom.'@#U', '$(form).find("[name=\''.$nom.'\']:checked").val()', $condition);
993                                                                        break;
994                                                                default:
995                                                                        $condition = preg_replace('#@'.$nom.'@#U', '$(form).find("[name=\''.$nom.'\']").val()', $condition);
996                                                        }
997                                                }
998                                                $code .= 'if ('.$condition.') {$(form).find("li.'.$class_li.'").show(400);} ';
999                                                $code .= 'else {$(form).find(".'.$class_li.'").hide(400);} ';
1000                                        }
1001                                }
1002                $code .= '};';
1003                $code .= '$("li#afficher_si_'.$id_form.'").parents("form").each(function(){verifier_saisies_'.$id_form.'(this);});';
1004                $code .= '$("li#afficher_si_'.$id_form.'").parents("form").change(function(){verifier_saisies_'.$id_form.'(this);});';
1005        $code .= '});';
1006        return $i>0 ? $code : '';
1007}
1008
1009/*
1010 * Le tableau de saisies a-t-il une option afficher_si ?
1011 *
1012 * @param array $saisies Un tableau de saisies
1013 * @return boolean
1014 */
1015
1016function saisies_afficher_si($saisies) {
1017        $afficher_si = false;
1018        $saisies = saisies_lister_par_nom($saisies,true);
1019        foreach ($saisies as $saisie) {
1020                if (isset($saisie['options']['afficher_si']))
1021                        $afficher_si = true;
1022        }
1023        return $afficher_si;
1024}
1025
1026/*
1027 * Lorsque l'on affiche les saisies (#VOIR_SAISIES), les saisies ayant une option afficher_si
1028 * et dont les conditions ne sont pas remplies doivent être retirées du tableau de saisies
1029 *
1030 * @param array $saisies Un tableau de saisies
1031 * @param array $env Les variables d'environnement
1032 * @return array Un tableau de saisies
1033 */
1034
1035function saisies_verifier_afficher_si($saisies, $env) {
1036        // eviter une erreur par maladresse d'appel :)
1037        if (!is_array($saisies)) {
1038                return array();
1039        }
1040        foreach ($saisies as $cle => $saisie) {
1041                if (isset($saisie['options']['afficher_si'])) {
1042                        $condition = $saisie['options']['afficher_si'];
1043                        // On gère le cas @plugin:non_plugin@
1044                        preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
1045                        foreach ($matches[1] as $plug) {
1046                                if (defined('_DIR_PLUGIN_'.strtoupper($plug)))
1047                                        $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
1048                                else
1049                                        $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
1050                        }
1051                        // On transforme en une condition valide
1052                        $condition = preg_replace('#@(.+)@#U', '$env["valeurs"][\'$1\']', $condition);
1053                        eval('$ok = '.$condition.';');
1054                        if (!$ok)
1055                                unset($saisies[$cle]);
1056                }
1057        }
1058        return $saisies;
1059}
1060
1061?>
Note: See TracBrowser for help on using the repository browser.