Version 15 — Juillet 2012 — denisb
Les Astuces longues de SPIP sont des astuces qui nécessitent plus de 20 lignes pour être expliquées : voir les Astuces courtes pour SPIP courtes.
)
Question :
_
Dans ZPIP, la structure de base est définie à coup d’inclusion de grands blocs logiques du style
<code class=« spip sans_telechargement »>
>
...
<div id=« navigation »>
< INCLUREfond=navigation/#ENVtype,env >
< INCLUREfond=extra/#ENVtype,env >
</div >....
....
Supposons par exemple que nous soyons dans un contexte « rubrique » http///monsite.fr/spip.php?rubriqueXX
et que le squelette contenu/rubrique.html
se comporte de manière à afficher l’article N°yy
Comment peut-on transmettre cet id_article
dans l’inclusion extra
ou dans l’inclusion navigation
pour, par exemple, lister les autres articles de la rubrique. Il faut bien que le squelette appelé connaisse l’id de l’article à exclure que seul contenu/rubrique.html
connait !
Pour que extra/rubrique.html ou navigation/rubrique.html puisse tenir compte de la situation, il faut disposer d’un moyen pour leur transmettre cette valeur. Or, seul le squelette appelant peut transmettre une variable...
Réponse :
_
L’astuce (alambiquée) pour remonter des variables d’un squelette appelé, est d’affecter le résultat sérialisé de ce squelette à une variable tableau dans le squelette appelant :
Dans structure.html :
<code class=« spip sans_telechargement »>
>
[(#SETmyvars,[(#INCLUREfond=vars/#ENVtype,env)])]
Dans vars/rubrique.html :
<code class=« spip sans_telechargement »>
>
#CACHE3600
[(#SETvars,#ARRAY
objet,rubrique,
id_objet,#ENVid_rubrique,
titreRubrique,Rubriques,
titrePage,#ENVid_rubrique ?
)]
[(#SETvars, #GETvars|array_merge#ARRAYtitreRubrique,#TITRE,idRubrique,#ID_RUBRIQUE)]
(#GETvars
#FILTREtrim
Puis dans structure.html :
<code class=« spip sans_telechargement »>
>
---- ------
----
- ZPIP : faire un inclure de squelette suivant une condition
_ dans le body de ZPIP, charger ou non un INCLURE qui contient #ENV{type}
<code class=« spip sans_telechargement »>
[(#ID_RUBRIQUE|==10
[(#ID_RUBRIQUE|=={10 }|?{
''
,
<INCLURE{fond=extra/#ENV{type }, env <INCLURE{fond=extra/#ENV{type},env }>
})]
ne fonctionne pas à cause de accolades de #ENV, donc contourner avec
_
<code class=« spip sans_telechargement »>
[(#ID_RUBRIQUE|==10|non code>[(#ID_RUBRIQUE|==10|non ) <INCLUREfond=extra/#ENVtype , env <INCLUREfond=extra/#ENVtype,env > ]
----- ---------
contexte
tout le monde le sait (beaucoup le déplorent) : <code class=« spip sans_telechargement »>
>
[(#ENVvar|==val|oui)
en SPIP3, le critère {si ...}
permet de définir la condition d’exécution depuis la boucle elle-même.
en SPIP2, il faut utiliser le plugin « bonux » et sa boucle « CONDITION ».
il existe néanmoins un autre moyen pour arriver à nos fins...
<code class="spip sans_telechargement ">
>
#SETtest, #ENVtruc|==coucou| ?0, 999999
coucou !
explications :
#GET{test}
vaut donc soit « zéro », soit « neuf cent quatre-vingt-dix-neuf mille neuf cent quatre-vingt-dix-neuf ».--------- ----
dans un squelette, afficher la date du jour (la date courante) n’est pas toujours aisé.
_ deux variables peuvent entrer en jeu :
pour chaque cas, néanmoins, il existe une possibilité d’afficher la date du jour et ce sans que cette date soit tributaire du cache du squelette (ce sera toujours la date courante qui sera affichée)
dans une boucle dont la table possède
un champ date ou date_redac |
hors boucle | |
pas de date ni de date_redac en url
ni passées par formulaire |
#ENV{date_redac}
ou
|
#DATE_REDAC
ou
|
variable date passée en url ou par formulaire | #ENV{date_redac} |
#DATE_REDAC |
variable date_redac passée en url ou par formulaire | #ENV{date} |
#DATE |
variables date et date_redac passées
en url ou par formulaire |
définir en début de squelette la date courante avec par exemple :
puis l’utiliser dans le squelette avec :
|
voir aussi saisie des dates de publication et de rédaction antérieure (spip 2.0.x et 2.1.x)
</blockquote>- la date du prochain jeudi qui suit #DATE
:
[(#VAL{Y-m-d}|date{#VAL{next Thursday}|strtotime{#DATE|affdate{U}}})]
- le nom du jour de l’avant-veille de #DATE
:
[(#VAL{Y-m-d}|date{#VAL{-2 days}|strtotime{#DATE|affdate{U}}}|nom_jour)]
- la date de lundi prochain :
[(#SET{lundi_prochain, #VAL{Y-m-d 00:00:00}|date{#VAL{next Monday}|strtotime{#DATE|affdate{U}}}})]
#GET{lundi_prochain}
- la date du dimanche d’après lundi prochain :
[(#SET{dimanche_apres, #VAL{Y-m-d 23:59:59}|date{#VAL{+6days}|strtotime{#GET{lundi_prochain}|affdate{U}}}})]
#GET{dimanche_apres}
- afficher le label nouveau ! pour un article publié ou modifié il y a moins de 10 jours :
#SET{periode, -10days}
#TITRE[ (#DATE_MODIF|>{#VAL{Y-m-d H:i:s}|date{#GET{periode}|strtotime}}|oui) nouveau !]
et _fil_ (sur irc) propose encore plus simple :
#TITRE[ (#DATE|strtotime|>{#VAL{-10days}|strtotime}|?{nouveau !, ''})]
----
Triton nous confie un petit exemple qui marche pour MS Excel et openOffice (il y a des particularités d’encodage de caractères) :
<code class=« spip sans_telechargement »>
>
#CACHE0 #HTTP_HEADERContent-Type : text/csv ; charset=windows-1252/Winlatin1 #HTTP_HEADERContent-Disposition : attachment ; filename=inscriptions.csv
« date » ; « nom_participant » ;« prenom » ;« paiement effectue » ; « tarif_valide » ; « promo » ;« telephone » ; « email » ;« societe » ; « nbr_part » ;« conjoint » ; « mobile_dom » ;« type_paiement » ; « souscripteur »
<BOUCLE_les_inscriptions_ouvertes(EVENEMENTS_LESINSCRIPTIONS ) id_evenement nbr_part > 0>« [(#DATE|affdate’d-m-Y
Il faut, souvent, coller toutes les lignes comme ci-dessus, sinon, on peut, ou pas, se retrouver avec des lignes vides dans le csv....
Si tu colles ca dans un squelette (nommé squelette_cvs), il suffit
ensuite d’appeler la page spip.php ?page=squelette_cvs et le navigateur
te proposera de sauvegarder le fichier (ici inscriptions.csv - voir le
filename au dessus) ou de l ouvrir avec le logiciel de ton choix....
Apres, faut voir a quoi doit servir ton cvs, a etre lu directement par
une appli type MS/ Open Office (cet exemple) ou a autre chose, import
dans une base sql par exemple, auquel cas, il faudra peut-être modifier l’encodage de caractères...
Par ailleurs, paube indique qu’il faut d’abord passer les champs par le filtre textebrut avant de les passer à la moulinette de utf8_decode
on peut aussi « jolifier » et simplifier le code (surtout dans la boucle) :
<code class="spip sans_telechargement ">
#CACHE0
#CACHE{0}
#HTTP_HEADER{Content-Type: text/csv; charset=windows-1252/Winlatin1}
#HTTP_HEADER{Content-Disposition: attachment; filename=inscriptions.csv}
"ordre"; "date"; "nom_participant"; "prenom"; "paiement effectue"; "tarif_valide"; "promo"; "telephone"; "email"; "societe"; "nbr_part"; "conjoint"; "mobile_dom"; "type_paiement"; "souscripteur"
<BOUCLE_inscriptions_ouvertes(EVENEMENTS_LESINSCRIPTIONS ) {id_evenement} {nbr_part > 0}>#VAL{#COMPTEUR_BOUCLE;"[(#DATE|affdate{'d-m-Y <BOUCLE_inscriptions_ouvertes(EVENEMENTS_LESINSCRIPTIONS){id_evenement}{nbr_part>0}>#VAL{#COMPTEUR_BOUCLE;"[(#DATE|affdate{'d-m-Y '})]"; "#NOM_PARTICIPANT"; "#PRENOM"; "#VERIFIER_PAIEMENT_INSCRIPTION{#ID_INSCRIPTION}"; "#TARIF_VALIDE"; "#PROMO"; "#TELEPHONE"; "#EMAIL"; "#SOCIETE"; "#NBR_PART"; "#CONJOINT"; "#MOBILE_DOM"; "#TYPE_PAIEMENT"; "#SOUSCRIPTEUR"}|textebrut|utf8_decode)]
</BOUCLE_inscriptions_ouvertes>
l’astuce consiste à ajouter #COMPTEUR_BOUCLE;
comme premier champ de #VAL
(donc aussi "ordre";
en première ligne de la feuille)
----
/**
* Le filtre extraire_email permet de récuperer toutes les adresses email
* présentes dans le texte retourné par la balise sur laquelle il s'applique.
*
* @param string $texte
* l'affichage retourné par la balise
*
* @return array
* un tableau dédoublonné des adresses email
**/
function extraire_email($texte) {
// /toto@truc.net étant une adresse valide ne pas confondre
// avec toto@truc.net dans href="mailto://toto@truc.net"
$texte = preg_replace(',mailto://,', '', $texte);
// contrôle : voir http://tools.ietf.org/html/rfc3696#page-6
if (preg_match_all(";[a-z0-9!#$%&'*+/=?^_<span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+e3x9fi1dKyg/OlwuW2EtejAtOSEjJCUmYW1wOycqKy89P15fPC9jb2RlPg=="></span>{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?;ims", $texte, $matches))
return array_unique($matches[0]);
return array();
}
exemple d’utilisation dans un squelette :
<code cadre class=’spip sans_telechargement ’>
#SETres, #ARRAY
[(#SETres, #GETres|array_merge#TEXTE|extraire_email)]
(#GETres
----
copiée sur la fonction du débugueur debusquer_contexte() (de ecrire/public/debusquer.php), cette fonction est à déposer dans le fichier mes_options.php
/**
* Une fonction récursive pour joliment afficher #ENV, #GET, #SESSION...
* en squelette : [(#ENV|bel_env)], [(#GET|bel_env)], [(#SESSION|bel_env)]
* ou encore [(#ARRAY{0,1, a,#SESSION, 1,#ARRAY{x,y}}|bel_env)]
*
* @param string|array $env
* si une string est passée elle doit être le serialize d'un array
*
* @return string
* une chaîne html affichant une <table>
**/
function bel_env($env) {
$env = str_replace(array('"', '''), array('"', '\''), $env);
if (is_array($env_tab = @unserialize($env))) {
$env = $env_tab;
}
if (!is_array($env)) {
return '';
}
$style = " style='border:1px solid #ddd;'";
$res = "<table style='border-collapse:collapse;'>\n";
foreach ($env as $nom => $val) {
if (is_array($val) || is_array(@unserialize($val))) {
$val = bel_env($val);
}
else {
$val = entites_html($val);
}
$res .= "<tr>\n<td$style><strong>". entites_html($nom).
" : </strong></td><td$style>" .$val. "</td>\n</tr>\n";
}
$res .= "</table>";
return $res;
}
ne reste plus qu’à l’appeler (que l’on soit loggé ou pas) dans un squelette avec :
<code cadre class=« spip sans_telechargement »>
(#ENV
</code </cadre >
ou encore :
<code cadre class=« spip sans_telechargement »>
(#GET
</code </cadre >
ou encore :
<code cadre class=« spip sans_telechargement »>
(#SESSION
</code </cadre >
----
- Avec SPIP3 c’est même pas drôle :
#PROFONDEUR
dans une boucle (RUBRIQUES)
#INFO_x{objet, id_objet}
en dehors d’une boucle- Avec SPIP2.1 deux solutions :
---- </cadre >
En spip2.x, le contexte d’appel d’un modèle n’était pas connu lors de la compilation de ce modèle. Ainsi un modèle appelé depuis le corps du texte de l’article 18 ne pouvait savoir qu’il était appelé depuis cet article précis.
Cela a changé avec spip3 ; désormais le modèle véhicule le contexte de son objet appelant. Cela veut dire que appelé depuis l’article 18, le modèle intègre la donnée id_article = 18 ; donnée que l’on peut donc utiliser dans le modèle avec :
#ID_ARTICLE
,#ENV{id_article}
,#ENV{args/id_article}
.Mais plusieurs cas peuvent se présenter :
<mon_modele1>
#ID_ARTICLE
vaudra la valeur id_article de l’article appelant (celui où se trouve l’appel du modèle)#ENV{id_article}
vaudra la valeur id_article de l’article appelant (celui où se trouve l’appel du modèle)#ENV{args/id_article}
vaudra ’’ (vide) <mon_modele1|id_article=25>
#ID_ARTICLE
vaudra la valeur passée en argument : 25#ENV{id_article}
vaudra la valeur passée en argument : 25#ENV{args/id_article}
vaudra la valeur passée en argument : 25 <mon_modele1|id_article=>
#ID_ARTICLE
vaudra ’’ (vide)#ENV{id_article}
vaudra ’’ (vide)#ENV{args/id_article}
vaudra ’’ (vide)Et alors ?
Connaissant l’id de l’objet (article, rubrique, mot, site...) depuis lequel notre modèle est appelé, il est désormais possible d’utiliser des boucles utilisant cette information, de telle sorte que le modèle devient ainsi contextuel en affichant des informations dépendantes de son lieu d’appel. Un même modèle appelé depuis plusieurs articles retournera ainsi des informations spécifiques différentes pour chaque article.
Attention !
Comme désormais l’id de l’objet appelant (id_article, id_rubrique, id_mot...) est toujours transmis au modèle, il devient impossible d’utiliser dans le modèle une boucle avec le critère conditionnel {id_article?}
(ou {id_rubrique?}
, ou {id_mot?}
...)
L’astuce consistera à utiliser 2 critères dépendants de #ENV{args/id_article}
car seul #ENV{args/id_article}
nous renseigne sur l’argument « id_article » passé explicitement au modèle.
<BOUCLE_a_cond(ARTICLES) {id_article >= #ENV{args/id_article, 0}} {id_article <= #ENV{args/id_article, 99999999}} {"<br />"}>
#ID_ARTICLE - #TITRE
</BOUCLE_a_cond>
----