Carnet Wiki

Créer une boucle sur une nouvelle table

Version 5 — il y a 5 mois Jacques

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 :

 <cadre  class="SQL ">
 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');

</cadre >
alors je peux écrire directement le squelette suivant :

spip 
&lt; BOUCLE_test(SPIP_MAMMIFERES){id_mammifere=3 &lt;cadre  class="spip ">
 &lt;BOUCLE_test(SPIP_MAMMIFERES){id_mammifere=3 }>
  Le #NOM appartient à la famille des #FAMILLE.
&lt;/BOUCLE_test>
 &lt;/cadre >

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

xml 
&lt; pipeline &lt;cadre  class="xml ">
 &lt;pipeline >
  <nom>declarer_tables_interfaces</nom>
  <inclure>monprefixe_pipelines.php</inclure>
&lt;/pipeline>
 &lt;/cadre >

 &lt;cadre  class="PHP ">
 function monprefixe_declarer_tables_interfaces($interfaces)
{
  $interfaces['table_des_tables']['mammiferes'] = 'mammiferes';
  return $interfaces;
}



</
cadre >
On peut alors écrire :

spip 
&lt; BOUCLE_test(MAMMIFERES){id_mammifere=3 &lt;cadre  class="spip ">
 &lt;BOUCLE_test(MAMMIFERES){id_mammifere=3 }>
  Le #NOM appartient à la famille des #FAMILLE.
&lt;/BOUCLE_test>
 &lt;/cadre >

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 :

xml 
 &lt; fonctions>public/monprefixe_boucles &lt;cadre  class="xml ">
  <fonctions>public/monprefixe_boucles .php&lt;/fonctions>
 &lt;/cadre >

 &lt;cadre  class="PHP ">
 function boucle_MABOUCLE_dist($id_boucle, &$boucles)
{
  $boucle = &$boucles[$id_boucle];
  // ...
  return calculer_boucle($id_boucle, $boucles); 
}


</
cadre >

  • $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 :

 &lt;cadre  class="PHP ">
 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);
}


</
cadre >

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.

php 
$ b &lt;code  class="php ">
 $b  = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;
if ($table = $p->boucles[$b]->type_requete) {
  ...
}
</code> gagne à être remplacé par 
<code class="php">
$b = index_boucle($p);
if (
  isset($p->boucles[$b])
  and $table = $p->boucles[$b]->type_requete
) { 
  ... 
}
&lt;/ code > 


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 :

 &lt;cadre  class="SQL ">
 CREATE TABLE `spip_auteurs_mammiferes` (
  `id_auteur` bigint(21) NOT NULL default '',
  `id_mammifere` bigint(21) NOT NULL default '',
  PRIMARY KEY  (`id_auteur`,`id_mammifere`)
);
INSERT INTO spip_auteurs_mammiferes (`id_auteur`, `id_mammifere`) VALUES (1,1);&lt;/cadre > 


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 :<cadre class=« PHP  »>
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 ;

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 :

 &lt;cadre  class="SPIP ">
 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 />
&lt;/BOUCLE_lesautres>
 &lt;/cadre >

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