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

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

Éviter un warning si mauvais appel de verification de saisie (Sébastien Z.)

File size: 34.3 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                $verifier = $saisie['verifier'];
440
441                // Si le nom du champ est un tableau indexé, il faut parser !
442                if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)){
443                        $valeur = _request($separe[1]);
444                        preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
445                        // On va chercher au fond du tableau
446                        foreach($index[1] as $cle){
447                                $valeur = $valeur[$cle];
448                        }
449                }
450                // Sinon la valeur est juste celle du nom
451                else
452                        $valeur = _request($champ);
453               
454                // On regarde d'abord si le champ est obligatoire
455                if ($obligatoire and $obligatoire != 'non' and (is_null($valeur) or (is_string($valeur) and trim($valeur) == '') or (is_array($valeur) and count($valeur) == 0)))
456                        $erreurs[$champ] = _T('info_obligatoire');
457               
458                // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif
459                if (!$erreurs[$champ] and is_array($verifier) and $verif_fonction){
460                        // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur
461                        if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $verifier['options']))
462                                $erreurs[$champ] = $erreur_eventuelle;
463                }
464        }
465       
466        return $erreurs;
467}
468
469/*
470 * Compare deux tableaux de saisies pour connaitre les différences
471 * @param array $saisies_anciennes Un tableau décrivant des saisies
472 * @param array $saisies_nouvelles Un autre tableau décrivant des saisies
473 * @param bool $avec_conteneur Indique si on veut prendre en compte dans la comparaison les conteneurs comme les fieldsets
474 * @return array Retourne le tableau des saisies supprimées, ajoutées et modifiées
475 */
476function saisies_comparer($saisies_anciennes, $saisies_nouvelles, $avec_conteneur=true){
477        $saisies_anciennes = saisies_lister_par_nom($saisies_anciennes, $avec_conteneur);
478        $saisies_nouvelles = saisies_lister_par_nom($saisies_nouvelles, $avec_conteneur);
479       
480        // Les saisies supprimées sont celles qui restent dans les anciennes quand on a enlevé toutes les nouvelles
481        $saisies_supprimees = array_diff_key($saisies_anciennes, $saisies_nouvelles);
482        // Les saisies ajoutées, c'est le contraire
483        $saisies_ajoutees = array_diff_key($saisies_nouvelles, $saisies_anciennes);
484        // Il reste alors les saisies qui ont le même nom
485        $saisies_restantes = array_intersect_key($saisies_anciennes, $saisies_nouvelles);
486        // Dans celles-ci, celles qui sont modifiées sont celles dont la valeurs est différentes
487        $saisies_modifiees = array_udiff($saisies_nouvelles, $saisies_restantes, 'saisies_comparer_rappel');
488        // Et enfin les saisies qui ont le même nom et la même valeur
489        $saisies_identiques = array_diff_key($saisies_restantes, $saisies_modifiees);
490       
491        return array(
492                'supprimees' => $saisies_supprimees,
493                'ajoutees' => $saisies_ajoutees,
494                'modifiees' => $saisies_modifiees,
495                'identiques' => $saisies_identiques
496        );
497}
498
499/*
500 * Compare deux saisies et indique si elles sont égales ou pas
501 */
502function saisies_comparer_rappel($a, $b){
503        if ($a === $b) return 0;
504        else return 1;
505}
506
507
508/**
509 * Retourne si une saisie peut être affichée.
510 * On s'appuie sur l'éventuelle clé "editable" du $champ.
511 * Si editable vaut :
512 *  absent : le champ est éditable
513 *  1, le champ est éditable
514 *  0, le champ n'est pas éditable
515 * -1, le champ est éditable s'il y a du contenu dans le champ (l'environnement)
516 *     ou dans un de ses enfants (fieldsets)
517 *
518 * @param $champ tableau de description de la saisie
519 * @param $env environnement transmis à la saisie, certainement l'environnement du formulaire
520 * @param $utiliser_editable false pour juste tester le cas -1
521 *
522 * @return bool la saisie est-elle éditable ?
523**/
524function saisie_editable($champ, $env, $utiliser_editable=true) {
525        if ($utiliser_editable) {
526                // si le champ n'est pas éditable, on sort.
527                if (!isset($champ['editable'])) {
528                        return true;
529                }
530                $editable = $champ['editable'];
531
532                if ($editable > 0) {
533                        return true;
534                }
535                if ($editable == 0) {
536                        return false;
537                }
538        }
539
540        // cas -1
541        // name de la saisie
542        if (isset($champ['options']['nom'])) {
543                // si on a le name dans l'environnement, on le teste
544                $nom = $champ['options']['nom'];
545                if (isset($env[$nom])) {
546                        return $env[$nom] ? true : false ;
547                }
548        }
549        // sinon, si on a des sous saisies
550        if (isset($champ['saisies']) and is_array($champ['saisies'])) {
551                foreach($champ['saisies'] as $saisie) {
552                        if (saisie_editable($saisie, $env, false)) {
553                                return true;
554                        }
555                }
556        }
557       
558        // aucun des paramètres demandés n'avait de contenu
559        return false;
560       
561}
562
563
564/*
565 * Génère une saisie à partir d'un tableau la décrivant et de l'environnement
566 * Le tableau doit être de la forme suivante :
567 * array(
568 *              'saisie' => 'input',
569 *              'options' => array(
570 *                      'nom' => 'le_name',
571 *                      'label' => 'Un titre plus joli',
572 *                      'obligatoire' => 'oui',
573 *                      'explication' => 'Remplissez ce champ en utilisant votre clavier.'
574 *              )
575 * )
576 */
577function saisies_generer_html($champ, $env=array()){
578        // Si le parametre n'est pas bon, on genere du vide
579        if (!is_array($champ))
580                return '';
581
582        // Si la saisie n'est pas editable, on sort aussi.
583        if (!saisie_editable($champ, $env)) {
584                return '';
585        }
586       
587        $contexte = array();
588       
589        // On sélectionne le type de saisie
590        $contexte['type_saisie'] = $champ['saisie'];
591       
592        // Peut-être des transformations à faire sur les options textuelles
593        $options = $champ['options'];
594
595       
596        foreach ($options as $option => $valeur){
597                $options[$option] = _T_ou_typo($valeur, 'multi');
598        }
599       
600        // On ajoute les options propres à la saisie
601        $contexte = array_merge($contexte, $options);
602       
603        // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
604        if(isset($contexte['env']) or is_array($champ['saisies'])){
605                unset($contexte['env']);
606               
607                // À partir du moment où on passe tout l'environnement, il faut enlever certains éléments qui ne doivent absolument provenir que des options
608                unset($env['inserer_debut']);
609                unset($env['inserer_fin']);
610                $saisies_disponibles = saisies_lister_disponibles();
611                if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){
612                        $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
613                        foreach ($options_a_supprimer as $option_a_supprimer){
614                                unset($env[$option_a_supprimer]);
615                        }
616                }
617               
618                $contexte = array_merge($env, $contexte);
619        }
620        // Sinon on ne sélectionne que quelques éléments importants
621        else{
622                // On récupère la liste des erreurs
623                $contexte['erreurs'] = $env['erreurs'];
624        }
625       
626        // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
627        // Si le nom du champ est un tableau indexé, il faut parser !
628        if (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){
629                $contexte['valeur'] = $env[$separe[1]];
630                preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
631                // On va chercher au fond du tableau
632                foreach($index[1] as $cle){
633                        $contexte['valeur'] = $contexte['valeur'][$cle];
634                }
635        }
636        // Sinon la valeur est juste celle du nom
637        else
638                $contexte['valeur'] = $env[$contexte['nom']];
639       
640        // Si ya des enfants on les remonte dans le contexte
641        if (is_array($champ['saisies']))
642                $contexte['saisies'] = $champ['saisies'];
643       
644        // On génère la saisie
645        return recuperer_fond(
646                'saisies/_base',
647                $contexte
648        );
649}
650
651/*
652 * Génère une vue d'une saisie
653 *
654 * @param array $saisie Un tableau décrivant une saisie
655 * @param array $env L'environnement, contenant normalement la réponse à la saisie
656 * @param array $env_obligatoire
657 * @return string Retour le HTML des vues
658 */
659function saisies_generer_vue($saisie, $env=array(), $env_obligatoire=array()){
660        // Si le paramètre n'est pas bon, on génère du vide
661        if (!is_array($saisie))
662                return '';
663       
664        $contexte = array();
665       
666        // On sélectionne le type de saisie
667        $contexte['type_saisie'] = $saisie['saisie'];
668       
669        // Peut-être des transformations à faire sur les options textuelles
670        $options = $saisie['options'];
671        foreach ($options as $option => $valeur){
672                $options[$option] = _T_ou_typo($valeur, 'multi');
673        }
674       
675        // On ajoute les options propres à la saisie
676        $contexte = array_merge($contexte, $options);
677       
678        // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement
679        if(isset($contexte['env']) or is_array($saisie['saisies'])){
680                unset($contexte['env']);
681               
682                // À partir du moment où on passe tout l'environnement, il faut enlever
683                // certains éléments qui ne doivent absolument provenir que des options
684                $saisies_disponibles = saisies_lister_disponibles();
685                if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){
686                        $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);
687                        foreach ($options_a_supprimer as $option_a_supprimer){
688                                unset($env[$option_a_supprimer]);
689                        }
690                }
691               
692                $contexte = array_merge($env, $contexte);
693        }
694       
695        // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ
696       
697        // On regarde en priorité s'il y a un tableau listant toutes les valeurs
698        if ($env['valeurs'] and is_array($env['valeurs']) and isset($env['valeurs'][$contexte['nom']])){
699                $contexte['valeur'] = $env['valeurs'][$contexte['nom']];
700        }
701        // Si le nom du champ est un tableau indexé, il faut parser !
702        elseif (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){
703                $contexte['valeur'] = $env[$separe[1]];
704                preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
705                // On va chercher au fond du tableau
706                foreach($index[1] as $cle){
707                        $contexte['valeur'] = $contexte['valeur'][$cle];
708                }
709        }
710        // Sinon la valeur est juste celle du nom
711        else
712                $contexte['valeur'] = $env[$contexte['nom']];
713       
714        // Si ya des enfants on les remonte dans le contexte
715        if (is_array($saisie['saisies']))
716                $contexte['saisies'] = $saisie['saisies'];
717
718        if (is_array($env_obligatoire)) {
719                $contexte = array_merge($contexte, $env_obligatoire);
720        }
721        // On génère la saisie
722        return recuperer_fond(
723                'saisies-vues/_base',
724                $contexte
725        );
726}
727
728/*
729 * Génère un nom unique pour un champ d'un formulaire donné
730 *
731 * @param array $formulaire Le formulaire à analyser
732 * @param string $type_saisie Le type de champ dont on veut un identifiant
733 * @return string Un nom unique par rapport aux autres champs du formulaire
734 */
735function saisies_generer_nom($formulaire, $type_saisie){
736        $champs = saisies_lister_champs($formulaire);
737       
738        // Tant que type_numero existe, on incrémente le compteur
739        $compteur = 1;
740        while (array_search($type_saisie.'_'.$compteur, $champs) !== false)
741                $compteur++;
742       
743        // On a alors un compteur unique pour ce formulaire
744        return $type_saisie.'_'.$compteur;
745}
746
747/**
748 * Insère du HTML au début ou à la fin d'une saisie
749 *
750 * @param array $saisie La description d'une seule saisie
751 * @param string $insertion Du code HTML à insérer dans la saisie
752 * @param string $ou L'endroit où insérer le HTML : "debut" ou "fin"
753 * @return array Retourne la description de la saisie modifiée
754 */
755function saisies_inserer_html($saisie, $insertion, $ou='fin'){
756        if (!in_array($ou, array('debut', 'fin')))
757                $ou = 'fin';
758       
759        if ($ou == 'debut')
760                $saisie['options']['inserer_debut'] = $insertion.$saisie['options']['inserer_debut'];
761        elseif ($ou == 'fin')
762                $saisie['options']['inserer_fin'] = $saisie['options']['inserer_fin'].$insertion;
763       
764        return $saisie;
765}
766
767/*
768 * Liste toutes les saisies configurables (ayant une description)
769 *
770 * @return array Un tableau listant des saisies et leurs options
771 */
772function saisies_lister_disponibles(){
773        static $saisies = null;
774       
775        if (is_null($saisies)){
776                $saisies = array();
777                $liste = find_all_in_path('saisies/', '.+[.]yaml$');
778               
779                if (count($liste)){
780                        foreach ($liste as $fichier=>$chemin){
781                                $type_saisie = preg_replace(',[.]yaml$,i', '', $fichier);
782                                $dossier = str_replace($fichier, '', $chemin);
783                                // On ne garde que les saisies qui ont bien le HTML avec !
784                                if (file_exists("$dossier$type_saisie.html")
785                                        and (
786                                                is_array($saisie = saisies_charger_infos($type_saisie))
787                                        )
788                                ){
789                                        $saisies[$type_saisie] = $saisie;
790                                }
791                        }
792                }
793        }
794       
795        return $saisies;
796}
797
798/**
799 * Charger les informations contenues dans le yaml d'une saisie
800 *
801 * @param string $type_saisie Le type de la saisie
802 * @return array Un tableau contenant le YAML décodé
803 */
804function saisies_charger_infos($type_saisie){
805        include_spip('inc/yaml');
806        $fichier = find_in_path("saisies/$type_saisie.yaml");
807        $saisie = yaml_decode_file($fichier);
808        if (is_array($saisie)){
809                $saisie['titre'] = $saisie['titre'] ? _T_ou_typo($saisie['titre']) : $type_saisie;
810                $saisie['description'] = $saisie['description'] ? _T_ou_typo($saisie['description']) : '';
811                $saisie['icone'] = $saisie['icone'] ? find_in_path($saisie['icone']) : '';
812        }
813        return $saisie;
814}
815
816/*
817 * Quelles sont les saisies qui se débrouillent toutes seules, sans le _base commun
818 *
819 * @return array Retourne un tableau contenant les types de saisies qui ne doivent pas utiliser le _base.html commun
820 */
821function saisies_autonomes(){
822        $saisies_autonomes = pipeline(
823                'saisies_autonomes',
824                array(
825                        'fieldset',
826                        'hidden',
827                        'destinataires', 
828                        'explication'
829                )
830        );
831       
832        return $saisies_autonomes;
833}
834
835/*
836 * Transforme une chaine en tableau avec comme principe :
837 * - une ligne devient une case
838 * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur
839 *
840 * @param string $chaine Une chaine à transformer
841 * @return array Retourne un tableau PHP
842 */
843function saisies_chaine2tableau($chaine, $separateur="\n"){
844        if ($chaine and is_string($chaine)){
845                $tableau = array();
846                // On découpe d'abord en lignes
847                $lignes = explode($separateur, $chaine);
848                foreach ($lignes as $i=>$ligne){
849                        $ligne = trim(trim($ligne), '|');
850                        // Si ce n'est pas une ligne sans rien
851                        if ($ligne !== ''){
852                                // Si on trouve un découpage dans la ligne on fait cle|valeur
853                                if (strpos($ligne, '|') !== false){
854                                        list($cle,$valeur) = explode('|', $ligne, 2);
855                                        $tableau[$cle] = $valeur;
856                                }
857                                // Sinon on génère la clé
858                                else{
859                                        $tableau[$i] = $ligne;
860                                }
861                        }
862                }
863                return $tableau;
864        }
865        // Si c'est déjà un tableau on le renvoie tel quel
866        elseif (is_array($chaine)){
867                return $chaine;
868        }
869        else{
870                return array();
871        }
872}
873
874/*
875 * Transforme un tableau en chaine de caractères avec comme principe :
876 * - une case de vient une ligne de la chaine
877 * - chaque ligne est générée avec la forme cle|valeur
878 */
879function saisies_tableau2chaine($tableau){
880        if ($tableau and is_array($tableau)){
881                $chaine = '';
882       
883                foreach($tableau as $cle=>$valeur){
884                        $ligne = trim("$cle|$valeur");
885                        $chaine .= "$ligne\n";
886                }
887                $chaine = trim($chaine);
888       
889                return $chaine;
890        }
891        // Si c'est déjà une chaine on la renvoie telle quelle
892        elseif (is_string($tableau)){
893                return $tableau;
894        }
895        else{
896                return '';
897        }
898}
899
900/*
901 * Génère une page d'aide listant toutes les saisies et leurs options
902 */
903function saisies_generer_aide(){
904        // On a déjà la liste par saisie
905        $saisies = saisies_lister_disponibles();
906       
907        // On construit une liste par options
908        $options = array();
909        foreach ($saisies as $type_saisie=>$saisie){
910                $options_saisie = saisies_lister_par_nom($saisie['options'], false);
911                foreach ($options_saisie as $nom=>$option){
912                        // Si l'option n'existe pas encore
913                        if (!isset($options[$nom])){
914                                $options[$nom] = _T_ou_typo($option['options']);
915                        }
916                        // On ajoute toujours par qui c'est utilisé
917                        $options[$nom]['utilisee_par'][] = $type_saisie;
918                }
919                ksort($options_saisie);
920                $saisies[$type_saisie]['options'] = $options_saisie;
921        }
922        ksort($options);
923       
924        return recuperer_fond(
925                'inclure/saisies_aide',
926                array(
927                        'saisies' => $saisies,
928                        'options' => $options
929                )
930        );
931}
932
933/*
934 * Génère, à partir d'un tableau de saisie le code javascript ajouté à la fin de #GENERER_SAISIES
935 * pour produire un affichage conditionnel des saisies avec une option afficher_si.
936 *
937 * @param array $saisies Un tableau de saisies
938 * @param string $id_form Un identifiant unique pour le formulaire
939 * @return text
940 */
941function saisies_generer_js_afficher_si($saisies,$id_form){
942        $i = 0;
943        $saisies = saisies_lister_par_nom($saisies,true);
944        $code = '';
945        $code .= '$(document).ready(function(){';
946                $code .= 'verifier_saisies_'.$id_form.' = function(form){';
947                                foreach ($saisies as $saisie) {
948                                        if (isset($saisie['options']['afficher_si'])) {
949                                                $i++;
950                                                switch ($saisie['saisie']) {
951                                                        case 'fieldset':
952                                                                $class_li = 'fieldset_'.$saisie['options']['nom'];
953                                                                break;
954                                                        case 'explication':
955                                                                $class_li = 'explication_'.$saisie['options']['nom'];
956                                                                break;
957                                                        default:
958                                                                $class_li = 'editer_'.$saisie['options']['nom'];
959                                                }
960                                                $condition = $saisie['options']['afficher_si'];
961                                                // On gère le cas @plugin:non_plugin@
962                                                preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
963                                                foreach ($matches[1] as $plug) {
964                                                        if (defined('_DIR_PLUGIN_'.strtoupper($plug)))
965                                                                $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
966                                                        else
967                                                                $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
968                                                }
969                                                // On gère le cas @config:plugin:meta@ suivi d'un test
970                                                preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);
971                                                foreach ($matches[1] as $plugin) {
972                                                        $config = lire_config($plugin);
973                                                        $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);
974                                                }
975                                                // On transforme en une condition valide
976                                                preg_match_all('#@(.+)@#U', $condition, $matches);
977                                                foreach ($matches[1] as $nom) {
978                                                        switch($saisies[$nom]['saisie']) {
979                                                                case 'radio':
980                                                                case 'oui_non':
981                                                                        $condition = preg_replace('#@'.$nom.'@#U', '$(form).find("[name=\''.$nom.'\']:checked").val()', $condition);
982                                                                        break;
983                                                                default:
984                                                                        $condition = preg_replace('#@'.$nom.'@#U', '$(form).find("[name=\''.$nom.'\']").val()', $condition);
985                                                        }
986                                                }
987                                                $code .= 'if ('.$condition.') {$(form).find("li.'.$class_li.'").show(400);} ';
988                                                $code .= 'else {$(form).find(".'.$class_li.'").hide(400);} ';
989                                        }
990                                }
991                $code .= '};';
992                $code .= '$("li#afficher_si_'.$id_form.'").parents("form").each(function(){verifier_saisies_'.$id_form.'(this);});';
993                $code .= '$("li#afficher_si_'.$id_form.'").parents("form").change(function(){verifier_saisies_'.$id_form.'(this);});';
994        $code .= '});';
995        return $i>0 ? $code : '';
996}
997
998/*
999 * Le tableau de saisies a-t-il une option afficher_si ?
1000 *
1001 * @param array $saisies Un tableau de saisies
1002 * @return boolean
1003 */
1004
1005function saisies_afficher_si($saisies) {
1006        $afficher_si = false;
1007        $saisies = saisies_lister_par_nom($saisies,true);
1008        foreach ($saisies as $saisie) {
1009                if (isset($saisie['options']['afficher_si']))
1010                        $afficher_si = true;
1011        }
1012        return $afficher_si;
1013}
1014
1015/*
1016 * Lorsque l'on affiche les saisies (#VOIR_SAISIES), les saisies ayant une option afficher_si
1017 * et dont les conditions ne sont pas remplies doivent être retirées du tableau de saisies
1018 *
1019 * @param array $saisies Un tableau de saisies
1020 * @param array $env Les variables d'environnement
1021 * @return array Un tableau de saisies
1022 */
1023
1024function saisies_verifier_afficher_si($saisies, $env) {
1025        // eviter une erreur par maladresse d'appel :)
1026        if (!is_array($saisies)) {
1027                return array();
1028        }
1029        foreach ($saisies as $cle => $saisie) {
1030                if (isset($saisie['options']['afficher_si'])) {
1031                        $condition = $saisie['options']['afficher_si'];
1032                        // On gère le cas @plugin:non_plugin@
1033                        preg_match_all('#@plugin:(.+)@#U', $condition, $matches);
1034                        foreach ($matches[1] as $plug) {
1035                                if (defined('_DIR_PLUGIN_'.strtoupper($plug)))
1036                                        $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);
1037                                else
1038                                        $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);
1039                        }
1040                        // On transforme en une condition valide
1041                        $condition = preg_replace('#@(.+)@#U', '$env["valeurs"][\'$1\']', $condition);
1042                        eval('$ok = '.$condition.';');
1043                        if (!$ok)
1044                                unset($saisies[$cle]);
1045                }
1046        }
1047        return $saisies;
1048}
1049
1050?>
Note: See TracBrowser for help on using the repository browser.