Carnet Wiki

Créer une boucle sur une nouvelle table

On peut créer ses propres boucles dans SPIP.

En l’absence de code spécifique, SPIP interprète le nom de la boucle comme le nom d’une table, et les balises comme les noms de ses champs.
Par exemple, si je crée une table mammiferes avec des champs id_mammifere, nom et famille :

CREATE TABLE `spip_mammiferes` (
  `id_mammifere` int(11) NOT NULL auto_increment,
  `nom` varchar(255) default NULL,
  `famille` varchar(255) default NULL,
  `statut` ENUM ('prepa', 'publie', 'poubelle'),
  PRIMARY KEY  (`id_mammifere`)
);
INSERT INTO `spip_mammiferes` (nom, famille, statut) VALUES ('dauphin', 'cétacés', 'publie');
INSERT INTO `spip_mammiferes` (nom, famille, statut) VALUES ('lapin', 'lagomorphes', 'prepa');
INSERT INTO `spip_mammiferes` (nom, famille, statut) VALUES ('singe', 'primates', 'publie');

alors je peux écrire directement le squelette suivant :

<BOUCLE_test(SPIP_MAMMIFERES){id_mammifere=3}>
  Le #NOM appartient à la famille des #FAMILLE.
</BOUCLE_test>

Pour pouvoir utiliser une table sans le préfixe _spip, on la déclare dans l’interface table_des_tables :

<pipeline>
  <nom>declarer_tables_interfaces</nom>
  <inclure>monprefixe_pipelines.php</inclure>
</pipeline>
function monprefixe_declarer_tables_interfaces($interfaces)
{
  $interfaces['table_des_tables']['mammiferes'] = 'mammiferes';
  return $interfaces;
}

On peut alors écrire :

<BOUCLE_test(MAMMIFERES){id_mammifere=3}>
  Le #NOM appartient à la famille des #FAMILLE.
</BOUCLE_test>

Noter que les boucles sont prévues pour accéder à des tables SQL et à leurs champs ; l’utiliser dans d’autres contextes est possible, mais relève de l’acrobatie et est donc forcément limité. Lorsque vous introduisez de nouvelles structures de données dans SPIP, il y a des chances que vous deviez les adapter à ce concept de boucles agissant sur une table, plutôt que d’essayer d’utiliser la boucle hors de son champ normal d’application.

On peut affiner le comportement de la boucle en déclarant une fonction boucle_MABOUCLE_dist ou critere_MABOUCLE_moncritere_dist. Le plus simple est d’inclure ces déclarations dans un fichier <fonction> de plugin.xml (chargé à chaque recalcul), par exemple :

 <fonctions>public/monprefixe_boucles.php</fonctions>
function boucle_MABOUCLE_dist($id_boucle, &$boucles)
{
  $boucle = &$boucles[$id_boucle];
  // ...
  return calculer_boucle($id_boucle, $boucles); 
}
  • $id_boucle : identifiant de la boucle, ex : _mesarticles pour une boucle <BOUCLE_mesarticles>.
  • &$boucles : tableau de toutes les boucles de la page, indexées par leur identifiant. Ce sont des objets SPIP complexes et internes. On utilisera typiquement $boucle = &$boucles[$id_boucle];. Noter que les champs vont être
    • $boucle->id_table : le nom de la table détecté par SPIP
    • $boucle->primary : la clef primaire, apparemment auto-détectée
    • $boucle->select : un tableau avec le nom de champs à récupérer ; SPIP le remplit par défaut avec la liste des balises trouvées dans la boucle
    • $boucle->from :
    • $boucle->from_type :
    • $boucle->where :
    • $boucle->join :
    • $boucle->having :
    • $boucle->limit :
    • $boucle->group :
    • $boucle->order :

Par exemple, pour filtrer les mammifères non-publiés :

function boucle_MAMMIFERES_dist($id_boucle, &$boucles)
{
  $boucle = &$boucles[$id_boucle];
  
  $id_table = $boucle->id_table;
  $mstatut = $id_table .'.statut';
  $boucle->where[] = array("'='", "'$mstatut'", "'\\'publie\\''");
  
  return calculer_boucle($id_boucle, $boucles);
}

Noter qu’un objet boucle est déjà présent au moment où l’on entre dans notre fonction. Il ne reste plus qu’à le compléter.

Remarque : La fonction index_boucle ramène l’index de la boucle.

$b = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
if ($table = $p->boucles[$b]->type_requete) {
  ...
}

gagne à être remplacée par

$b = index_boucle($p);
if (
  isset($p->boucles[$b])
  and $table = $p->boucles[$b]->type_requete
) { 
  ... 
}

Étape suivante : on souhaite accéder à des champs d’autres tables dans la boucle. Imaginons que nous voulons dire qui a photographié un mammifère, et pouvoir filtrer uniquement les mammifères de cet auteur :

CREATE TABLE `spip_auteurs_mammiferes` (
  `id_auteur` bigint(21) NOT NULL default '0',
  `id_mammifere` bigint(21) NOT NULL default '0',
  PRIMARY KEY  (`id_auteur`,`id_mammifere`)
);
INSERT INTO spip_auteurs_mammiferes (`id_auteur`, `id_mammifere`) VALUES (1,1);

Si l’on spécifie {id_auteur=1} dans notre boucle, il y a une erreur, car SPIP ne sait pas où chercher id_auteur. Il faut le lui dire explicitement, à nouveau dans le pipeline declarer_tables_interfaces :

function monprefixe_declarer_tables_interfaces($interfaces)
{
  $interfaces['table_des_tables']['mammiferes'] = 'mammiferes';
  
  $interfaces['table_des_tables']['auteurs_mammiferes'] = 'auteurs_mammiferes'; // ou dans declarer_tables_auxiliaires
  $interfaces['tables_jointures']['spip_mammiferes']['id_auteur'] = 'auteurs_mammiferes';
  return $interfaces;
}

Ce qui nous permet par exemple d’écrire dans le squelette :

Les miens:<br />
<BOUCLE_lesmiens(MAMMIFERES){id_auteur=1}{doublons}>
  Le #NOM appartient à la famille des #FAMILLE.<br />
</BOUCLE_lesmiens>
Les autres:<br />
<BOUCLE_lesautres(MAMMIFERES){doublons}>
  Le #NOM appartient à la famille des #FAMILLE.<br />
</BOUCLE_lesautres>

Voir

-  Sur programmer.spip.net : la section Jointures automatiques pour plus de détails.
-  Sur code.spip.net : ecrire/public/compiler.php:public_compiler_dist(...) et ecrire/public/criteres.php:calculter_criteres(...)
-  Des exemples : ecrire/public/boucles.php

JLuc - Mise à jour :27 novembre 2023 à 18h38min