[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / inc / cvt_multietapes.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2017 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * CVT Multi étapes
15 *
16 * Module facilitant l'écriture de formulaires CVT
17 * en plusieurs étapes.
18 *
19 * `#FORMULAIRE_TRUC`
20 *
21 * Squelette :
22 * Chaque étape est representée par un squelette indépendant qui doit
23 * implémenter un formulaire autonome pour les saisies de l'étape n :
24 *
25 * - formulaires/truc.html pour l'etape 1
26 * - formulaires/truc_2.html pour l'etape 2
27 * - formulaires/truc_n.html pour l'etape n
28 *
29 * Si un squelette `formulaires/truc_n.html` manque pour l'étape n
30 * c'est `formulaires/truc.html` qui sera utilisé
31 * (charge à lui de gérer le cas de cette étape).
32 *
33 * Charger :
34 * `formulaires_truc_charger_dist()` :
35 * passer '_etapes' => nombre total d'etapes de saisies (>1 !)
36 * indiquer toutes les valeurs à saisir sur toutes les pages
37 * comme si il s'agissait d'un formulaire unique
38 *
39 * Vérifier :
40 * Le numero d'étape courante est disponible dans `$x=_request('_etape')`, si nécessaire
41 * `_request()` permet d'accéder aux saisies effectuées depuis l'étape 1,
42 * comme si les étapes 1 a `$x` avaient été saisies en une seule fois
43 *
44 * - formulaires_truc_verifier_1_dist() : verifier les saisies de l'etape 1 uniquement
45 * - formulaires_truc_verifier_2_dist() : verifier les saisies de l'etape 2
46 * - formulaires_truc_verifier_n_dist() : verifier les saisies de l'etape n
47 *
48 * Il est possible d'implémenter toutes les vérifications dans une fonction unique
49 * qui sera alors appelée avec en premier argument le numero de l'étape à vérifier
50 * `formulaires_truc_verifier_etape_dist($etape,...)` : vérifier les saisies
51 * de l'étape `$etape` uniquement.
52 *
53 * À chaque étape x, les étapes 1 a x sont appelées en vérification
54 * pour vérifier l'absence de régression dans la validation (erreur, tentative de réinjection ...)
55 * en cas d'erreur, la saisie retourne à la première étape en erreur.
56 * en cas de succès, l'étape est incrémentée, sauf si c'est la dernière.
57 * Dans ce dernier cas on déclenche `traiter()`.
58 *
59 * Traiter :
60 * `formulaires_truc_traiter_dist()` : ne sera appelé que lorsque **toutes**
61 * les étapes auront été saisies sans erreur.
62 *
63 * La fonction traiter peut donc traiter l'ensemble des saisies comme si il
64 * s'agissait d'un formulaire unique dans lequel toutes les données auraient
65 * été saisies en une fois.
66 */
67
68 if (!defined('_ECRIRE_INC_VERSION')) {
69 return;
70 }
71
72 /**
73 * Reinjecter dans _request() les valeurs postees
74 * dans les etapes precedentes
75 *
76 * @param string $form
77 * @return array
78 */
79 function cvtmulti_recuperer_post_precedents($form) {
80 include_spip('inc/filtres');
81 if ($form
82 and $c = _request('cvtm_prev_post')
83 and $c = decoder_contexte_ajax($c, $form)
84 ) {
85 #var_dump($c);
86
87 # reinjecter dans la bonne variable pour permettre de retrouver
88 # toutes les saisies dans un seul tableau
89 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
90 $store = &$_POST;
91 } else {
92 $store = &$_GET;
93 }
94
95 foreach ($c as $k => $v) // on ecrase pas si saisi a nouveau !
96 {
97 if (!isset($store[$k])) {
98 $_REQUEST[$k] = $store[$k] = $v;
99 } // mais si tableau des deux cotes, on merge avec priorite a la derniere saisie
100 elseif (is_array($store[$k])
101 and is_array($v)
102 and $z = array_keys($v)
103 and !is_numeric(reset($z))
104 and $z = array_keys($store[$k])
105 and !is_numeric(reset($z))
106 ) {
107 $_REQUEST[$k] = $store[$k] = array_merge($v, $store[$k]);
108 }
109 }
110
111 // vider pour eviter un second appel a verifier_n
112 // en cas de double implementation (unipotence)
113 set_request('cvtm_prev_post');
114
115 return array($c['_etape'], $c['_etapes']);
116 }
117
118 return false;
119 }
120
121 /**
122 * Sauvegarder les valeurs postees dans une variable encodee
123 * pour les recuperer a la prochaine etape
124 *
125 * @param string $form
126 * @param bool $je_suis_poste
127 * @param array $valeurs
128 * @return array
129 */
130 function cvtmulti_sauver_post($form, $je_suis_poste, &$valeurs) {
131 if (!isset($valeurs['_cvtm_prev_post'])) {
132 $post = array('_etape' => $valeurs['_etape'], '_etapes' => $valeurs['_etapes']);
133 foreach (array_keys($valeurs) as $champ) {
134 if (substr($champ, 0, 1) !== '_') {
135 if ($je_suis_poste || (isset($valeurs['_forcer_request']) && $valeurs['_forcer_request'])) {
136 if (($v = _request($champ)) !== null) {
137 $post[$champ] = $v;
138 }
139 }
140 }
141 }
142 include_spip('inc/filtres');
143 $c = encoder_contexte_ajax($post, $form);
144 if (!isset($valeurs['_hidden'])) {
145 $valeurs['_hidden'] = '';
146 }
147 $valeurs['_hidden'] .= "<input type='hidden' name='cvtm_prev_post' value='$c' />";
148 // marquer comme fait, pour eviter double encodage (unipotence)
149 $valeurs['_cvtm_prev_post'] = true;
150 }
151
152 return $valeurs;
153 }
154
155
156 /**
157 * Reperer une demande de formulaire CVT multi page
158 * et la reformater
159 *
160 * @deprecated : appel direct de cvtmulti_formulaire_charger_etapes par le core
161 * @param array $flux
162 * @return array
163 */
164 function cvtmulti_formulaire_charger($flux) {
165 if (is_array($flux['data'])
166 and isset($flux['data']['_etapes'])
167 ) {
168 $flux['data'] = cvtmulti_formulaire_charger_etapes($flux['args'], $flux['data']);
169 }
170
171 return $flux;
172 }
173
174 /**
175 * Charger une etape du cvt multi
176 * @param $args
177 * @param $valeurs
178 * @return array
179 */
180 function cvtmulti_formulaire_charger_etapes($args, $valeurs) {
181 if (!isset($valeurs['_etape'])) {
182 $form = $args['form'];
183 $je_suis_poste = $args['je_suis_poste'];
184 $nb_etapes = $valeurs['_etapes'];
185 $etape = _request('_etape');
186 $etape = min(max($etape, 1), $nb_etapes);
187 set_request('_etape', $etape);
188 $valeurs['_etape'] = $etape;
189
190 // sauver les posts de cette etape pour les avoir a la prochaine etape
191 $valeurs = cvtmulti_sauver_post($form, $je_suis_poste, $valeurs);
192 }
193 return $valeurs;
194 }
195
196
197 /**
198 * Verifier les etapes de saisie
199 *
200 * @deprecated : appel direct de cvtmulti_formulaire_verifier_etapes par le core
201 * @param array $flux
202 * @return array
203 */
204 function cvtmulti_formulaire_verifier($flux) {
205 $flux['data'] = cvtmulti_formulaire_verifier_etapes($flux['args'], $flux['data']);
206 return $flux;
207 }
208
209 /**
210 * Verifier les etapes de saisie
211 *
212 * @param array $args
213 * @param $erreurs
214 * @return array
215 */
216 function cvtmulti_formulaire_verifier_etapes($args, $erreurs) {
217 #var_dump('Pipe verifier');
218
219 if ($form = $args['form']
220 and ($e = cvtmulti_recuperer_post_precedents($form)) !== false
221 ) {
222 // recuperer l'etape saisie et le nombre d'etapes total
223 list($etape, $etapes) = $e;
224 $etape_demandee = _request('aller_a_etape'); // possibilite de poster en entier dans aller_a_etape
225
226 // lancer les verifs pour chaque etape deja saisie de 1 a $etape
227 $erreurs_etapes = array();
228 $derniere_etape_ok = 0;
229 $e = 0;
230 while ($e < $etape and $e < $etapes) {
231 $e++;
232 $erreurs_etapes[$e] = array();
233 if ($verifier = charger_fonction("verifier_$e", "formulaires/$form/", true)) {
234 $erreurs_etapes[$e] = call_user_func_array($verifier, $args['args']);
235 } elseif ($verifier = charger_fonction("verifier_etape", "formulaires/$form/", true)) {
236 $a = $args['args'];
237 array_unshift($a, $e);
238 $erreurs_etapes[$e] = call_user_func_array($verifier, $a);
239 }
240 // et on appelle un pipeline dedie aux etapes, plus easy
241 $args['etape'] = $e;
242 $erreurs_etapes[$e] = pipeline(
243 'formulaire_verifier_etape',
244 array(
245 'args' => $args,
246 'data' => $erreurs_etapes[$e]
247 )
248 );
249
250 if ($derniere_etape_ok == $e - 1 and !count($erreurs_etapes[$e])) {
251 $derniere_etape_ok = $e;
252 }
253 // possibilite de poster dans _retour_etape_x
254 if (!is_null(_request("_retour_etape_$e"))) {
255 $etape_demandee = $e;
256 }
257 }
258
259 // si la derniere etape OK etait la derniere
260 // on renvoie le flux inchange et ca declenche traiter
261 if ($derniere_etape_ok == $etapes and !$etape_demandee) {
262 return $erreurs;
263 } else {
264 $etape = $derniere_etape_ok + 1;
265 if ($etape_demandee > 0 and $etape_demandee < $etape) {
266 $etape = $etape_demandee;
267 }
268 $etape = min($etape, $etapes);
269 #var_dump("prochaine etape $etape");
270 // retourner les erreurs de l'etape ciblee
271 $erreurs = isset($erreurs_etapes[$etape]) ? $erreurs_etapes[$etape] : array();
272 // Ne pas se tromper dans le texte du message d'erreur : la clé '_etapes' n'est pas une erreur !
273 if ($erreurs) {
274 $erreurs['message_erreur'] = singulier_ou_pluriel(count($erreurs), 'avis_1_erreur_saisie', 'avis_nb_erreurs_saisie');
275 } else {
276 $erreurs['message_erreur'] = "";
277 }
278 $erreurs['_etapes'] = "etape suivante $etape";
279 set_request('_etape', $etape);
280 }
281 }
282
283 return $erreurs;
284 }
285
286 /**
287 * Selectionner le bon fond en fonction de l'etape
288 * L'etape 1 est sur le fond sans suffixe
289 * Les autres etapes x sont sur le fond _x
290 *
291 * @param array $flux
292 * @return array
293 */
294 function cvtmulti_styliser($flux) {
295 if (strncmp($flux['args']['fond'], 'formulaires/', 12) == 0
296 and isset($flux['args']['contexte']['_etapes'])
297 and isset($flux['args']['contexte']['_etape'])
298 and ($e = $flux['args']['contexte']['_etape']) > 1
299 and $ext = $flux['args']['ext']
300 and $f = $flux['data']
301 and file_exists($f . "_$e.$ext")
302 ) {
303 $flux['data'] = $f . "_$e";
304 }
305
306 return $flux;
307 }