Carnet Wiki

MultiBase

Version 7 — Août 2007 — 193.252.xx.xx

Déclarer une table SPIP ou non SPIP d’un autre serveur MYSQL

Pour la version 1.9.3 et suivante, se référer pour l’instant à http://trac.rezo.net/trac/spip/chan... et http://trac.rezo.net/trac/spip/chan...

À partir de la version 1.9.2, il est possible, non seulement de lire d’autres tables SQL que celles propres à Spip, mais également d’aller lire des tables présentes sur d’autres serveurs, typiquement d’autres sites sous SPIP mais pas seulement.

Pour ce faire, la syntaxe des types de boucles est étendue avec la notation suivante :

<BOUCLE_EXT(site-annexe:ARTICLES)>#TITRE</BOUCLE_EXT>

qui va lister tous les titres de la table article du serveur site-annexe

<BOUCLE_AUTREXEMPLE(site-pas-mal-non-plus:CATALOGUE)>
</BOUCLE_AUTREXEMPLE>
<br>#TOTAL_BOUCLE au catalogue
</B_AUTREXEMPLE>

qui va ramener le nombre d’entrées de la table CATALOGUE du serveur « site-pas-mal-non-plus ».

Pour arriver à ce résultat il faut toutefois déclarer les nouveaux serveurs avec leur identifiant de connexion.
Chacun est déclaré dans un fichier portant son nom, préfixé par « inc_connect- » et suffixé par « .php » ou « .php3 », le fichier étant placé dans config (donc ci-dessus, il faut config/inc_connect-site-annexe.php).
Ce fichier doit contenir (au minimum) ces 6 fonctions (où nom est à nouveau le nom du serveur) :

-  function base_nom() qui retourne un lien vers le serveur
-  function spip_query_nom($query) équivalente à spip_query_db dans le serveur usuel
-  function spip_nom_fetch($res) équivalente à spip_fetch_array (i.e. mysql_fetch_array) dans le serveur usuel
-  function spip_nom_count($res) équivalente à spip_num_rows (i.e. mysql_num_rows) dans le serveur usuel
-  function spip_nom_free($res) équivalente à spip_free_result (i.e. mysql_free_result) dans le serveur usuel
-  function spip_nom_select($select, $from, $where, $groupby, $orderby, $limit, $sousrequete, $cpt, $table, $id, $serveur) équivalente à spip_mysql_select dans le serveur actuel (i.e. mysql_query après un pré-traitement non négligeable).

Les fonctions du serveur usuel figurent dans ecrire/base/db_mysql.php et on s’en inspire pour écrire les nouvelles, ainsi que de config/connect.php pour la gestion des identifiants de connexion. Un exemple concret suit.

Ce fichier sera lu à l’exécution de la première boucle référençant ce serveur, et ne sera plus lu par la suite ; on y placera donc l’ouverture de la connexion.

Si le site annexe est sous un Spip de même numéro de version, cela suffit car la description des tables du serveur principal servira à interroger celles du serveur distant.

En revanche, si l’on veut en plus accéder à des tables non spip spécifiques, il faut les ajouter à la globale $tables_principales, ainsi :

$spip_title = array(
        "id"        => "bigint(21) NOT NULL",
        "title"        => "text NOT NULL"
);
$spip_title_key = array(
        "PRIMARY KEY"                => "id"
);
$GLOBALS['tables_principales']['title']= array('field' => &$spip_title, 'key' => &$spip_title_key);

Spip procède à la lecture d’un fichier spécifique à chaque squelette : si le squellette s’appelle S, Spip lira le fichier S_fonctions.php (à mettre au même endroit que le squelette) avant chaque éxécution du squelette compilé (et juste avant sa compilation éventuelle).

On mettra donc dans ce fichier la description des tables comme ci-dessus, ainsi que les filtres spécifiques au squelette si l’on veut soulager mes_fonctions.php(3) (qui reste lu au départ néanmoins).

Dans le cas d’un squelette appelant systématiquement une base externe « mabase », on pourra également mettre les fonctions qu’il utilise dans le fichier config/inc_connect-mabase.php qui est lu à la connexion.
-  

Un exemple concret

(Phil.Martin@inrialpes.fr)

-  J’ai une autre base appelée « basilic ».

-  Dans cette base, une table « authors » avec les champs id, first, last et url. La description de la table « authors » est obtenue avec l’ordre MySQL « DESCRIBE authors », ou graphiquement avec phpMyAdmin en affichant sa structure.

