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

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

Commentaire + saisies_voir n'emmetant pas de faux env sur les enfants de fieldset.

File size: 34.9 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                // on sauve l'ancien environnement
619                // car les sous-saisies ne doivent pas être affectees
620                // par les modification sur l'environnement servant à generer la saisie mère
621                $contexte['_env'] = $env;
622               
623                // À partir du moment où on passe tout l'environnement, il faut enlever certains éléments qui ne doivent absolument provenir que des options
624                unset($env['inserer_debut']);
625                unset($env['inserer_fin']);
626                $saisies_disponibles = saisies_lister_disponibles();
627                if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){
628                        $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
629                        foreach ($options_a_supprimer as $option_a_supprimer){
630                                unset($env[$option_a_supprimer]);
631                        }
632                }
633               
634                $contexte = array_merge($env, $contexte);
635        }
636        // Sinon on ne sélectionne que quelques éléments importants
637        else{
638                // On récupère la liste des erreurs
639                $contexte['erreurs'] = $env['erreurs'];
640        }
641
642        // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
643        // Si le nom du champ est un tableau indexé, il faut parser !
644        if (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){
645                $contexte['valeur'] = $env[$separe[1]];
646                preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
647                // On va chercher au fond du tableau
648                foreach($index[1] as $cle){
649                        $contexte['valeur'] = $contexte['valeur'][$cle];
650                }
651        }
652        // Sinon la valeur est juste celle du nom
653        else
654                $contexte['valeur'] = $env[$contexte['nom']];
655
656        // Si ya des enfants on les remonte dans le contexte
657        if (is_array($champ['saisies']))
658                $contexte['saisies'] = $champ['saisies'];
659       
660        // On génère la saisie
661        return recuperer_fond(
662                'saisies/_base',
663                $contexte
664        );
665}
666
667/*
668 * Génère une vue d'une saisie
669 *
670 * @param array $saisie Un tableau décrivant une saisie
671 * @param array $env L'environnement, contenant normalement la réponse à la saisie
672 * @param array $env_obligatoire
673 * @return string Retour le HTML des vues
674 */
675function saisies_generer_vue($saisie, $env=array(), $env_obligatoire=array()){
676        // Si le paramètre n'est pas bon, on génère du vide
677        if (!is_array($saisie))
678                return '';
679
680        $contexte = array();
681               
682        // On sélectionne le type de saisie
683        $contexte['type_saisie'] = $saisie['saisie'];
684       
685        // Peut-être des transformations à faire sur les options textuelles
686        $options = $saisie['options'];
687        foreach ($options as $option => $valeur){
688                $options[$option] = _T_ou_typo($valeur, 'multi');
689        }
690       
691        // On ajoute les options propres à la saisie
692        $contexte = array_merge($contexte, $options);
693
694        // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
695        if(isset($contexte['env']) or is_array($saisie['saisies'])){
696                unset($contexte['env']);
697
698                // on sauve l'ancien environnement
699                // car les sous-saisies ne doivent pas être affectees
700                // par les modification sur l'environnement servant à generer la saisie mère
701                $contexte['_env'] = $env;
702                               
703                // À partir du moment où on passe tout l'environnement, il faut enlever
704                // certains éléments qui ne doivent absolument provenir que des options
705                $saisies_disponibles = saisies_lister_disponibles();
706                if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){
707                        $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
708                        foreach ($options_a_supprimer as $option_a_supprimer){
709                                unset($env[$option_a_supprimer]);
710                        }
711                }
712               
713                $contexte = array_merge($env, $contexte);
714        }
715
716        // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
717       
718        // On regarde en priorité s'il y a un tableau listant toutes les valeurs
719        if ($env['valeurs'] and is_array($env['valeurs']) and isset($env['valeurs'][$contexte['nom']])){
720                $contexte['valeur'] = $env['valeurs'][$contexte['nom']];
721        }
722        // Si le nom du champ est un tableau indexé, il faut parser !
723        elseif (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){
724                $contexte['valeur'] = $env[$separe[1]];
725                preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
726                // On va chercher au fond du tableau
727                foreach($index[1] as $cle){
728                        $contexte['valeur'] = $contexte['valeur'][$cle];
729                }
730        }
731        // Sinon la valeur est juste celle du nom
732        else
733                $contexte['valeur'] = $env[$contexte['nom']];
734
735        // Si ya des enfants on les remonte dans le contexte
736        if (is_array($saisie['saisies']))
737                $contexte['saisies'] = $saisie['saisies'];
738
739        if (is_array($env_obligatoire)) {
740                $contexte = array_merge($contexte, $env_obligatoire);
741        }
742        // On génère la saisie
743        return recuperer_fond(
744                'saisies-vues/_base',
745                $contexte
746        );
747}
748
749/*
750 * Génère un nom unique pour un champ d'un formulaire donné
751 *
752 * @param array $formulaire Le formulaire à analyser
753 * @param string $type_saisie Le type de champ dont on veut un identifiant
754 * @return string Un nom unique par rapport aux autres champs du formulaire
755 */
756function saisies_generer_nom($formulaire, $type_saisie){
757        $champs = saisies_lister_champs($formulaire);
758       
759        // Tant que type_numero existe, on incrémente le compteur
760        $compteur = 1;
761        while (array_search($type_saisie.'_'.$compteur, $champs) !== false)
762                $compteur++;
763       
764        // On a alors un compteur unique pour ce formulaire
765        return $type_saisie.'_'.$compteur;
766}
767
768/**
769 * Insère du HTML au début ou à la fin d'une saisie
770 *
771 * @param array $saisie La description d'une seule saisie
772 * @param string $insertion Du code HTML à insérer dans la saisie
773 * @param string $ou L'endroit où insérer le HTML : "debut" ou "fin"
774 * @return array Retourne la description de la saisie modifiée
775 */
776function saisies_inserer_html($saisie, $insertion, $ou='fin'){
777        if (!in_array($ou, array('debut', 'fin')))
778                $ou = 'fin';
779       
780        if ($ou == 'debut')
781                $saisie['options']['inserer_debut'] = $insertion.$saisie['options']['inserer_debut'];
782        elseif ($ou == 'fin')
783                $saisie['options']['inserer_fin'] = $saisie['options']['inserer_fin'].$insertion;
784       
785        return $saisie;
786}
787
788/*
789 * Liste toutes les saisies configurables (ayant une description)
790 *
791 * @return array Un tableau listant des saisies et leurs options
792 */
793function saisies_lister_disponibles(){
794        static $saisies = null;
795       
796        if (is_null($saisies)){
797                $saisies = array();
798                $liste = find_all_in_path('saisies/', '.+[.]yaml$');
799               
800                if (count($liste)){
801                        foreach ($liste as $fichier=>$chemin){
802                                $type_saisie = preg_replace(',[.]yaml$,i', '', $fichier);
803                                $dossier = str_replace($fichier, '', $chemin);
804                                // On ne garde que les saisies qui ont bien le HTML avec !
805                                if (file_exists("$dossier$type_saisie.html")
806                                        and (
807                                                is_array($saisie = saisies_charger_infos($type_saisie))
808                                        )
809                                ){
810                                        $saisies[$type_saisie] = $saisie;
811                                }
812                        }
813                }
814        }
815       
816        return $saisies;
817}
818
819/**
820 * Charger les informations contenues dans le yaml d'une saisie
821 *
822 * @param string $type_saisie Le type de la saisie
823 * @return array Un tableau contenant le YAML décodé
824 */
825function saisies_charger_infos($type_saisie){
826        include_spip('inc/yaml');
827        $fichier = find_in_path("saisies/$type_saisie.yaml");
828        $saisie = yaml_decode_file($fichier);
829        if (is_array($saisie)){
830                $saisie['titre'] = $saisie['titre'] ? _T_ou_typo($saisie['titre']) : $type_saisie;
831                $saisie['description'] = $saisie['description'] ? _T_ou_typo($saisie['description']) : '';
832                $saisie['icone'] = $saisie['icone'] ? find_in_path($saisie['icone']) : '';
833        }
834        return $saisie;
835}
836
837/*
838 * Quelles sont les saisies qui se débrouillent toutes seules, sans le _base commun
839 *
840 * @return array Retourne un tableau contenant les types de saisies qui ne doivent pas utiliser le _base.html commun
841 */
842function saisies_autonomes(){
843        $saisies_autonomes = pipeline(
844                'saisies_autonomes',
845                array(
846                        'fieldset',
847                        'hidden',
848                        'destinataires', 
849                        'explication'
850                )
851        );
852       
853        return $saisies_autonomes;
854}
855
856/*
857 * Transforme une chaine en tableau avec comme principe :
858 * - une ligne devient une case
859 * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur
860 *
861 * @param string $chaine Une chaine à transformer
862 * @return array Retourne un tableau PHP
863 */
864function saisies_chaine2tableau($chaine, $separateur="\n"){
865        if ($chaine and is_string($chaine)){
866                $tableau = array();
867                // On découpe d'abord en lignes
868                $lignes = explode($separateur, $chaine);
869                foreach ($lignes as $i=>$ligne){
870                        $ligne = trim(trim($ligne), '|');
871                        // Si ce n'est pas une ligne sans rien
872                        if ($ligne !== ''){
873                                // Si on trouve un découpage dans la ligne on fait cle|valeur
874                                if (strpos($ligne, '|') !== false){
875                                        list($cle,$valeur) = explode('|', $ligne, 2);
876                                        $tableau[$cle] = $valeur;
877                                }
878                                // Sinon on génère la clé
879                                else{
880                                        $tableau[$i] = $ligne;
881                                }
882                        }
883                }
884                return $tableau;
885        }
886        // Si c'est déjà un tableau on le renvoie tel quel
887        elseif (is_array($chaine)){
888                return $chaine;
889        }
890        else{
891                return array();
892        }
893}
894
895/*
896 * Transforme un tableau en chaine de caractères avec comme principe :
897 * - une case de vient une ligne de la chaine
898 * - chaque ligne est générée avec la forme cle|valeur
899 */
900function saisies_tableau2chaine($tableau){
901        if ($tableau and is_array($tableau)){
902                $chaine = '';
903       
904                foreach($tableau as $cle=>$valeur){
905                        $ligne = trim("$cle|$valeur");
906                        $chaine .= "$ligne\n";
907                }
908                $chaine = trim($chaine);
909       
910                return $chaine;
911        }
912        // Si c'est déjà une chaine on la renvoie telle quelle
913        elseif (is_string($tableau)){
914                return $tableau;
915        }
916        else{
917                return '';
918        }
919}
920
921/*
922 * Génère une page d'aide listant toutes les saisies et leurs options
923 */
924function saisies_generer_aide(){
925        // On a déjà la liste par saisie
926        $saisies = saisies_lister_disponibles();
927       
928        // On construit une liste par options
929        $options = array();
930        foreach ($saisies as $type_saisie=>$saisie){
931                $options_saisie = saisies_lister_par_nom($saisie['options'], false);
932                foreach ($options_saisie as $nom=>$option){
933                        // Si l'option n'existe pas encore
934                        if (!isset($options[$nom])){
935                                $options[$nom] = _T_ou_typo($option['options']);
936                        }
937                        // On ajoute toujours par qui c'est utilisé
938                        $options[$nom]['utilisee_par'][] = $type_saisie;
939                }
940                ksort($options_saisie);
941                $saisies[$type_saisie]['options'] = $options_saisie;
942        }
943        ksort($options);
944       
945        return recuperer_fond(
946                'inclure/saisies_aide',
947                array(
948                        'saisies' => $saisies,
949                        'options' => $options
950                )
951        );
952}
953
954/*
955 * Génère, à partir d'un tableau de saisie le code javascript ajouté à la fin de #GENERER_SAISIES
956 * pour produire un affichage conditionnel des saisies avec une option afficher_si.
957 *
958 * @param array $saisies Un tableau de saisies
959 * @param string $id_form Un identifiant unique pour le formulaire
960 * @return text
961 */
962function saisies_generer_js_afficher_si($saisies,$id_form){
963        $i = 0;
964        $saisies = saisies_lister_par_nom($saisies,true);
965        $code = '';
966        $code .= '$(document).ready(function(){';
967                $code .= 'verifier_saisies_'.$id_form.' = function(form){';
968                                foreach ($saisies as $saisie) {
969                                        if (isset($saisie['options']['afficher_si'])) {
970                                                $i++;
971                                                switch ($saisie['saisie']) {
972                                                        case 'fieldset':
973                                                                $class_li = 'fieldset_'.$saisie['options']['nom'];
974                                                                break;
975                                                        case 'explication':
976                                                                $class_li = 'explication_'.$saisie['options']['nom'];
977                                                                break;
978                                                        default:
979                                                                $class_li = 'editer_'.$saisie['options']['nom'];
980                                                }
981                                                $condition = $saisie['options']['afficher_si'];
982                                                // On gère le cas @plugin:non_plugin@
983                                                preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
984                                                foreach ($matches[1] as $plug) {
985                                                        if (defined('_DIR_PLUGIN_'.strtoupper($plug)))
986                                                                $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
987                                                        else
988                                                                $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
989                                                }
990                                                // On gère le cas @config:plugin:meta@ suivi d'un test
991                                                preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);
992                                                foreach ($matches[1] as $plugin) {
993                                                        $config = lire_config($plugin);
994                                                        $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);
995                                                }
996                                                // On transforme en une condition valide
997                                                preg_match_all('#@(.+)@#U', $condition, $matches);
998                                                foreach ($matches[1] as $nom) {
999                                                        switch($saisies[$nom]['saisie']) {
1000                                                                case 'radio':
1001                                                                case 'oui_non':
1002                                                                        $condition = preg_replace('#@'.$nom.'@#U', '$(form).find("[name=\''.$nom.'\']:checked").val()', $condition);
1003                                                                        break;
1004                                                                default:
1005                                                                        $condition = preg_replace('#@'.$nom.'@#U', '$(form).find("[name=\''.$nom.'\']").val()', $condition);
1006                                                        }
1007                                                }
1008                                                $code .= 'if ('.$condition.') {$(form).find("li.'.$class_li.'").show(400);} ';
1009                                                $code .= 'else {$(form).find(".'.$class_li.'").hide(400);} ';
1010                                        }
1011                                }
1012                $code .= '};';
1013                $code .= '$("li#afficher_si_'.$id_form.'").parents("form").each(function(){verifier_saisies_'.$id_form.'(this);});';
1014                $code .= '$("li#afficher_si_'.$id_form.'").parents("form").change(function(){verifier_saisies_'.$id_form.'(this);});';
1015        $code .= '});';
1016        return $i>0 ? $code : '';
1017}
1018
1019/*
1020 * Le tableau de saisies a-t-il une option afficher_si ?
1021 *
1022 * @param array $saisies Un tableau de saisies
1023 * @return boolean
1024 */
1025
1026function saisies_afficher_si($saisies) {
1027        $afficher_si = false;
1028        $saisies = saisies_lister_par_nom($saisies,true);
1029        foreach ($saisies as $saisie) {
1030                if (isset($saisie['options']['afficher_si']))
1031                        $afficher_si = true;
1032        }
1033        return $afficher_si;
1034}
1035
1036/*
1037 * Lorsque l'on affiche les saisies (#VOIR_SAISIES), les saisies ayant une option afficher_si
1038 * et dont les conditions ne sont pas remplies doivent être retirées du tableau de saisies
1039 *
1040 * @param array $saisies Un tableau de saisies
1041 * @param array $env Les variables d'environnement
1042 * @return array Un tableau de saisies
1043 */
1044
1045function saisies_verifier_afficher_si($saisies, $env) {
1046        // eviter une erreur par maladresse d'appel :)
1047        if (!is_array($saisies)) {
1048                return array();
1049        }
1050        foreach ($saisies as $cle => $saisie) {
1051                if (isset($saisie['options']['afficher_si'])) {
1052                        $condition = $saisie['options']['afficher_si'];
1053                        // On gère le cas @plugin:non_plugin@
1054                        preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
1055                        foreach ($matches[1] as $plug) {
1056                                if (defined('_DIR_PLUGIN_'.strtoupper($plug)))
1057                                        $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
1058                                else
1059                                        $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
1060                        }
1061                        // On transforme en une condition valide
1062                        $condition = preg_replace('#@(.+)@#U', '$env["valeurs"][\'$1\']', $condition);
1063                        eval('$ok = '.$condition.';');
1064                        if (!$ok)
1065                                unset($saisies[$cle]);
1066                }
1067        }
1068        return $saisies;
1069}
1070
1071?>
Note: See TracBrowser for help on using the repository browser.