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

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

Ajout d'une fonction et méthode utile pour ajouter des champs extras sur des formulaires
spécifiques qui éditent aussi des objets éditoriaux, mais qui ne sont pas les formulaires
d'édition par défaut. Par exemple pour des formulaires d'inscription, ou des formulaires d'édition de profils d'auteur.

Cette fonction cextras_obtenir_saisies_champs_extras($objet, $options) retourne la liste des saisies
acceptées en modification par le visiteur en cours. Des options peuvent filtrer plus ou moins finement cette liste :

  • id_auteur : indique un auteur spécifique pour les tests d'autorisation (défaut : l'auteur en session)
  • autoriser : 'modifier' (par défaut) ou 'voir', qui correspond à exécuter l'autorisation qu'à l'auteur de modifier le champ. S'il n'a pas le droit, le champ ne sera pas retourné
  • whitelist : si renseigné, liste de noms de champs acceptés (les autres ne seront pas affichés)
  • blacklist : si renseigné, liste de noms de champs ignorés (ne seront pas affichés)

Les autorisations s'appliquent sur les champs qui restent après whitelist et blacklist.

Cette liste de saisies peut alors être injectées dans une clé retournée par le Charger
d'un formulaire CVT, et donc également par un pipeline formulaire_charger.

Cette clé peut être utilisée dans le HTML du formulaire directement avec la
balise #GENERER_SAISIE{#ENV{laclé}} ou en ajoutant le code résultant en PHP
via le pipeline formulaire_fond et l'inclusion inclure/generer_saisies.

Si cette clé vaut _champs_extras_saisies alors champs extras tentera automatiquement
d'ajouter les saisies dans le HTML du formulaire, si <!--extra--> est présent.
Cf cextras_formulaire_fond().

Notons que les saisies seront enregistrées en base de données (actuellement du moins)
SI le pipeline 'pre_edition' est appelé dans les traitements du formulaire pour la table
correspondante. C'est le cas si on appelle la fonction objet_modifier(). Mais ce n'est pas
le cas si seulement objet_inserer() est appelé.

Un exemple qui a inspiré cette fonction d'aide était de pouvoir ajouter des champs extras
sur le formulaire d'inscription aux newsletters du plugin mailsubscribers. Pour cela, appeler
dans un plugin le pipeline formulaire_charger tel que :

<pipeline nom="formulaire_charger" inclure="demo_pipelines.php" />

Dedans appeler la fonction pour récupérer les champs extras de l'objet mailsubscribers :

`
function demo_formulaire_charger($flux) {

if ($fluxargs?form? == 'newsletter_subscribe') {

include_spip('inc/cextras');
if ($saisies = cextras_obtenir_saisies_champs_extras('mailsubscribers')) {

$flux_champs_extras_saisies? = $saisies;

}

}
return $flux;

}
`

Ça fonctionne presque du premier coup… Sauf que visiblement ce formulaire d'inscription n'appelle objet_modifier
que lorsqu'on inscrit une seconde fois un courriel ; du coup, la première fois les champs extras ne semblent pas
pris en compte. Il faudrait ajouter un pipeline sur 'pre_insertion' en plus pour les insérer…
Cependant, ça fait déjà le job de récupérer les champs extras et de les ajouter au formulaire.