-  Si je n’utilise cette base que dans le squellette S, je mets la description des tables dans le fichier S_fonctions.php, sinon dans mes_fonctions.php. On transforme les données de description dans un tableau php et on rajoute une boucle au nom explicite, ce qui donne le code suivant :

<?php
global $tables_des_serveurs_sql;
$basilic_authors = array (
                           "id" => "INTEGER NOT NULL",
                           "first" => "VARCHAR(30) NOT NULL",
                           "last" => "VARCHAR(30) NOT NULL",
                           "url" => "VARCHAR(100) NOT NULL",
                           );
$basilic_authors_key = array(
                           "PRIMARY KEY" => "id"
                           );
$tables_des_serveurs_sql['basilic']['bauthors'] = array(
                         'field' => &$basilic_authors,
                         'key' => &$basilic_authors_key);
function boucle_BAUTHORS_dist($id_boucle, &$boucles) {
 $boucle = &$boucles[$id_boucle];
 $id_table = $boucle->id_table;
 $boucle->from[] =  "authors AS $id_table";
 return calculer_boucle($id_boucle, $boucles);
}
?>

-  Créer le fichier config/inc_connect-basilic.php :

<?php
  if (defined("_ECRIRE_INC_CONNECT_AUTHORS")) return; 
define("_ECRIRE_INC_CONNECT_AUTHORS", "1"); 
 
global $spip_authors_link, $spip_authors_db;
// pour connexions multiples 
 
$spip_authors_link = @mysql_connect('mon_serveur','mon_login','mon_mot_de_passe'); 
$spip_authors_db = "authors"; 
@mysql_select_db($spip_authors_db); 
 
// Cf base_db_mysql_dist dans ecrire/base/db_mysql.php 
function base_authors() 
{ 
  return $GLOBALS['spip_authors_link']? 'spip_query_authors' : false; 
} 
 
function spip_query_authors($query) { 
 
$query = traite_query($query);


return                  mysql_query($query, $GLOBALS['spip_authors_link']); 
} 
 
// http://doc.spip.org/@spip_abstract_select 
function spip_authors_select($select, $from, $where, 
                  $groupby, $orderby, $limit, 
                  $sousrequete, $having, 
                  $table, $id, $serveur) { 
  
  $res = spip_mysql_select($select, $from, $where, 
                                       $groupby, $orderby, $limit, 
                                          $sousrequete, $having, 
                                            $table, $id, $serveur); 
     return $res; 
 
} 
 
// http://doc.spip.org/@spip_abstract_fetch 
function spip_authors_fetch($res) { 
  return spip_fetch_array($res); 
} 
 
// http://doc.spip.org/@spip_abstract_count 
function spip_authors_count($res) { 
  return spip_num_rows($res); 
} 
 
// http://doc.spip.org/@spip_abstract_free 
function spip_authors_free($res) { 
  return spip_free_result($res); 
} 
 
// http://doc.spip.org/@spip_mysql_insert 
function spip_authors_insert($table, $champs, $valeurs) { 
return  spip_mysql_insert($table, $champs, $valeurs); 
} 
 
// http://doc.spip.org/@spip_abstract_showtable 
function spip_authors_showtable($res) { 
  return spip_mysql_showtable($res); 
}
?>


-  Une boucle :
<BOUCLE_auteur(basilic:BAUTHORS)>#ID #FIRST #LAST</BOUCLE_auteur>

Ce qui ne marche pas encore :

— -

-  les balises formulaires, parce qu’elles appellent des fonctions annexes qu’il faut reprendre une à une : on ne peut donc faire apparaitre sous un site Spip le formulaire de la pétition déclarée sur un autre site ;
-  la seule requête gérée est SELECT, il n’est pas question d’alimenter le forum d’un site distant car cela nécessite un UPDATE ou un INSERT ; en contre-partie, il n’est pas nécessaire d’avoir le ALL PRIVILEGES sur la base lue, un accès en lecture suffit ;
-  l’interface permet a priori d’interroger d’autres serveurs que MySQL ; j’ai procédé à des essais avec Postgres, ça marche pour des boucles sans critères comme celles ci-dessus, mais le compilateur actuel traduit les critères par des idiosyncrasies MySQL qu’il faut retraduire au niveau de spip_postgres_select, il y a encore du travail.
-  le debugger de squelette aura peut-etre besoin d’etre debugé quant à sa gestion de ces nouveaux venus...