Browse Source

feat: sélection des documents plus versatile pour le modèle album

On permet d'utiliser le modèle en dehors de l'objet éditorial album :
- soit on donne une sélection arbitraire de documents avec id_document
- soit on veut les documents liés à un contenu avec objet + id_objet.

Par contre ça fait parfois des jointures improbables qui cassent les conditions du where dans certains cas : L1.objet=truc AND L2.id_objet = N.
On contourne en faisant une partie du where à la main + un critère qui fait juste un LEFT JOIN sur la table de liens, mais il y a certainement quelque chose à corriger dans le core.

On active la mediabox sur tous les documents images.

Et quelques fix et optimisations du modèle.
master
tcharlss 3 months ago
parent
commit
98afaab8d2
  1. 64
      modeles/album.html
  2. 237
      modeles/album_fonctions.php

64
modeles/album.html

@ -2,6 +2,13 @@
Modèle album standard.
Permet d'afficher des documents de diverses façons.
On peut choisir les documents de 3 façons :
- Soit ceux liés à un album : id_album
- Soit ceux liés à un objet : objet + id_objet
- Soit une sélection arbitraire : id_document
Par défaut c'est une vue sous forme de vignettes, plutôt adaptée aux images.
Le paramètre `disposition` permet de changer substantiellement l'affichage :
@ -17,9 +24,13 @@
Paramètres :
**obligatoire
*optionnel
*conseillé
- **id_album : identifiant d'un album
Sélection des documents :
- **id_album : soit l'identifiant d'un album
- **objet + id_objet : soit un type d'objet et son identifiant
- **id_document : soit des numéros de documents, tableau ou séparés par des virgules
Textes personnalisés :
@ -89,7 +100,6 @@
- _ALBUMS_BALISE_PAGINATION_VIGNETTES
]
<BOUCLE_modele_album(ALBUMS) {id_album}>
[(#REM) Rétrocompatibilité : rustines pour les paramètres dépréciés, à supprimer un jour ]
[(#ENV{titre}|in_array{#LISTE{oui,true}}|oui)
[(#EVAL{null}|setenv{titre})]
@ -100,22 +110,30 @@
[(#EVAL{null}|setenv{label})]
]
[(#REM) Compat numéros séparés par des virgules si id_document ]
[(#ENV{id_document}|oui)
[(#ENV{id_document}|is_array|?{#ENV{id_document},#ENV{id_document}|explode{','}}|setenv{id_document})]
]
[(#REM) Sens du tri des documents ]
#SET{tri_sens,#ARRAY{
date, #ENV{sens,-1},
media, #ENV{sens,1},
fichier, #ENV{sens,1},
extension, #ENV{sens,1},
titre, #ENV{sens,1},
num titre, #ENV{sens,1},
sinum titre,#ENV{sens,1},
id_document,#ENV{sens,1},
rang_lien, #ENV{sens,1},
}}
#SET{tri_defaut,#ENV{id_document}|?{sinum titre,rang_lien}}
[(#REM) Contenu de la légende ]
#SET{legende, #ARRAY{
titre, #ENV{titre,#TITRE*},
descriptif, #ENV{descriptif,#DESCRIPTIF*},
credits, #ENV{credits,#CREDITS*}
titre, #ENV*{titre,#INFO_TITRE*{album,#ENV{id_album}}},
descriptif, #ENV*{descriptif,#INFO_DESCRIPTIF*{album,#ENV{id_album}}},
credits, #ENV*{credits,#INFO_CREDITS*{album,#ENV{id_album}}}
}}
[(#REM) Divers ]
@ -123,26 +141,38 @@
#SET{classe_caption, #ENV{position_legende}|sinon{#CONST{_ALBUMS_POSITION_LEGENDE}}}
#SET{classe_legacy, vignettes}
[(#REM) Params calculés d'après le contexte ]
#SET{params,#ALBUM_PARAMS}
[(#REM) Rustine : pour contourner des problèmes de jointure auto avec objet + id_objet, on fait le where à la main + critère {documents_album} ]
#SET{where,#VAL{' AND '}|join{#LISTE{
#ENV{objet}|?{#VAL{documents_liens.objet=}|concat{#ENV{objet}|sql_quote}},
#ENV{id_objet}|?{#VAL{documents_liens.id_objet=}|concat{#ENV{id_objet}}}
}|array_filter}
<B_documents_modele_album>
<figure
role="group"
class="album album_model[ album_(#ALBUM_PARAMS{disposition})][ album_(#ALBUM_PARAMS{images}|?{images,mixed})][ album_caption-(#GET{classe_caption})][ (#ENV{classe})][ (#ENV{align})][ (#GET{classe_legacy})]"
id="modele_album#ID_ALBUM"
class="album album_model[ album_(#GET{params/disposition})][ album_(#GET{params/images}|?{images,mixed})][ album_caption-(#GET{classe_caption})][ (#ENV{classe}|attribut_html)][ (#ENV{align})][ (#GET{classe_legacy})]"
id="modele_album_[(#GET{params/uniqid})]"
>
<B_documents_modele_album>
#ANCRE_PAGINATION
<ul class="album__items">
<BOUCLE_documents_modele_album(DOCUMENTS)
{id_album}
{tri #ENV{par,rang_lien}, #GET{tri_sens}}
{par sinum titre, date, id_document}
{documents_album}
{id_album?}
{where #GET{where}}
{id_document?}
{tri #ENV{par,#GET{tri_defaut}}, #GET{tri_sens}}
{media?}
{extension?}
{tout}
{pagination #GET{pagination} album#ID_ALBUM}
{pagination #GET{pagination} album#GET{params/uniqid}}
{si #ENV{id_album}|ou{#ENV{objet}}|ou{#ENV{id_document}}}
>
#SET{classe_ratio,#ALBUM_PARAMS{recadrer_ratio}|sinon{#LARGEUR:#HAUTEUR}|albums_classe_ratio{#MEDIA}}
<li class="album__item[ album__item_(#MEDIA)[ album__item_[(#MEDIA)]_(#EXTENSION)]][ (#GET{classe_ratio})]">
#SET{classe_ratio,#GET{params/recadrer_ratio}|sinon{#LARGEUR:#HAUTEUR}|albums_classe_ratio{#MEDIA}}
<li class="album__item[ album__item_(#MEDIA)[ album__item_[(#MEDIA)]_(#EXTENSION)]][ (#GET{classe_ratio})]" data-rang="#RANG_LIEN">
[(#REM) Modèle standard de document avec des ajustements pour les albums ]
#ALBUM_DOC
</li>
@ -150,7 +180,6 @@
</ul>
[<nav class="album__pagination pagination">(#PAGINATION{#ENV{pagination_type}})</nav>]
</B_documents_modele_album>
[(#ENV{masquer_legende}|non|et{#GET{legende}|array_filter}|oui)
<figcaption class="album__caption spip_doc_legende">
@ -161,5 +190,4 @@
]
</figure>
</BOUCLE_modele_album>
</B_documents_modele_album>

237
modeles/album_fonctions.php

@ -3,7 +3,7 @@
/**
* Fonctions utiles au modèle album
*
* Contient notamment des balises destinées uniquement au modèle standard
* Contient principalement des balises destinées au modèle standard
*
* @plugin Albums
* @copyright 2014
@ -22,15 +22,14 @@ if (!defined('_ECRIRE_INC_VERSION')) {
* Compile la balise `#ALBUM_DOC` qui retourne le code HTML
* d'un modèle de document ajusté pour les albums.
*
* Utilise en général un modèle standard sur lequel on ajoute des attributs
* et effectue des traitements sur les images.
* Utilise en général un modèle standard `#DOC` auquel on ajoute des attributs
* et applique des traitements d'images.
*
* Le choix du modèle et les traitements dépendent de la disposition de l'album et du contexte.
*
* S'utilise uniquement dans une boucle documents imbriquée dans une boucle album.
* S'utilise uniquement dans une boucle documents ou documents_liens.
*
* @uses calculer_album_doc()
* @uses calculer_album_params()
* @balise
* @example
* ```
@ -48,20 +47,12 @@ function balise_ALBUM_DOC_dist($p) {
// La boucle document
$index = index_boucle_mere($p); // <BOUCLE_truc> → _truc
$boucle = $p->boucles[$index] ?? null;
$cle_objet = $p->boucles[$index]->primary ?? null; // id_document
// La boucle album parente
$index_parent = $boucle->id_parent ?? null;
$boucle_parent = $p->boucles[$index_parent] ?? null;
$cle_objet_parent = $p->boucles[$index_parent]->primary ?? null; // id_album
// ids
$_id_document = champ_sql($cle_objet, $p);
$_id_album = champ_sql($cle_objet_parent, $p);
$type = $p->boucles[$index]->type_requete ?? null; // documents_liens
// Erreur squelette si hors boucle
$msg = null;
if (
$cle_objet !== 'id_document'
or $cle_objet_parent !== 'id_album'
!$boucle
or !in_array($type, ['documents', 'documents_liens'])
) {
erreur_squelette(
[
@ -74,25 +65,19 @@ function balise_ALBUM_DOC_dist($p) {
// Infos sur le document
$_document = "[
'id_document' => $_id_document,
'id_document' => " . champ_sql('id_document', $p) . ",
'media' => " . champ_sql('media', $p) . ",
'titre' => " . champ_sql('titre', $p) . ",
'descriptif' => " . champ_sql('descriptif', $p) . ",
'credits' => " . champ_sql('credits', $p) . ',
]';
// Infos sur l'album
// $_contexte = "\$Pile[0]['args'] ?? []"; // uniquement présent avec #MODELE ?
$_contexte = '$Pile[0]';
$_params = "calculer_album_params($_id_album, $_contexte)";
$_album = "array_merge(
[
'id_album' => $_id_album,
],
$_params
)";
$p->code = "calculer_album_doc($_document, $_album)";
// Contexte
// Les params passés au modèle sont parfois dans une clé `args`, on met à plat
$_contexte = "array_merge(\$Pile[0] ?? [], \$Pile[0]['args'] ?? [])";
$_contexte = "nettoyer_contexte_modele_album($_contexte)";
$p->code = "calculer_album_doc($_document, $_contexte)";
$p->interdire_scripts = false;
return $p;
}
@ -101,35 +86,37 @@ function balise_ALBUM_DOC_dist($p) {
/**
* Fonction privée pour calculer le HTML de la balise #ALBUM_DOC
*
* @see calculer_album_params()
* @uses calculer_album_params()
* @uses calculer_id_modele_album()
*
* @param array $document
* Tableau d'infos sur le document
* array<int id_document, string media, int largeur, int hauteur>
* @param array $album
* Tableau d'infos sur l'album et ses paramètres
* array<int id_album, >
* @param array $contexte
* Contexte d'appel du modèle, sans les trucs par défaut inutiles (date, date_redac, etc.)
* @return string
*/
function calculer_album_doc(array $document, array $album): string {
function calculer_album_doc(array $document, array $contexte): string {
$html = '';
$id_album = (int) $album['id_album'] ?? 0;
$id_document = (int) $document['id_document'] ?? 0;
$id_document = (int) ($document['id_document'] ?? 0);
$media = $document['media'] ?? null;
$titre = trim($document['titre'] ?? null);
$descriptif = trim($document['descriptif'] ?? null);
$credits = trim($document['credits'] ?? null);
// Identifiant unique : id_album ou autre
$uniqid = calculer_id_modele_album($contexte);
// Choix du modèle, et valeurs pour les traitements à appliquer aux images
// Valeurs définies dans calculer_album_params()
$disposition = $album['disposition'];
$modele_doc = $album['modele_doc'];
$largeur = $album['largeur'];
$hauteur = $album['hauteur'];
$recadrer_ratio = $album['recadrer_ratio'];
$recadrer_sens = $album['recadrer_sens'];
$images = $album['images'];
$params = calculer_album_params($contexte);
$disposition = $params['disposition'];
$modele_doc = $params['modele_doc'];
$largeur = $params['largeur'];
$hauteur = $params['hauteur'];
$recadrer_ratio = $params['recadrer_ratio'];
$recadrer_sens = $params['recadrer_sens'];
$images = $params['images'];
// On récupère le modèle en forçant l'ajout d'un lien.
$contexte_modele = [
@ -143,13 +130,24 @@ function calculer_album_doc(array $document, array $album): string {
$classe = "album__doc album__doc_$media album__doc_$modele_doc album__doc_$classe_caption";
$html = ajouter_class($html, $classe);
// Si c'est une disposition destinée aux images,
// ajouter l'attribut rel au lien afin d'avoir une galerie unique pour l'album
// Mediabox : activer si c'est une image
if (
$images === true
and ($pos_href = strpos($html, 'href=')) !== false
$media === 'image'
and $chercher = 'class="'
and ($pos_class = strpos($html, $chercher)) !== false
) {
$attribut_rel = "rel=\"modele_album$id_album\"" ;
$class_box = 'mediabox ';
$html = substr_replace($html, $class_box, $pos_class + strlen($chercher), 0);
// retirer la class hasbox (d'où elle sort ???)
$html = str_replace('hasbox', '', $html);
}
// Mediabox : identifiant de galerie
if (
($pos_href = strpos($html, 'href=')) !== false
) {
// $attribut_rel = "rel=\"modele_album_$uniqid\" ";
$attribut_rel = "data-box-group=\"modele_album_$uniqid\" ";
$html = substr_replace($html, $attribut_rel, $pos_href, 0);
}
@ -165,7 +163,6 @@ function calculer_album_doc(array $document, array $album): string {
}
}
return $html;
}
@ -174,8 +171,6 @@ function calculer_album_doc(array $document, array $album): string {
* Compile la balise `#ALBUM_PARAMS` qui retourne
* soit un ensemble de valeurs utiles au modèle album, soit une seule.
*
* S'utilise dans une boucle album, ou dans une boucle documents imbriquée dans une boucle album.
*
* @uses calculer_album_params()
* @balise
* @example
@ -190,38 +185,14 @@ function calculer_album_doc(array $document, array $album): string {
* Pile complétée par le code à générer
*/
function balise_ALBUM_PARAMS_dist($p) {
// Les params passés au modèle sont parfois dans une clé `args`, on met à plat
$_contexte = "array_merge(\$Pile[0] ?? [], \$Pile[0]['args'] ?? [])";
$_contexte = "nettoyer_contexte_modele_album($_contexte)";
$_param = interprete_argument_balise(1, $p) ?: null;
$etoile = $p->etoile;
// La boucle
$index = index_boucle_mere($p); // <BOUCLE_truc> → _truc
$boucle = $p->boucles[$index] ?? null;
$cle_objet = $p->boucles[$index]->primary ?? null; // id_document / id_album
// La boucle parente
$index_parent = $boucle->id_parent ?? null;
$boucle_parent = $p->boucles[$index_parent] ?? null;
$cle_objet_parent = $p->boucles[$index_parent]->primary ?? null; // id_album
// Erreur si hors boucle album
if (
!$boucle
or (
$cle_objet !== 'id_album'
and $cle_objet_parent !== 'id_album'
)
) {
erreur_squelette([
'zbug_champ_hors_boucle',
['champ' => zbug_presenter_champ($p)]
], $p);
}
$_id_album = champ_sql('id_album', $p);
// $_contexte = "\$Pile[0]['args'] ?? []"; // uniquement présent avec #MODELE ?
$_contexte = '$Pile[0] ?? []';
$_valeur = interprete_argument_balise(1, $p) ?: null;
$p->code = "calculer_album_params((int) $_id_album, $_contexte, $_valeur)";
$p->code = "calculer_album_params($_contexte, $_param)";
$p->interdire_scripts = false;
return $p;
}
@ -237,21 +208,20 @@ function balise_ALBUM_PARAMS_dist($p) {
*
* @uses albums_decrire_dispositions()
*
* @param integer $id_album
* Numéro de l'album
* @param array $contexte
* Environnement du modèle
* Environnement du modèle, sans les trucs par défaut inutiles (date, date_redac, etc.)
* @param string|null $valeur
* Nom d'un paramètre pour ne retourner que celui-ci
* @return array|string
* Soit un tableau de params : array<string disposition, string modele_doc, string recadrer_ratio, string recadrer_sens, int largeur, int hauteur, bool images>
* Soit une la valeur d'un param
* Soit la valeur d'un param
*/
function calculer_album_params(int $id_album, ?array $contexte = [], ?string $param = null) {
function calculer_album_params(array $contexte = [], ?string $param = null) {
// On fait qu'une seule fois le travail par modèle
// On ne fait qu'une seule fois le travail par modèle
static $memory;
$hash = hash('md5', $id_album . json_encode($contexte, JSON_THROW_ON_ERROR)); // le plus rapide en php 8.1 = xxh3
$uniqid = calculer_id_modele_album($contexte);
$hash = hash('md5', $uniqid.json_encode($contexte, JSON_THROW_ON_ERROR)); // le plus rapide en php 8.1 = xxh3
if (isset($memory[$hash])) {
return ($param ? ($memory[$hash][$param] ?? null) : $memory[$hash]);
}
@ -266,6 +236,9 @@ function calculer_album_params(int $id_album, ?array $contexte = [], ?string $pa
// sinon le test avec `??` est invalide. Ou alors changer la façon de tester.
$set = [];
// À toute fin utile
$set['uniqid'] = $uniqid;
// Disposition
// Priorité : params > constante > config > défaut
$disposition_defaut = array_keys($dispositions)[0]; // 1ère de la liste
@ -322,6 +295,68 @@ function calculer_album_params(int $id_album, ?array $contexte = [], ?string $pa
}
/**
* Nettoyer le contexte pour ne garder que les trucs en rapport avec le modèle
*
* Permet de calculer un hash
*
* @param array|null $contexte
* @return void
*/
function nettoyer_contexte_modele_album(array $contexte = []): array {
$exclure = [
'args', 'date', 'date_redac', 'date_default', 'date_redac_default', 'lang', 'dir_racine', 'wysiwyg', 'espace_prive',
];
$contexte = array_filter($contexte, function ($k) use($exclure) {return !in_array($k, $exclure);}, ARRAY_FILTER_USE_KEY);
return $contexte;
}
/**
* Renvoie un identifiant unique pour le modèle
*
* Dépend de la façon dont sont sélectionnés les documents : soit via id_album, soit id_patate, etc.
*
* @param array|null $contexte
* @return string
* - Si album : <id_album>
* - Si objet : <objet>_<id_objet>
* - si documents : documents_<hash>
*/
function calculer_id_modele_album(array $contexte): string {
static $ids;
$hash = hash('md5', json_encode($contexte, JSON_THROW_ON_ERROR)); // le plus rapide en php 8.1 = xxh3
if (isset($ids[$hash])) {
return $ids[$hash];
}
$ids = [];
// Soit un numéro d'album
if ($id_album = $contexte['id_album'] ?? null) {
$id = (string) $id_album;
// Soit un type et un numéro d'objet
} elseif ($objet = $contexte['objet'] ?? null) {
$id_objet = $contexte['id_objet'] ?? null;
$id = "${objet}_${id_objet}";
// Soit des numéros de documents
} elseif ($id_document = $contexte['id_document'] ?? null) {
$id_document = (is_array($id_document) ? $id_document : explode(',', $id_document));
$id_document = hash('md5', implode('-', $id_document));
$id = "documents_$id_document";
} else {
$id = uniqid();
}
// Ajouter le hash du contexte des fois que le même album soit affiché plusieurs fois
// $id = "${id}_${hash}";
$ids[$hash] = $id;
return $id;
}
/**
* Renvoie une classe correspondant à un ratio
*
@ -368,3 +403,27 @@ function albums_classe_ratio(string $ratio): string {
return $classe;
}
/**
* Compile le critère `{documents_album}`
*
* Rustine pour forcer une jointure en LEFT avec les documents liés.
* Des fois le compilo fait du caca : plusieurs jointures sur la même table,
* et ça pète les conditions dans le WHERE.
*
* @param string $idb Identifiant de la boucle
* @param object $boucles AST du squelette
* @param object $crit Paramètres du critère dans cette boucle
* @return void
*/
function critere_DOCUMENTS_documents_album_dist($idb, &$boucles, $crit) {
$boucle = &$boucles[$idb];
$id_table = $boucle->id_table; // documents
$primary = $boucle->primary; // id_document
$table_join = 'documents_liens';
$table_sql_join = "spip_$table_join";
$boucle->from[$table_join] = $table_sql_join;
$boucle->from_type[$table_join] = 'LEFT';
$boucle->join[$table_join] = ["'$id_table'","'$primary'","'$primary'"];
}
Loading…
Cancel
Save