Carnet Wiki

MultiBase

Version 5 — Août 2007 — 82.224.xx.xx

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

Simple copié collé du message de Emmanuel visible également ici http://article.gmane.org/gmane.comp...

À partir de la version 1.9.2 , il Il est à présent 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 server « 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 ecrire (donc ci-dessus, il faut config/inc_connect-site-annexe ecrire/inc_connect-site-annexe .php).
Ce fichier doit contenir ( au minimum ) ces 6 4 fonctions (où nom 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.
- function <code>spip_NOM_fetch($res, $serveur) équivalente à spip_fetch_array (i.e. mysql_fetch_array) dans le serveur usuel
-  function <code>spip_nom_count($res)</code code>spip_NOM_count($res , $serveur)</code > équivalente à spip_num_rows (i.e. mysql_num_rows) dans le serveur usuel
-  function <code>spip_nom_free($res)</code code>spip_NOM_free($res , $serveur)</code > équivalente à spip_free_result (i.e. mysql_free_result) dans le serveur usuel
-  function <code>spip_nom_select($select code>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 4 fonctions du serveur usuel figurent dans <code>ecrire/base/db_mysql code>ecrire/inc_db_mysql .php</code php3</code > et on il faut évidemment s’en inspire inspirer pour écrire les 4 nouvelles, ainsi que de <code>config/connect code>inc-connect .php</code php3</code > 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 peut donc y placera donc placer l’ouverture de la connexion.

Si le site annexe est sous un Spip de même numéro de version, cela suffit doit suffire car la description des tables dans le < code>inc_serialbase</code > 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, par exemple comme je le disais tout à l’heure ainsi :

$spip_title 
&lt; code>$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).

Comme il n’est pas question de placer cette affectation directement dans le fichier inc_serialbase qui ne doit décrire que les tables locales d’une part, et qu’on ne peut indéfiniment charger mes_fonctions.php3 avec des déclarations qui ne sont pas systématiquement utiles, Spip_ procède à présent à la lecture d’un fichier spécifique à chaque squelette : si le squellette s’appelle S, Spip lira le fichier S_fonctions.php3 avant chaque éxécution du squelette compilé (et juste avant sa compilation éventuelle).
On peut donc mettre 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.php3 (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 <code>config/inc_connect-mabase code>ecrire/inc_connect-mabase .php qui est lu à la connexion.
-

Un exemple concret

Bonne expérimentation à tous,

Déclarer une table d’une autre base MySQL

(Phil.Martin@inrialpes.fr)

-  J’ai sur le même serveur MySQL 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 :

- Rajouter dans /mes_fonctions.php3 :

$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"
                          );


<code>
&lt;?php
 global $tables_des_serveurs_sql;

<code >
$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  »
) ;
<code >
$tables_des_serveurs_sql[’basilic’][’bauthors’] = array (
’field array(’field ’ => &$basilic_authors,
’key’ => &$basilic_authors_key) ;
<code >
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) ;

 ?

</
code > >

- Créer le fichier /ecrire/inc_connect-basilic.php3 :

&lt;?php
if (defined("_ECRIRE_INC_CONNECT_BASILIC")) return;
define("_ECRIRE_INC_CONNECT_BASILIC", "1");


@mysql_connect('mon_serveur','','mon_login','mon_mot_de_passe');
@mysql_select_db("basilic");


function spip_basilic_fetch($res, $serveur) {
 return spip_fetch_array ($res, $serveur);
}


function spip_basilic_count($res, $serveur) {
 return spip_num_rows ($res, $serveur);
}


function spip_basilic_free($res, $serveur) {
 return spip_free_result ($res, $serveur);
}


- Créer le fichier config/inc_connect-basilic.php:
<code>
&lt;?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); 
 
$start = ($GLOBALS['mysql_profile'] AND (($GLOBALS['connect_statut'] == '0minirezo') OR ($GLOBALS['auteur_session']['statut'] == '0minirezo'))) ? microtime() : 0; 
 
return spip_mysql_trace($query,  
                        $start, 
                          mysql_query($query, $GLOBALS['spip_authors_link'])); 
} 
 
