spip_nursit/ecrire/inc/cvt_multietapes.php
2023-06-01 17:30:12 +02:00

318 lines
10 KiB
PHP

<?php
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
* Copyright (c) 2001-2019 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/
/**
* CVT Multi étapes
*
* Module facilitant l'écriture de formulaires CVT
* en plusieurs étapes.
*
* `#FORMULAIRE_TRUC`
*
* Squelette :
* Chaque étape est representée par un squelette indépendant qui doit
* implémenter un formulaire autonome pour les saisies de l'étape n :
*
* - formulaires/truc.html pour l'etape 1
* - formulaires/truc_2.html pour l'etape 2
* - formulaires/truc_n.html pour l'etape n
*
* Si un squelette `formulaires/truc_n.html` manque pour l'étape n
* c'est `formulaires/truc.html` qui sera utilisé
* (charge à lui de gérer le cas de cette étape).
*
* Charger :
* `formulaires_truc_charger_dist()` :
* passer '_etapes' => nombre total d'etapes de saisies (>1 !)
* indiquer toutes les valeurs à saisir sur toutes les pages
* comme si il s'agissait d'un formulaire unique
*
* Vérifier :
* Le numero d'étape courante est disponible dans `$x=_request('_etape')`, si nécessaire
* `_request()` permet d'accéder aux saisies effectuées depuis l'étape 1,
* comme si les étapes 1 a `$x` avaient été saisies en une seule fois
*
* - formulaires_truc_verifier_1_dist() : verifier les saisies de l'etape 1 uniquement
* - formulaires_truc_verifier_2_dist() : verifier les saisies de l'etape 2
* - formulaires_truc_verifier_n_dist() : verifier les saisies de l'etape n
*
* Il est possible d'implémenter toutes les vérifications dans une fonction unique
* qui sera alors appelée avec en premier argument le numero de l'étape à vérifier
* `formulaires_truc_verifier_etape_dist($etape,...)` : vérifier les saisies
* de l'étape `$etape` uniquement.
*
* À chaque étape x, les étapes 1 a x sont appelées en vérification
* pour vérifier l'absence de régression dans la validation (erreur, tentative de réinjection ...)
* en cas d'erreur, la saisie retourne à la première étape en erreur.
* en cas de succès, l'étape est incrémentée, sauf si c'est la dernière.
* Dans ce dernier cas on déclenche `traiter()`.
*
* Traiter :
* `formulaires_truc_traiter_dist()` : ne sera appelé que lorsque **toutes**
* les étapes auront été saisies sans erreur.
*
* La fonction traiter peut donc traiter l'ensemble des saisies comme si il
* s'agissait d'un formulaire unique dans lequel toutes les données auraient
* été saisies en une fois.
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Reinjecter dans _request() les valeurs postees
* dans les etapes precedentes
*
* @param string $form
* @return array
*/
function cvtmulti_recuperer_post_precedents($form) {
include_spip('inc/filtres');
if ($form
and $c = _request('cvtm_prev_post')
and $c = decoder_contexte_ajax($c, $form)
) {
#var_dump($c);
# reinjecter dans la bonne variable pour permettre de retrouver
# toutes les saisies dans un seul tableau
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$store = &$_POST;
} else {
$store = &$_GET;
}
foreach ($c as $k => $v) // on ecrase pas si saisi a nouveau !
{
if (!isset($store[$k])) {
$_REQUEST[$k] = $store[$k] = $v;
} // mais si tableau des deux cotes, on merge avec priorite a la derniere saisie
elseif (is_array($store[$k])
and is_array($v)
and $z = array_keys($v)
and !is_numeric(reset($z))
and $z = array_keys($store[$k])
and !is_numeric(reset($z))
) {
$_REQUEST[$k] = $store[$k] = array_merge($v, $store[$k]);
}
}
// vider pour eviter un second appel a verifier_n
// en cas de double implementation (unipotence)
set_request('cvtm_prev_post');
return array($c['_etape'], $c['_etapes']);
}
return false;
}
/**
* Sauvegarder les valeurs postees dans une variable encodee
* pour les recuperer a la prochaine etape
*
* @param string $form
* @param bool $je_suis_poste
* @param array $valeurs
* @return array
*/
function cvtmulti_sauver_post($form, $je_suis_poste, &$valeurs) {
if (!isset($valeurs['_cvtm_prev_post'])) {
$post = array('_etape' => $valeurs['_etape'], '_etapes' => $valeurs['_etapes']);
foreach (array_keys($valeurs) as $champ) {
if (substr($champ, 0, 1) !== '_') {
if ($je_suis_poste || (isset($valeurs['_forcer_request']) && $valeurs['_forcer_request'])) {
if (($v = _request($champ)) !== null) {
$post[$champ] = $v;
}
}
}
}
include_spip('inc/filtres');
$c = encoder_contexte_ajax($post, $form);
if (!isset($valeurs['_hidden'])) {
$valeurs['_hidden'] = '';
}
$valeurs['_hidden'] .= "<input type='hidden' name='cvtm_prev_post' value='$c' />";
// marquer comme fait, pour eviter double encodage (unipotence)
$valeurs['_cvtm_prev_post'] = true;
}
return $valeurs;
}
/**
* Reperer une demande de formulaire CVT multi page
* et la reformater
*
* @deprecated : appel direct de cvtmulti_formulaire_charger_etapes par le core
* @param array $flux
* @return array
*/
function cvtmulti_formulaire_charger($flux) {
if (is_array($flux['data'])
and isset($flux['data']['_etapes'])
) {
$flux['data'] = cvtmulti_formulaire_charger_etapes($flux['args'], $flux['data']);
}
return $flux;
}
/**
* Charger une etape du cvt multi
* @param $args
* @param $valeurs
* @return array
*/
function cvtmulti_formulaire_charger_etapes($args, $valeurs) {
if (!isset($valeurs['_etape'])) {
$form = $args['form'];
$je_suis_poste = $args['je_suis_poste'];
$nb_etapes = $valeurs['_etapes'];
$etape = _request('_etape');
$etape = min(max($etape, 1), $nb_etapes);
set_request('_etape', $etape);
$valeurs['_etape'] = $etape;
// sauver les posts de cette etape pour les avoir a la prochaine etape
$valeurs = cvtmulti_sauver_post($form, $je_suis_poste, $valeurs);
}
return $valeurs;
}
/**
* Verifier les etapes de saisie
*
* @deprecated : appel direct de cvtmulti_formulaire_verifier_etapes par le core
* @param array $flux
* @return array
*/
function cvtmulti_formulaire_verifier($flux) {
$flux['data'] = cvtmulti_formulaire_verifier_etapes($flux['args'], $flux['data']);
return $flux;
}
/**
* Verifier les etapes de saisie
*
* @param array $args
* @param $erreurs
* @return array
*/
function cvtmulti_formulaire_verifier_etapes($args, $erreurs) {
#var_dump('Pipe verifier');
if ($form = $args['form']
and ($e = cvtmulti_recuperer_post_precedents($form)) !== false
) {
// recuperer l'etape saisie et le nombre d'etapes total
list($etape, $etapes) = $e;
$etape_demandee = intval(_request('aller_a_etape')); // possibilite de poster un entier dans aller_a_etape
$args['etape_saisie'] = $etape;
$args['etapes'] = $etapes;
// lancer les verifs pour chaque etape deja saisie de 1 a $etape
$erreurs_etapes = array();
$derniere_etape_ok = 0;
$e = 0;
while ($e < max($etape, $etape_demandee -1) and $e < $etapes) {
$e++;
$erreurs_etapes[$e] = array();
if ($verifier = charger_fonction("verifier_$e", "formulaires/$form/", true)) {
$erreurs_etapes[$e] = call_user_func_array($verifier, $args['args']);
} elseif ($verifier = charger_fonction("verifier_etape", "formulaires/$form/", true)) {
$a = $args['args'];
array_unshift($a, $e);
$erreurs_etapes[$e] = call_user_func_array($verifier, $a);
}
// et on appelle un pipeline dedie aux etapes, plus easy
$args['etape'] = $e;
$args['etape_demandee'] = $etape_demandee;
$erreurs_etapes[$e] = pipeline(
'formulaire_verifier_etape',
array(
'args' => $args,
'data' => $erreurs_etapes[$e]
)
);
if ($derniere_etape_ok == $e - 1 and !count($erreurs_etapes[$e])) {
$derniere_etape_ok = $e;
}
// possibilite de poster dans _retour_etape_x ou aller_a_etape
if (!is_null(_request("_retour_etape_$e"))) {
$etape_demandee = $e;
}
// Il se peut que les verifications ait décidé de faire sauter des étapes
if ($aller_a_etape = intval(_request('aller_a_etape'))) {
$etape_demandee = $aller_a_etape; // possibilite de poster un entier dans aller_a_etape
}
}
// si la derniere etape OK etait la derniere
// on renvoie le flux inchange et ca declenche traiter
if ($derniere_etape_ok == $etapes
and (!$etape_demandee or $etape_demandee>=$etapes)) {
return $erreurs;
} else {
$etape = $derniere_etape_ok + 1;
if ($etape_demandee > 0 and $etape_demandee < $etape) {
$etape = $etape_demandee;
}
$etape = min($etape, $etapes);
#var_dump("prochaine etape $etape");
// retourner les erreurs de l'etape ciblee
$erreurs = isset($erreurs_etapes[$etape]) ? $erreurs_etapes[$etape] : array();
// Ne pas se tromper dans le texte du message d'erreur : la clé '_etapes' n'est pas une erreur !
if ($erreurs) {
if (!isset($erreurs['message_erreur'])) {
$erreurs['message_erreur'] = singulier_ou_pluriel(count($erreurs), 'avis_1_erreur_saisie', 'avis_nb_erreurs_saisie');
}
} else {
$erreurs['message_erreur'] = "";
}
$erreurs['_etapes'] = "etape suivante $etape";
set_request('_etape', $etape);
}
}
return $erreurs;
}
/**
* Selectionner le bon fond en fonction de l'etape
* L'etape 1 est sur le fond sans suffixe
* Les autres etapes x sont sur le fond _x
*
* @param array $flux
* @return array
*/
function cvtmulti_styliser($flux) {
if (strncmp($flux['args']['fond'], 'formulaires/', 12) == 0
and isset($flux['args']['contexte']['_etapes'])
and isset($flux['args']['contexte']['_etape'])
and ($e = $flux['args']['contexte']['_etape']) > 1
and $ext = $flux['args']['ext']
and $f = $flux['data']
and file_exists($f . "_$e.$ext")
) {
$flux['data'] = $f . "_$e";
}
return $flux;
}