source: spip-zone/_plugins_/champs_extras_core/trunk/cextras_pipelines.php @ 115804

Last change on this file since 115804 was 115804, checked in by bruno@…, 19 months ago

version 3.12.0 : ne pas bloquer sur les champs obligatoires masqués par afficher_si

Dans cextras_formulaire_verifier() utiliser saisies_verifier_afficher_si() qui permet d'exclure de la verification les champs masqués.

Le bug était signalé sur contrib https://contrib.spip.net/Champs-Extras-3#comment498169 avec une desciption complète.

File size: 16.8 KB
Line 
1<?php
2
3/**
4 * Utilisations de pipelines
5 *
6 * @package SPIP\Cextras\Pipelines
7**/
8
9// sécurité
10if (!defined("_ECRIRE_INC_VERSION")) return;
11
12/**
13 * Retourne la liste des saisies de champs extras concernant un objet donné
14 *
15 * @pipeline_appel declarer_champs_extras
16 * @param string $table
17 *     Nom d'une table SQL éditoriale
18 * @return array
19 *     Liste des saisies de champs extras de l'objet
20**/
21function champs_extras_objet($table) {
22        static $saisies_tables = array();
23        if (!$saisies_tables) {
24                include_spip('public/interfaces');
25                $saisies_tables = pipeline('declarer_champs_extras', array());
26        }
27        return isset($saisies_tables[$table]) ? $saisies_tables[$table] : array();
28}
29
30/**
31 * Filtrer par autorisation les saisies transmises
32 *
33 * Chacune des saisies est parcourue et si le visiteur n'a pas l'autorisation
34 * de la voir, elle est enlevée de la liste.
35 * La fonction ne retourne donc que la liste des saisies que peut voir
36 * la personne.
37 *
38 * @param string $faire
39 *     Type d'autorisation testée : 'voir', 'modifier'
40 * @param string $quoi
41 *     Type d'objet tel que 'article'
42 * @param array $saisies
43 *     Liste des saisies à filtrer
44 * @param array $args
45 *     Arguments pouvant être utiles à l'autorisation
46 * @return array
47 *     Liste des saisies filtrées
48**/
49function champs_extras_autorisation($faire, $quoi='', $saisies=array(), $args=array()) {
50        if (!$saisies) return array();
51        include_spip('inc/autoriser');
52
53        foreach ($saisies as $cle => $saisie) {
54                $id = isset($args['id']) ? $args['id'] : $args['id_objet'];
55                if (!autoriser($faire . 'extra', $quoi, $id, '', array(
56                        'type' => $quoi,
57                        'id_objet' => $id,
58                        'contexte' => isset($args['contexte']) ? $args['contexte'] : array(),
59                        'table' => table_objet_sql($quoi),
60                        'saisie' => $saisie,
61                        'champ' => $saisie['options']['nom'],
62                ))) {
63                        // on n'est pas autorise
64                        unset($saisies[$cle]);
65                }
66                else
67                {
68                        // on est autorise
69                        // on teste les sous-elements
70                        if (!empty($saisie['saisies'])) {
71                                $saisies[$cle]['saisies'] = champs_extras_autorisation($faire, $quoi, $saisie['saisies'], $args);
72                        }
73                }
74        }
75        return $saisies;
76}
77
78/**
79 * Ajoute pour chaque saisie de type SQL un drapeau (input hidden)
80 * permettant de retrouver les saisies editées.
81 *
82 * Particulièrement utile pour les checkbox qui ne renvoient
83 * rien si on les décoche.
84 *
85 * @param array $saisies
86 *     Liste de saisies
87 * @return array $saisies
88 *     Saisies complétées des drapeaux d'édition
89**/
90function champs_extras_ajouter_drapeau_edition($saisies) {
91        $saisies_sql = champs_extras_saisies_lister_avec_sql($saisies);
92        foreach ($saisies_sql as $saisie) {
93                $nom = $saisie['options']['nom'];
94                $saisies[] = array(
95                        'saisie' => 'hidden',
96                        'options' => array(
97                                'nom' => "cextra_$nom",
98                                'defaut' => 1 
99                        )
100                );
101        }
102        return $saisies;
103}
104
105// ---------- pipelines -----------
106
107
108/**
109 * Ajouter les champs extras sur les formulaires CVT editer_xx
110 *
111 * Liste les champs extras de l'objet, et s'il y en a les ajoute
112 * sur le formulaire d'édition en ayant filtré uniquement les saisies
113 * que peut voir le visiteur et en ayant ajouté des champs hidden
114 * servant à champs extras.
115 *
116 * @pipeline editer_contenu_objet
117 * @param array $flux Données du pipeline
118 * @return array      Données du pipeline
119**/ 
120function cextras_editer_contenu_objet($flux){
121        // recuperer les saisies de l'objet en cours
122        $objet = $flux['args']['type'];
123        include_spip('inc/cextras');
124        if ($saisies = champs_extras_objet( table_objet_sql($objet) )) {
125                // filtrer simplement les saisies que la personne en cours peut voir
126                $saisies = champs_extras_autorisation('modifier', $objet, $saisies, $flux['args']);
127                // pour chaque saisie presente, de type champs extras (hors fieldset et autres)
128                // ajouter un flag d'edition
129                $saisies = champs_extras_ajouter_drapeau_edition($saisies);
130                // ajouter au formulaire
131                $ajout = recuperer_fond('inclure/generer_saisies', array_merge($flux['args']['contexte'], array('saisies'=>$saisies)));
132
133                // div par défaut en 3.1+, mais avant ul / li
134                $balise = saisie_balise_structure_formulaire('ul');
135                $flux['data'] = preg_replace(
136                        '%(<!--extra-->)%is',
137                        "<$balise class='editer-groupe champs_extras'>$ajout</$balise>\n" . '$1',
138                        $flux['data']
139                );
140        }
141
142        return $flux;
143}
144
145
146/**
147 * Ajouter les champs extras soumis par les formulaire CVT editer_xx
148 *
149 * Pour chaque champs extras envoyé par le formulaire d'édition,
150 * ajoute les valeurs dans l'enregistrement à effectuer.
151 *
152 * @pipeline pre_edition
153 * @param array $flux Données du pipeline
154 * @return array      Données du pipeline
155**/ 
156function cextras_pre_edition($flux){
157        include_spip('inc/cextras');
158        include_spip('inc/saisies_lister');
159        if (
160                $flux['args']['action'] == 'modifier'
161                and $table = $flux['args']['table']
162                and $saisies = champs_extras_objet($table)
163        ) {
164                // Restreindre les champs postés en fonction des autorisations de les modifier
165                // au cas où un malin voudrait en envoyer plus que le formulaire ne demande
166                $saisies = champs_extras_autorisation('modifier', objet_type($table), $saisies, $flux['args']);
167                $saisies = champs_extras_saisies_lister_avec_sql($saisies);
168                foreach ($saisies as $saisie) {
169                        $nom = $saisie['options']['nom'];
170                        if (_request('cextra_' .  $nom)) {
171                                $extra = _request($nom);
172                                if (is_array($extra)) {
173                                        $extra = join(',' , $extra);
174                                }
175                                $flux['data'][$nom] = corriger_caracteres($extra);
176                        }
177                }
178        }
179
180        return $flux;
181}
182
183
184/**
185 * Ajouter les champs extras sur la visualisation de l'objet
186 *
187 * S'il y a des champs extras sur l'objet, la fonction les ajoute
188 * à la vue de l'objet, en enlevant les saisies que la personne n'a
189 * pas l'autorisation de voir.
190 *
191 * @pipeline afficher_contenu_objet
192 * @param array $flux Données du pipeline
193 * @return array      Données du pipeline
194**/ 
195function cextras_afficher_contenu_objet($flux){
196        // recuperer les saisies de l'objet en cours
197        $objet = $flux['args']['type'];
198        include_spip('cextras_fonctions');
199        $contexte = isset($flux['args']['contexte']) ? $flux['args']['contexte'] : array();
200        if ($html = champs_extras_voir_saisies($objet, $flux['args']['id_objet'], $contexte)) {
201                $flux['data'] .= $html;
202        }
203        return $flux;
204}
205
206/**
207 * Pour les saisies transmises, appliquer les traitements sur leurs contenus
208 *
209 * On applique les eventuels traitements definis pour chaque saisie,
210 * dans l'option 'traitements'. Si la valeur de l'option correspond
211 * à une constante connue (tel que `_TRAITEMENTS_RACCOURCIS`), ce
212 * sera la valeur de la constante qui sera utilisée, sinon
213 * directement le texte écrit. Il faut absolument `%s` pour que cela fonctionne.
214 *
215 * @note
216 *     La `saisies-vues/_base` applique le filtre `|propre` par défaut si
217 *     elle ne trouve pas de saisie. Dans ce cas, certains traitements peuvent
218 *     être effectués 2 fois !
219 *
220 * @param array $saisies
221 *      Liste décrivant les saisies
222 * @param array $valeurs
223 *      Couples (champ => valeur)
224 * @return array
225 *      Couples (champ => valeur traitée, le cas échéant)
226 */
227function cextras_appliquer_traitements_saisies($saisies, $valeurs) {
228        $saisies = saisies_lister_avec_traitements($saisies);
229
230        // Fournir $connect et $Pile[0] au traitement si besoin (l'evil eval)
231        $connect = '';
232        $Pile = array(0 => (isset($flux['args']['contexte']) ? $flux['args']['contexte'] : array()));
233
234        foreach ($saisies as $saisie) {
235                $traitement = $saisie['options']['traitements'];
236                $traitement = defined($traitement) ? constant($traitement) : $traitement;
237                $nom = $saisie['options']['nom'];
238                list($avant, $apres) = explode('%s', $traitement);
239                eval('$val = ' . $avant . ' $valeurs[$nom] ' . $apres . ';');
240                $valeurs[$nom] = $val;
241        }
242
243        return $valeurs;
244}
245
246/**
247 * Vérification de la validité des champs extras
248 *
249 * Lorsqu'un formulaire 'editer_xx' se présente, la fonction effectue,
250 * pour chaque champs extra les vérifications prévues dans la
251 * définition de la saisie, et retourne les éventuelles erreurs rencontrées.
252 *
253 * @pipeline formulaire_verifier
254 * @param array $flux Données du pipeline
255 * @return array      Données du pipeline
256**/ 
257function cextras_formulaire_verifier($flux){
258        $form = $flux['args']['form'];
259       
260        if (strncmp($form, 'editer_', 7) !== 0) {
261                return $flux;
262        }
263       
264        $objet = substr($form, 7);
265        if ($saisies = champs_extras_objet( $table = table_objet_sql($objet) )) {
266                include_spip('inc/autoriser');
267                include_spip('inc/saisies');
268
269                // restreindre les saisies selon les autorisations
270                $id_objet = $flux['args']['args'][0]; // ? vraiment toujours ?
271                $saisies = champs_extras_autorisation('modifier', $objet, $saisies, array_merge($flux['args'], array(
272                        'id' => $id_objet,
273                        'contexte' => array()))); // nous ne connaissons pas le contexte dans ce pipeline
274
275                // restreindre les vérifications aux saisies enregistrables
276                $saisies = champs_extras_saisies_lister_avec_sql($saisies);
277
278                // ne pas traiter les saisies obligatoires masquées par afficher_si
279                include_spip('inc/saisies_afficher_si');
280                $saisies = saisies_verifier_afficher_si($saisies);
281
282                foreach ($saisies as $saisie) {
283                        $nom = $saisie['options']['nom'];
284                        $normaliser = null;
285                        $erreur = cextras_verifier_saisie($saisie, _request($nom), $normaliser);
286                        if ($erreur) {
287                                $flux['data'][$nom] = $erreur;
288                        } elseif (!is_null($normaliser)) {
289                                set_request($nom, $normaliser);
290                        }
291                }
292        }
293        return $flux;
294}
295
296/**
297 * Vérifie qu'une valeur est acceptée par la déclaration de saisie transmise.
298 *
299 * Peut aussi normaliser (la formater d'une certaine manière pour le format attendu
300 * dans la base de donnée). Dans ce cas la valeur normalisée est placée dans `$normaliser`
301 *
302 * @param array $saisie
303 * @param mixed $valeur
304 * @param mixed $normaliser Valeur normalisée, le cas échéant
305 * @param bool $depuis_crayons true si en provenance d'une vérification par Crayons.
306 * @return false|string Message d'erreur, le cas echéant.
307 */
308function cextras_verifier_saisie($saisie, $valeur, &$normaliser = null, $depuis_crayons = false) {
309        static $verifier = null;
310
311        // Si le plugin verifier est présent.
312        if (is_null($verifier)) {
313                $verifier = charger_fonction('verifier', 'inc', true);
314        }
315
316        // verifier obligatoire
317        if (
318                isset($saisie['options']['obligatoire'])
319                and $saisie['options']['obligatoire']
320                and !$valeur
321        ) {
322                return _T('info_obligatoire');
323        }
324
325        // verifier (api) + normalisation
326        if (
327                $verifier
328                AND isset($saisie['verifier']['type'])
329                AND $verif = $saisie['verifier']['type']
330        ) {
331                $options = isset($saisie['verifier']['options']) ? $saisie['verifier']['options'] : array();
332                $erreur = $verifier($valeur, $verif, $options, $normaliser);
333                if ($erreur) {
334                        return $erreur;
335                }
336
337                // Si une valeur normalisée a ete transmise, c'est tout bon.
338                if (!is_null($normaliser)) {
339                        return false;
340                }
341
342                // [FIXME] exceptions connues de vérifications (pour les dates entre autres)
343                // en attendant une meilleure solution !
344                //
345                // Lorsque le champ n'est pas rempli dans le formulaire
346                // alors qu'une normalisation est demandée,
347                // verifier() sort sans indiquer d'erreur (c'est normal).
348                //
349                // Sauf que la donnée alors soumise à SQL sera une chaine vide,
350                // ce qui ne correspond pas toujours à ce qui est attendu.
351                if ((is_string($valeur) and !strlen($valeur) or (is_array($valeur) and $saisie['saisie']=='date'))
352                        and isset($options['normaliser'])
353                        and $norme = $options['normaliser']) {
354                        // Charger la fonction de normalisation théoriquement dans verifier/date
355                        // et si on en trouve une, obtenir la valeur normalisée
356                        // qui est théoriquement la valeur par défaut, puisque $valeur est vide
357                        include_spip("verifier/$verif");
358                        if ($f_normaliser = charger_fonction("${verif}_${norme}", "normaliser", true)) {
359                                $erreur = null;
360                                $normaliser = $f_normaliser($valeur, $options, $erreur);
361                                if (!is_null($erreur)) {
362                                        return $erreur;
363                                }
364                                // On suppose la normalisation OK.
365                                return false;
366                        } else {
367                                include_spip('inc/cextras');
368                                extras_log("Fonction de normalisation pour ${verif}_${norme} introuvable");
369                        }
370                }
371        }
372        return false;
373}
374
375
376/**
377 * Insertion dans le pipeline revisions_chercher_label (Plugin révisions)
378 * Trouver le bon label à afficher sur les champs dans les listes de révisions
379 *
380 * Si un champ est un champ extra, son label correspond au label défini du champs extra
381 *
382 * @pipeline revisions_chercher_label
383 * @param array $flux Données du pipeline
384 * @return array      Données du pipeline
385**/
386function cextras_revisions_chercher_label($flux) {
387        $table = table_objet_sql($flux['args']['objet']);
388        $saisies_tables = champs_extras_objet($table);
389        foreach($saisies_tables as $champ){
390                if($champ['options']['nom'] == $flux['args']['champ']){
391                        $flux['data'] = $champ['options']['label'];
392                        break;
393                }
394        }
395        return $flux;
396}
397
398
399/**
400 * Ajouter les saisies de champs extras sur des formulaires spécifiques
401 *
402 * Les champs extras s'ajoutent déjà automatiquement sur les formulaires d'édition
403 * des objets éditoriaux. Pour d'autres formulaires plus spécifiques, tel
404 * que des formulaires d'inscriptions, il est possible d'envoyer,
405 * dans la partie 'charger' du formulaire en question la clé
406 * `_champs_extras_saisies`, listant les saisies à afficher dedans.
407 *
408 * Elles seront ajoutées automatiquement à l'endroit où le code
409 * html `<!--extra-->` est présent dans le formulaire.
410 *
411 * @see cextras_obtenir_saisies_champs_extras() qui aide à récupérer les saisies.
412 *
413 * @pipeline formulaire_fond
414 * @param array $flux
415 * @return array
416**/
417function cextras_formulaire_fond($flux) {
418        if (!empty($flux['args']['contexte']['_champs_extras_saisies'])) {
419                $saisies = $flux['args']['contexte']['_champs_extras_saisies'];
420
421                // ajouter au formulaire
422                $ajout = recuperer_fond('inclure/generer_saisies', array_merge($flux['args']['contexte'], array('saisies' => $saisies)));
423
424                // div par défaut en 3.1+, mais avant ul / li
425                $balise = saisie_balise_structure_formulaire('ul');
426                $flux['data'] = preg_replace(
427                        '%(<!--extra-->)%is',
428                        "<$balise class='editer-groupe champs_extras'>$ajout</$balise>\n" . '$1',
429                        $flux['data']
430                );
431        }
432        return $flux;
433}
434
435
436/**
437 * Définir une fonction de contrôleur pour Crayons si on tente d'éditer un champs extras.
438 *
439 * Si on édite un champs extras avec Crayons, sans avoir créé manuellement de contrôleur spécifique
440 * pour le champ en question, Crayons propose soit un textarea, soit un input.
441 *
442 * Vu que l'on connaît les déclarations de nos champs extras, on va les utiliser pour créer
443 * un formulaire d'édition plus adapté à notre champ.
444 *
445 * @pipeline crayons_controleur
446 * @param array $flux
447 * @return array
448 */
449function cextras_crayons_controleur($flux) {
450        // si Crayons a déjà trouvé de contrôleur PHP, on ne fait rien
451        if ($flux['data'] != 'controleur_dist') {
452                return $flux;
453        }
454
455        $type = $flux['args']['type'];
456        $champ = $flux['args']['champ'];
457
458        // controleur_dist teste aussi la présence des controleurs html…
459        if (find_in_path(($controleur = 'controleurs/' . $type . '_' . $champ) . '.html')) {
460                return $flux;
461        }
462        if (find_in_path(($controleur = 'controleurs/' . $champ) .'.html')) {
463                return $flux;
464        }
465
466        $id = $flux['args']['id'];
467        $table = table_objet_sql($type);
468
469        include_spip('inc/cextras');
470        // Il n'existe pas de controleur spécifique pour ce champ. Voyons si ce champ est un champs extra
471        $saisies = champs_extras_objet($table);
472        // Restreindre aux vrais champs en bdd
473        $saisies_sql = champs_extras_saisies_lister_avec_sql($saisies);
474        if (!empty($saisies_sql[$champ])) {
475                $flux['data'] = charger_fonction('champs_extras', 'controleurs');
476        } else {
477                // Ou un fieldset de champs extras
478                $saisies_fieldset = saisies_lister_avec_type($saisies, 'fieldset');
479                if (!empty($saisies_fieldset[$champ])) {
480                        $flux['data'] = charger_fonction('champs_extras_fieldset', 'controleurs');
481                }
482        }
483
484        return $flux;
485}
486
487/**
488 * Vérifier une saisie envoyée depuis un formulaire de Crayons.
489 *
490 * @pipeline crayons_verifier
491 * @param array $flux
492 * @return array
493 */
494function cextras_crayons_verifier($flux) {
495        // Le nom du modèle envoyé par le controleur/champs_extras.
496        if ($flux['args']['modele'] != 'champs_extras') {
497                return $flux;
498        }
499
500        $type = $flux['args']['type'];
501        $table = table_objet_sql($type);
502        $valeurs = $flux['args']['content'];
503
504        // Récupérer les saisies SQL de la table
505        $saisies = champs_extras_objet($table);
506        $saisies = champs_extras_saisies_lister_avec_sql($saisies);
507
508        foreach ($valeurs as $champ => $valeur) {
509                if ($saisie = saisies_chercher($saisies, $champ)) {
510                        $nom = $saisie['options']['nom'];
511
512                        // Crayons applatit les name envoyés sous forme de tableau (lorsque name="truc[]").
513                        // On récupère les véritables valeurs dans ce cas. Autrement la saisie 'date'
514                        // n'arrive pas à retrouver ses petits
515                        $key = 'content_' . $flux['args']['wid'] . '_' . $champ;
516                        $valeur = _request($key);
517
518                        $normaliser = null;
519                        $erreur = cextras_verifier_saisie($saisie, $valeur, $normaliser, true);
520                        if ($erreur) {
521                                $flux['data']['erreurs'][$nom] = $erreur;
522                        } elseif (!is_null($normaliser)) {
523                                $flux['data']['normaliser'][$nom] = $normaliser;
524                        }
525                }
526        }
527
528        return $flux;
529}
Note: See TracBrowser for help on using the repository browser.