You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
12 KiB

<?php
/**
* Déclarations de balises pour les squelettes
*
* @package SPIP\Cextras\Fonctions
**/
// sécurité
if (!defined("_ECRIRE_INC_VERSION")) return;
/**
* Retourne la description de la saisie du champ demandé
* permettant ainsi d'exploiter ses données.
*
* @example
* ```
* <BOUCLE_x(TABLE)>
* - #CHAMP_EXTRA{nom_du_champ}
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 ($flux['args']['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.
6 years ago
* - #CHAMP_EXTRA{nom_du_champ, label}
* </BOUCLE_x>
* ```
*
* @balise
* @note
* Lève une erreur de squelette si le nom de champs extras
* n'est pas indiqué en premier paramètre de la balise
*
* @param Champ $p
* AST au niveau de la balise
* @return Champ
* AST complété par le code PHP de la balise
**/
function balise_CHAMP_EXTRA_dist($p) {
// prendre nom de la cle primaire de l'objet pour calculer sa valeur
$id_boucle = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
$objet = $p->boucles[$id_boucle]->id_table;
// recuperer les parametres : colonne sql (champ)
if (!$colonne = interprete_argument_balise(1, $p)) {
$msg = array('zbug_balise_sans_argument', array('balise' => ' CHAMP_EXTRA'));
erreur_squelette($msg, $p);
}
$demande = sinon(interprete_argument_balise(2, $p), "''");
$p->code = "calculer_balise_CHAMP_EXTRA('$objet', $colonne, $demande)";
return $p;
}
/**
* Retourne la description d'un champ extra indiqué
*
* Retourne le tableau de description des options de saisies
* ou un des attributs de ce tableau
*
* @param string $objet
* Type d'objet
* @param string $colonne
* Nom de la colonne SQL
* @param string $demande
* Nom du paramètre demandé. On cherche un nom de clé dans la description :
* - dans le tableau 'options';
* - sinon à la racine (ie. si 'saisie', retourne le type de saisie).
* Non renseigné, tout le tableau de description est retourné
* @return mixed
* - Tableau si toute la description est demandée
* - Indéfini si un élément spécifique de la description est demandé.
* - Chaine vide si le champs extra n'est pas trouvé
*/
function calculer_balise_CHAMP_EXTRA($objet, $colonne, $demande='') {
// Si la balise n'est pas dans une boucle, on cherche un objet explicite dans le premier argument
// de la forme "trucs/colonne" ou "spip_trucs/colonne"
if (!$objet and $decoupe = explode('/', $colonne) and count($decoupe) == 2){
$objet = $decoupe[0];
$colonne = $decoupe[1];
}
// recuperer la liste des champs extras existants
include_spip('cextras_pipelines');
if (!$saisies = champs_extras_objet( $table = table_objet_sql($objet) )) {
return '';
}
include_spip('inc/saisies');
if (!$saisie = saisies_chercher($saisies, $colonne)) {
return '';
}
if (!$demande) {
return $saisie['options']; // retourne la description de la saisie...
}
if (array_key_exists($demande, $saisie['options'])) {
return $saisie['options'][$demande];
} elseif (array_key_exists($demande, $saisie)) {
return $saisie[$demande];
}
return '';
}
/**
* Retourne les choix possibles d'un champ extra donné
*
* @example
* ```
* #LISTER_CHOIX{champ}
* #LISTER_CHOIX{champ, " > "}
* // ** pour retourner un tableau (cle => valeur),
* // ou tableau groupe => tableau (cle => valeur) si déclaration de groupements.
* #LISTER_CHOIX**{champ}
* ```
*
* @balise
* @param Champ $p
* AST au niveau de la balise
* @return Champ
* AST complété par le code PHP de la balise
**/
function balise_LISTER_CHOIX_dist($p) {
// prendre nom de la cle primaire de l'objet pour calculer sa valeur
$id_boucle = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
// s'il n'y a pas de nom de boucle, on ne peut pas fonctionner
if (!isset($p->boucles[$id_boucle])) {
$msg = array('zbug_champ_hors_boucle', array('champ' => ' LISTER_CHOIX'));
erreur_squelette($msg, $p);
$p->code = "''";
return $p;
}
$objet = $p->boucles[$id_boucle]->id_table;
// recuperer les parametres : colonne sql (champ)
if (!$colonne = interprete_argument_balise(1, $p)) {
$msg = array('zbug_balise_sans_argument', array('balise' => ' LISTER_CHOIX'));
erreur_squelette($msg, $p);
$p->code = "''";
return $p;
}
$separateur = interprete_argument_balise(2, $p);
if (!$separateur) $separateur = "', '";
// generer le code d'execution
$applatir = ($p->etoile == "**") ? 'false' : 'true';
$p->code = "calculer_balise_LISTER_CHOIX('$objet', $colonne, $applatir)";
// retourne un array si #LISTER_CHOIX**
// sinon fabrique une chaine avec le separateur designe.
if ($p->etoile != "**") {
$p->code = "(is_array(\$a = $p->code) ? join($separateur, \$a) : " . $p->code . ")";
}
return $p;
}
/**
* Retourne les choix possibles d'un champ extra indiqué
*
* @note
* Le plugin saisies tolère des sélections avec
* un affichage par groupe (optgroup / options) avec une syntaxe
* spécifique. Ici nous devons pouvoir applatir
* toutes les cle => valeur.
*
* @param string $objet
* Type d'objet
* @param string $colonne
* Nom de la colonne SQL
* @param bool $applatir
* true pour applatir les choix possibles au premier niveau
* même si on a affaire à une liste de choix triée par groupe
* @return string|array
* - Tableau des couples (clé => valeur) des choix
* - Chaîne vide si le champs extra n'est pas trouvé
*/
function calculer_balise_LISTER_CHOIX($objet, $colonne, $applatir = true) {
if ($options = calculer_balise_CHAMP_EXTRA($objet, $colonne)) {
if (
!empty($options['datas'])
or !empty($options['data'])
) {
include_spip('inc/saisies');
$choix = !empty($options['datas']) ? $options['datas'] : $options['data'];
$choix = saisies_chaine2tableau($choix);
// applatir les sous-groupes si présents
if ($applatir) {
$masquer_sous_groupe = isset($options['vue_masquer_sous_groupe']) ? $options['vue_masquer_sous_groupe'] : false;
$choix = saisies_aplatir_tableau($choix, $masquer_sous_groupe);
}
return $choix;
}
}
return '';
}
/**
* Liste les valeurs des champs de type liste (enum, radio, case)
*
* Ces champs enregistrent en base la valeur de la clé
* Il faut donc transcrire clé -> valeur
*
* @example
* ```
* #LISTER_VALEURS{champ}
* #LISTER_VALEURS{champ, " > "}
* #LISTER_VALEURS**{champ} // retourne un tableau cle/valeur
* ```
*
* @note
* Pour des raisons d'efficacité des requetes SQL
* le paramètre "champ" ne peut être calculé
* ``#LISTER_VALEURS{#GET{champ}}`` ne peut pas fonctionner.
*
* Si cette restriction est trop limitative, on verra par la suite
* pour l'instant, on laisse comme ca...
*
* @balise
* @param Champ $p
* AST au niveau de la balise
* @return Champ
* AST complété par le code PHP de la balise
*/
function balise_LISTER_VALEURS_dist($p) {
// prendre nom de la cle primaire de l'objet pour calculer sa valeur
$id_boucle = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
// s'il n'y a pas de nom de boucle, on ne peut pas fonctionner
if (!isset($p->boucles[$id_boucle])) {
$msg = array('zbug_champ_hors_boucle', array('champ' => ' LISTER_VALEURS'));
erreur_squelette($msg, $p);
$p->code = "''";
return $p;
}
$objet = $p->boucles[$id_boucle]->id_table;
$_id_objet = $p->boucles[$id_boucle]->primary;
$id_objet = champ_sql($_id_objet, $p);
// recuperer les parametres : colonne sql (champ)
if (!$colonne = interprete_argument_balise(1, $p)) {
$msg = array('zbug_balise_sans_argument', array('balise' => ' LISTER_VALEURS'));
erreur_squelette($msg, $p);
$p->code = "''";
return $p;
}
$separateur = interprete_argument_balise(2, $p);
if (!$separateur) $separateur = "', '";
// demander la colonne dans la requete SQL
// $colonne doit etre un texte 'nom_du_champ'
if ($p->param[0][1][0]->type != 'texte') {
$msg = array('cextras:zbug_balise_argument_non_texte', array('nb'=>1, 'balise' => ' LISTER_VALEURS'));
erreur_squelette($msg, $p);
$p->code = "''";
return $p;
}
$texte_colonne = $p->param[0][1][0]->texte;
$valeur = champ_sql($texte_colonne, $p);
// generer le code d'execution
$p->code = "calculer_balise_LISTER_VALEURS('$objet', $colonne, $valeur)";
// retourne un array si #LISTER_VALEURS**
// sinon fabrique une chaine avec le separateur designe.
if ($p->etoile != "**") {
$p->code = "(is_array(\$a = $p->code) ? join($separateur, \$a) : " . $p->code . ")";
}
return $p;
}
/**
* Retourne liste des valeurs choisies pour un champ extra indiqué
*
* @param string $objet
* Type d'objet
* @param string $colonne
* Nom de la colonne SQL
* @param string $cles
* Valeurs enregistrées pour ce champ dans la bdd pour l'objet en cours
*
* @return string|array
* - Tableau des couples (clé => valeur) des choix
* - Chaîne vide si le champs extra n'est pas trouvé
**/
function calculer_balise_LISTER_VALEURS($objet, $colonne, $cles) {
//A-t-on une fonction spécifique pour ce type de saisie ?
$saisie = calculer_balise_CHAMP_EXTRA($objet, $colonne, 'saisie');
if ($f = charger_fonction("calculer_balise_LISTER_VALEURS_$saisie", 'champs_extras/', true)) {
return $f($objet, $colonne, $cles);
}
// exploser les cles !
$cles = explode(',', $cles);
// pas de valeur vide '', (ou d’espace … peu probable) !
$cles = array_filter($cles, 'trim');
// si pas de cles, on part aussi gentiment
if (!$cles) return array();
// recuperer les choix possibles
$choix = calculer_balise_LISTER_CHOIX($objet, $colonne);
// sortir gentiment si pas de champs declares
// on ne peut pas traduire les cles
if (!$choix) {
return $cles;
}
// correspondances...
$vals = array_intersect_key($choix, array_flip($cles));
// et voici les valeurs !
return $vals ? $vals : $cles;
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 ($flux['args']['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.
6 years ago
}
/**
* Retourne le HTML de la vue des champs extras de la table
*
* @example
* ```
* <BOUCLE_x(TABLE)>
* #VOIR_CHAMPS_EXTRAS
* </BOUCLE_x>
* ```
*
* @balise
* @param Champ $p
* AST au niveau de la balise
* @return Champ
* AST complété par le code PHP de la balise
**/
function balise_VOIR_CHAMPS_EXTRAS_dist($p) {
// prendre nom de la cle primaire de l'objet pour calculer sa valeur
$id_boucle = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
$objet = $p->boucles[$id_boucle]->id_table;
$_id_objet = $p->boucles[$id_boucle]->primary;
$id_objet = champ_sql($_id_objet, $p);
$p->code = "champs_extras_voir_saisies('$objet', $id_objet)";
return $p;
}
/**
* Retourne le HTML des vues des champs extras d'un objet
*
* @param string $objet Type d'objet
* @param int $id_objet Identifiant de l'objet
* @param array $contexte Contexte éventuel
* @return string Code HTML
*/
function champs_extras_voir_saisies($objet, $id_objet, $contexte = array()) {
include_spip('cextras_pipelines');
if ($saisies = champs_extras_objet( $table = table_objet_sql($objet) )) {
include_spip('inc/cextras');
// ajouter au contexte les noms et valeurs des champs extras
$saisies_sql = champs_extras_saisies_lister_avec_sql($saisies);
$valeurs = sql_fetsel(array_keys($saisies_sql), $table, id_table_objet($table) . '=' . sql_quote($id_objet));
if (!$valeurs) {
$valeurs = array();
} else {
$valeurs = cextras_appliquer_traitements_saisies($saisies_sql, $valeurs);
}
// restreindre la vue selon les autorisations
$saisies = champs_extras_autorisation('voir', $objet, $saisies, array(
'objet' => $objet,
'id_objet' => $id_objet,
'contexte' => $contexte,
));
// insérer la classe CSS pour crayons
$saisies = champs_extras_saisies_inserer_classe_crayons($saisies, $objet, $id_objet);
$contexte = array_merge($contexte, $valeurs, array(
'saisies' => $saisies,
'valeurs' => $valeurs,
));
// ajouter les vues
return recuperer_fond('inclure/voir_saisies', $contexte);
}
return '';
}