// http://doc.spip.org/@spip_abstract_select 
 function spip_authors_select($select spip_basilic_select($select , $from, $where, 
                  $groupby, $orderby, $limit, 
                  $sousrequete, $having $cpt , 
                  $table, $id, $serveur) { 
  
  $res  =   spip_mysql_select($select return  spip_mysql_select  ($ select , $from, $where, 
                                       $groupby, $orderby, $limit, 
                                          $sousrequete, $having $cpt , 
                                            $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...

- Le fichier ##inc-compilo-api.php3## nécessite une modification (pour la version du 9 Mai 2005) :

--- $tables_des_serveurs_sql = array('localhost' => &$tables_principales);
+++ $tables_des_serveurs_sql['localhost'] = &$tables_principales;

Déclarer une table d’une autre base MySQL SPIP 1.9

Il y a un bug dans la version stable de la 1.9 il faut appliquer le correctif disponible ici : http://trac.rezo.net/trac/spip/chan...

mes.fonctions.php dans le dossier squelettes :

global $tables_des_serveurs_sql;


$mabase_matable = array (
                                                        "numero" => "INT(11) NOT NULL",
                                                        "prenom" => "CHAR(20)",
                                                        "nom" => "CHAR(20)"
                                                        );                                                       
$mabase_matable_key = array (
                                                        "PRIMARY KEY" => "numero"
                                                        );
$tables_des_serveurs_sql['mabase']['matable'] = array('field' => &$mabase_matable, 'key' => &$mabase_matable_key);

Créer inc_connect-mabase.php dans le dossier ecrire

&lt;?php
if (defined("_ECRIRE_INC_CONNECT_mabase")) return;
define("_ECRIRE_INC_CONNECT_mabase", "1");


@mysql_connect('localhost','login','password');
@mysql_select_db("mabase");


function spip_mabase_fetch($res) {
 return spip_fetch_array($res);
}


function spip_mabase_count($res) {
 return spip_num_rows($res);
}


function spip_mabase_free($res) {
 return spip_free_result($res);
}


function spip_mabase_select($select, $from, $where,
                  $groupby, $orderby, $limit,
                  $sousrequete, $having,
                  $table, $id, $serveur) {
 return spip_mysql_select ($select, $from, $where,
                  $groupby, $orderby, $limit,
                  $sousrequete, $having,
                  $table, $id, $serveur);
}
?>

Example de boucles possibles après ça :

<BOUCLE_example(mabase:MATABLE){numero>50}
#NUMERO #PRENOM #NOM
</BOUCLE_example>

Multi serveur

Depuis la SVN7259, la connexion à plusieurs serveurs est clarifiée. On contrôle exactement comment on lance la requête. Il faut ajouter au fameux fichier ecrire/inc_connect-mabase.php les fonctions base_mabase et spip_query_mabase comme suit :

&lt;?php
  if (defined("_ECRIRE_INC_CONNECT_MABASE")) return;
define("_ECRIRE_INC_CONNECT_MABASE", "1");


global $spip_mabase_link, $spip_mabase_db;	// pour connexions multiples


$spip_mabase_link = @mysql_connect('serveur.sql.distant.fr', 'user_sql', 'mot_de_passe_sql');
$spip_mabase_db = "mabase";
@mysql_select_db($spip_mabase_db);


// Cf base_db_mysql_dist dans ecrire/base/db_mysql.php
// Le nom de la fonction qui requ^ete mabase, false si la connexion a echou'ee
function base_mabase()
{
  return $GLOBALS['spip_mabase_link']? 'spip_query_mabase' : false; 
}


// http://doc.spip.org/@spip_query_db
function spip_query_mabase($query) {


$query = traite_query($query);


$start = ($GLOBALS['mysql_profile'] AND (($GLOBALS['connect_statut'] == '0minirezo') OR ($GLOBALS['auteur_session']['statut'] == '0minirezo'))) ? microtime() : 0;


return spip_mysql_trace($query, 
				$start,
		  mysql_query($query, $GLOBALS['spip_mabase_link']));
}


// http://doc.spip.org/@spip_abstract_select
function spip_mabase_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_mabase_fetch($res) {
  return spip_fetch_array($res);
}


// http://doc.spip.org/@spip_abstract_count
function spip_mabase_count($res) {
  return spip_num_rows($res);
}


// http://doc.spip.org/@spip_abstract_free
function spip_mabase_free($res) {
  return spip_free_result($res);
}


// http://doc.spip.org/@spip_mysql_insert
function spip_mabase_insert($table, $champs, $valeurs) {
	return  spip_mysql_insert($table, $champs, $valeurs);
}


// http://doc.spip.org/@spip_abstract_showtable
function spip_mabase_showtable($res) {
  return spip_mysql_showtable($res);
}


?>

Et encore un autre exemple ! version minimale

Fonctionne assurément avec spip >= 7867 soit SPIP 1.9.2 alpha 2
-  créez un répertoire privé du nom de votre choix à la racine dirdemonchoix
-  déclarez le dans config/mes_options.php comme squelettes d’un autre niveau que vos squelettes
$dossier_squelettes="publicsquelettes:dirdemonchoix";
-  dans ce dossier, mettez inc_connect-mabase.php avec ce qui est spécifié plus haut après > (Depuis la SVN7259 , la connexion à plusieurs serveurs est clarifiée. )
-  il est optionnel de créer dedans le fichier dirdemonchoix_mes_fontions.php en déclarant tables et array, sauf si vous souhaitez des jointures entre vos tables (à ce que j’ai compris) et si vous souhaitez que spip sauve le xml avec ses tables et leur contenu