File size: 12.9 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                $saisies_tables = pipeline('declarer_champs_extras', array());
25        }
26        return isset($saisies_tables[$table]) ? $saisies_tables[$table] : array();
27}
28
29/**
30 * Filtrer par autorisation les saisies transmises
31 *
32 * Chacune des saisies est parcourue et si le visiteur n'a pas l'autorisation
33 * de la voir, elle est enlevée de la liste.
34 * La fonction ne retourne donc que la liste des saisies que peut voir
35 * la personne.
36 *
37 * @param string $faire
38 *     Type d'autorisation testée : 'voir', 'modifier'
39 * @param string $quoi
40 *     Type d'objet tel que 'article'
41 * @param array $saisies
42 *     Liste des saisies à filtrer
43 * @param array $args
44 *     Arguments pouvant être utiles à l'autorisation
45 * @return array
46 *     Liste des saisies filtrées
47**/
48function champs_extras_autorisation($faire, $quoi='', $saisies=array(), $args=array()) {
49        if (!$saisies) return array();
50        include_spip('inc/autoriser');
51
52        foreach ($saisies as $cle=>$saisie) {
53                $id = isset($args['id']) ? $args['id'] : $args['id_objet'];
54                if (!autoriser($faire . 'extra', $quoi, $id, '', array(
55                        'type' => $quoi,
56                        'id_objet' => $id,
57                        'contexte' => isset($args['contexte']) ? $args['contexte'] : array(),
58                        'table' => table_objet_sql($quoi),
59                        'saisie' => $saisie,
60                        'champ' => $saisie['options']['nom'],
61                ))) {
62                        // on n'est pas autorise
63                        unset($saisies[$cle]);
64                }
65                else
66                {
67                        // on est autorise
68                        // on teste les sous-elements
69                        if (isset($saisie['saisies']) and $saisie['saisies']) {
70                                $saisies['saisies'] = champs_extras_autorisation($faire, $quoi, $saisie['saisies'], $args);
71                        }
72                }
73        }
74        return $saisies;
75}
76
77/**
78 * Ajoute pour chaque saisie de type SQL un drapeau (input hidden)
79 * permettant de retrouver les saisies editées.
80 *
81 * Particulièrement utile pour les checkbox qui ne renvoient
82 * rien si on les décoche.
83 *
84 * @param array $saisies
85 *     Liste de saisies
86 * @return array $saisies
87 *     Saisies complétées des drapeaux d'édition
88**/
89function champs_extras_ajouter_drapeau_edition($saisies) {
90        $saisies_sql = champs_extras_saisies_lister_avec_sql($saisies);
91        foreach ($saisies_sql as $saisie) {
92                $nom = $saisie['options']['nom'];
93                $saisies[] = array(
94                        'saisie' => 'hidden',
95                        'options' => array(
96                                'nom' => "cextra_$nom",
97                                'defaut' => 1 
98                        )
99                );
100        }
101        return $saisies;
102}
103
104// ---------- pipelines -----------
105
106
107/**
108 * Ajouter les champs extras sur les formulaires CVT editer_xx
109 *
110 * Liste les champs extras de l'objet, et s'il y en a les ajoute
111 * sur le formulaire d'édition en ayant filtré uniquement les saisies
112 * que peut voir le visiteur et en ayant ajouté des champs hidden
113 * servant à champs extras.
114 *
115 * @pipeline editer_contenu_objet
116 * @param array $flux Données du pipeline
117 * @return array      Données du pipeline
118**/ 
119function cextras_editer_contenu_objet($flux){
120        // recuperer les saisies de l'objet en cours
121        $objet = $flux['args']['type'];
122        include_spip('inc/cextras');
123        if ($saisies = champs_extras_objet( table_objet_sql($objet) )) {
124                // filtrer simplement les saisies que la personne en cours peut voir
125                $saisies = champs_extras_autorisation('modifier', $objet, $saisies, $flux['args']);
126                // pour chaque saisie presente, de type champs extras (hors fieldset et autres)
127                // ajouter un flag d'edition
128                $saisies = champs_extras_ajouter_drapeau_edition($saisies);
129                // ajouter au formulaire
130                $ajout = recuperer_fond('inclure/generer_saisies', array_merge($flux['args']['contexte'], array('saisies'=>$saisies)));
131
132                // div par défaut en 3.1+, mais avant ul / li
133                $balise = saisie_balise_structure_formulaire('ul');
134                $flux['data'] = preg_replace(
135                        '%(<!--extra-->)%is',
136                        "<$balise class='editer-groupe champs_extras'>$ajout</$balise>\n" . '$1',
137                        $flux['data']
138                );
139        }
140
141        return $flux;
142}
143
144
145/**
146 * Ajouter les champs extras soumis par les formulaire CVT editer_xx
147 *
148 * Pour chaque champs extras envoyé par le formulaire d'édition,
149 * ajoute les valeurs dans l'enregistrement à effectuer.
150 *
151 * @pipeline pre_edition
152 * @param array $flux Données du pipeline
153 * @return array      Données du pipeline
154**/ 
155function cextras_pre_edition($flux){
156
157        include_spip('inc/cextras');
158        include_spip('inc/saisies_lister');
159        $table = $flux['args']['table'];
160        if ($saisies = champs_extras_objet( $table )) {
161
162                // Restreindre les champs postés en fonction des autorisations de les modifier
163                // au cas où un malin voudrait en envoyer plus que le formulaire ne demande
164                $saisies = champs_extras_autorisation('modifier', objet_type($table), $saisies, $flux['args']);
165
166                $saisies = champs_extras_saisies_lister_avec_sql($saisies);
167                foreach ($saisies as $saisie) {
168                        $nom = $saisie['options']['nom'];
169                        if (_request('cextra_' .  $nom)) {
170                                $extra = _request($nom);
171                                if (is_array($extra)) {
172                                        $extra = join(',' , $extra);
173                                }
174                                $flux['data'][$nom] = corriger_caracteres($extra);
175                        }
176                }
177        }
178
179        return $flux;
180}
181
182
183/**
184 * Ajouter les champs extras sur la visualisation de l'objet
185 *
186 * S'il y a des champs extras sur l'objet, la fonction les ajoute
187 * à la vue de l'objet, en enlevant les saisies que la personne n'a
188 * pas l'autorisation de voir.
189 *
190 * @pipeline afficher_contenu_objet
191 * @param array $flux Données du pipeline
192 * @return array      Données du pipeline
193**/ 
194function cextras_afficher_contenu_objet($flux){
195        // recuperer les saisies de l'objet en cours
196        $objet = $flux['args']['type'];
197        include_spip('inc/cextras');
198        if ($saisies = champs_extras_objet( $table = table_objet_sql($objet) )) {
199                // ajouter au contexte les noms et valeurs des champs extras
200                $saisies_sql = champs_extras_saisies_lister_avec_sql($saisies);
201                $valeurs = sql_fetsel(array_keys($saisies_sql), $table, id_table_objet($table) . '=' . sql_quote($flux['args']['id_objet']));
202                if (!$valeurs) {
203                        $valeurs = array();
204                } else {
205                        // on applique les eventuels traitements definis
206                        // /!\ La saisies-vues/_base applique |propre par defaut si elle ne trouve pas de saisie
207                        // Dans ce cas, certains traitements peuvent être effectués 2 fois !
208                        $saisies_traitees = saisies_lister_avec_traitements($saisies_sql);
209                        unset($saisies_sql);
210
211                        // Fournir $connect et $Pile[0] au traitement si besoin (l'evil eval)
212                        $connect = '';
213                        $Pile = array(0 => (isset($flux['args']['contexte']) ? $flux['args']['contexte'] : array()));
214
215                        foreach ($saisies_traitees as $saisie) {
216                                $traitement = $saisie['options']['traitements'];
217                                $traitement = defined($traitement) ? constant($traitement) : $traitement;
218                                $nom = $saisie['options']['nom'];
219                                list($avant, $apres) = explode('%s', $traitement);
220                                eval('$val = ' . $avant . ' $valeurs[$nom] ' . $apres . ';');
221                                $valeurs[$nom] = $val;
222                        }
223                }
224
225                $contexte = isset($flux['args']['contexte']) ? $flux['args']['contexte'] : array();
226                $contexte = array_merge($contexte, $valeurs);
227
228                // restreindre la vue selon les autorisations
229                $saisies = champs_extras_autorisation('voir', $objet, $saisies, $flux['args']);
230
231                // ajouter les vues
232                $flux['data'] .= recuperer_fond('inclure/voir_saisies', array_merge($contexte, array(
233                                        'saisies' => $saisies,
234                                        'valeurs' => $valeurs,
235                )));
236        }
237
238        return $flux;
239}
240
241/**
242 * Vérification de la validité des champs extras
243 *
244 * Lorsqu'un formulaire 'editer_xx' se présente, la fonction effectue,
245 * pour chaque champs extra les vérifications prévues dans la
246 * définition de la saisie, et retourne les éventuelles erreurs rencontrées.
247 *
248 * @pipeline formulaire_verifier
249 * @param array $flux Données du pipeline
250 * @return array      Données du pipeline
251**/ 
252function cextras_formulaire_verifier($flux){
253        $form = $flux['args']['form'];
254       
255        if (strncmp($form, 'editer_', 7) !== 0) {
256                return $flux;
257        }
258       
259        $objet = substr($form, 7);
260        if ($saisies = champs_extras_objet( $table = table_objet_sql($objet) )) {
261                include_spip('inc/autoriser');
262                include_spip('inc/saisies');
263
264                // restreindre les saisies selon les autorisations
265                $id_objet = $flux['args']['args'][0]; // ? vraiment toujours ?
266                $saisies = champs_extras_autorisation('modifier', $objet, $saisies, array_merge($flux['args'], array(
267                        'id' => $id_objet,
268                        'contexte' => array()))); // nous ne connaissons pas le contexte dans ce pipeline
269
270                // restreindre les vérifications aux saisies enregistrables
271                $saisies = champs_extras_saisies_lister_avec_sql($saisies);
272
273                $verifier = charger_fonction('verifier', 'inc', true);
274
275                foreach ($saisies as $saisie) {
276                        // verifier obligatoire
277                        $nom = $saisie['options']['nom'];
278                        if (isset($saisie['options']['obligatoire']) and $saisie['options']['obligatoire']
279                        and !_request($nom))
280                        {
281                                $flux['data'][$nom] = _T('info_obligatoire');
282                       
283                        // verifier (api) + normalisation
284                        } elseif ($verifier
285                           AND isset($saisie['verifier']['type'])
286                           AND $verif = $saisie['verifier']['type'])
287                        {
288                                $options = isset($saisie['verifier']['options']) ? $saisie['verifier']['options'] : array();
289                                $normaliser = null;
290                                $valeur = _request($nom);
291                                if ($erreur = $verifier($valeur, $verif, $options, $normaliser)) {
292                                        $flux['data'][$nom] = $erreur;
293                                // si une valeur de normalisation a ete transmis, la prendre.
294                                } elseif (!is_null($normaliser)) {
295                                        set_request($nom, $normaliser);
296                                } else {
297
298                                        // [FIXME] exceptions connues de vérifications (pour les dates entre autres)
299                                        // en attendant une meilleure solution !
300                                        //
301                                        // Lorsque le champ n'est pas rempli dans le formulaire
302                                        // alors qu'une normalisation est demandée,
303                                        // verifier() sort sans indiquer d'erreur (c'est normal).
304                                        //
305                                        // Sauf que la donnée alors soumise à SQL sera une chaine vide,
306                                        // ce qui ne correspond pas toujours à ce qui est attendu.
307                                        if ((is_string($valeur) and !strlen($valeur) or (is_array($valeur) and $saisie['saisie']=='date'))
308                                          and isset($options['normaliser'])
309                                          and $norme = $options['normaliser']) {
310                                                // Charger la fonction de normalisation théoriquement dans verifier/date
311                                                // et si on en trouve une, obtenir la valeur normalisée
312                                                // qui est théoriquement la valeur par défaut, puisque $valeur est vide
313                                                include_spip("verifier/$verif");
314                                                if ($normaliser = charger_fonction("${verif}_${norme}", "normaliser", true)) {
315                                                        $erreur = null;
316                                                        $defaut = $normaliser($valeur, $options, $erreur);
317                                                        if (is_null($erreur)) {
318                                                                set_request($nom, $defaut);
319                                                        } else {
320                                                                // on affecte l'erreur, mais il est probable que
321                                                                // l'utilisateur ne comprenne pas grand chose
322                                                                $flux['data'][$nom] = $erreur;
323                                                        }
324                                                } else {
325                                                        include_spip('inc/cextras');
326                                                        extras_log("Fonction de normalisation pour ${verif}_${norme} introuvable");
327                                                }
328
329                                        }
330                                }
331                        }
332                }
333        }
334        return $flux;
335}
336
337/**
338 * Insertion dans le pipeline revisions_chercher_label (Plugin révisions)
339 * Trouver le bon label à afficher sur les champs dans les listes de révisions
340 *
341 * Si un champ est un champ extra, son label correspond au label défini du champs extra
342 *
343 * @pipeline revisions_chercher_label
344 * @param array $flux Données du pipeline
345 * @return array      Données du pipeline
346**/ 
347function cextras_revisions_chercher_label($flux) {
348        $table = table_objet_sql($flux['args']['objet']);
349        $saisies_tables = champs_extras_objet($table);
350        foreach($saisies_tables as $champ){
351                if($champ['options']['nom'] == $flux['args']['champ']){
352                        $flux['data'] = $champ['options']['label'];
353                        break;
354                }
355        }
356        return $flux;
357}
358
359
360/**
361 * Ajouter les saisies de champs extras sur des formulaires spécifiques
362 *
363 * Les champs extras s'ajoutent déjà automatiquement sur les formulaires d'édition
364 * des objets éditoriaux. Pour d'autres formulaires plus spécifiques, tel
365 * que des formulaires d'inscriptions, il est possible d'envoyer,
366 * dans la partie 'charger' du formulaire en question la clé
367 * `_champs_extras_saisies`, listant les saisies à afficher dedans.
368 *
369 * Elles seront ajoutées automatiquement à l'endroit où le code
370 * html `<!--extra-->` est présent dans le formulaire.
371 *
372 * @see cextras_obtenir_saisies_champs_extras() qui aide à récupérer les saisies.
373 *
374 * @param array $flux
375 * @return array
376**/
377function cextras_formulaire_fond($flux) {
378        if (!empty($flux['args']['contexte']['_champs_extras_saisies'])) {
379                $saisies = $flux['args']['contexte']['_champs_extras_saisies'];
380
381                // ajouter au formulaire
382                $ajout = recuperer_fond('inclure/generer_saisies', array_merge($flux['args']['contexte'], array('saisies' => $saisies)));
383
384                // div par défaut en 3.1+, mais avant ul / li
385                $balise = saisie_balise_structure_formulaire('ul');
386                $flux['data'] = preg_replace(
387                        '%(<!--extra-->)%is',
388                        "<$balise class='editer-groupe champs_extras'>$ajout</$balise>\n" . '$1',
389                        $flux['data']
390                );
391        }
392        return $flux;
393}
Note: See TracBrowser for help on using the repository browser.