Carnet Wiki

MultiBase

Version 23 — Août 2008 — 145.242.xx.xx

<blockquote class="spip">

Voir aussi : : Acces-SPIP-aux-tables-externes-et : : AutreTableSpip : : JonctionEntreTables

</blockquote>

Qu’est-ce que SPIP peut faire avec une table externe mais qui nécessite une déclaration explicite avec SPIP 193 ?

[oct 2007]

Sans déclaration explicite, on peut
-  boucler sur une table externe
-  faire une jointure avec une autre table sur critère « champs de même nom et même valeur ».

Booz & ESJ précisent que faire une déclaration explicite permet de :

-  faire des jointures particulières

-  déclarer des critères logiques (plus sophistiqués que juste le nom du champs)

-  brancher les « crayons » sur ta table, pour édition rapide.

-  indexer avec le moteur de recherche en bricolant un peu.

-  gérer les conflits entre plugins
exemple : spip-listes vérifie si inscription2 est là avant de s’installer et procède
differemment selon que inscription2 est là ou pas

-  la sauvegarde
et la création des tables aussi,

-  l’install / désinstall d’un plugin.

-  ne pas mettre le préfixe dans le nom de la table (pour boucler dessus -> on peut utiliser le nom logique)
[/oct 2007]


version 1.9.3 - Déclarer une table SPIP ou non SPIP d’une autre base de données

<blockquote class="spip">

Pour la version 1.9.3, tout est automatique :
-  pour interroger la base ’mabase’ à partir d’un site SPIP local, il suffit d’avoir dans le répertoire config du site local un fichier nommé mabase.php. Dans le cas d’une autre base administrée par SPIP, ce fichier est tout simplement une copie
du connect.php du site distant. On peut aussi utiliser une installation mutualisée ayant un seul répertoire pour ces fichiers, afin de disposer directement des originaux (qui ne s’appellent donc plus connect.php mais leur contenu ne change pas).
Hormis ce cas particulièrement simple, le formulaire d’installation de SPIP permet à présent de déclarer ces bases, ce qui provoque la création du fichier de connexion dans le répertoire config ou son équivalent.
-  il suffit alors d’écrire les boucles <BOUCLE_n(B:ARTICLES)>

Remarques :
-  B est donc le nom du fichier de connexion sans l’extension,
-  comme le compilateur s’appuie sur le nom du fichier pour faire les appels distants, si le serveur est sensible à la casse alors le compilateur aussi.


Références :
-  SVN10559
-  SVN10463
-  SVN10183
-  SVN10133
-  SVN10113

Pour se connecter à la base ’mabase’, du serveur ’monserveur.quelque.part’, sur le port , ce fichier contient la ligne :

<?php spip_connect_db('monserveur.quelque.part',0,'login','motdepasse','mabase','mysql','prefixe'); ?>

Le préfixe n’est présent que s’il s’agit d’un site sous SPIP, n’utilisant pas le préfixe standard ’spip’. En outre, si la variable spip_connect_version est affectée dans ce fichier, le site local considérera que cette base externe est une base SPIP, et interprétera les noms de boucles et les noms de balises comme pour le site local. Toutefois, une base externe ne donne pas accès aux balises #EDIT{...} (les crayons), ni à celles sur les logos (#LOGO_ARTICLE etc) ni enfin aux vignettes personnalisées déclarées dans cette base. En outre, les seuls raccourcis SPIP interprétés seront ceux connus du site local. De même, il faut bien comprendre que le site appelé est considéré comme ayant les mêmes déclarations de tables que le site appelant, ce qui n’est pas toujours le cas (par exemple, depuis SVN10203, autrement dit spip_version == 1.950, plus aucune table n’a de champ nommé « url_propre », remplacés par une nouvelle table « spip_urls » ; un squelette bi-base dans ce cas ne pourrait pas présenter les urls propre du site appelé).

</blockquote>

Version 1.9.2 - Déclarer une table SPIP ou non SPIP d’une autre base de données

À 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>
&lt;/cadre &lt;/code >
qui va lister tous les titres de la table article du serveur site-annexe
&lt;cadre code >
<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.


Exemple : spipcarto

[oct 2007]

stephane du rezo.net a (d)écrit :

<blockquote class="spip">

En 1.9.2, pour la table spip_carto_cartes de spip carto par exemple, ca
donne (dans mes_fonctions) :

$spip_carto_cartes = array(
	"id_carto_carte" => "bigint(21) NOT NULL",
	"titre" => "VARCHAR(255) BINARY NOT NULL",
	"texte" => "TEXT BINARY NOT NULL",
	"url_carte" => "TEXT BINARY NOT NULL",
	"callage" => "TEXT BINARY NOT NULL",
	"id_srs" => "bigint(21) NOT NULL",
	"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL");


$spip_carto_cartes_key = array(
	"PRIMARY KEY" => "id_carto_carte");


GLOBALS['tables_principales']['spip_carto_cartes'] =
	array('field' => &$spip_carto_cartes, 'key' => &$spip_carto_cartes_key);


$GLOBALS['table_des_tables']['carto_cartes']="carto_cartes";


$GLOBALS['table_primary']['carto_cartes']="id_carto_carte";
// (ce dernier est peut etre obsolete maintenant, je ne sais plus)

enfin, avec ca, c’est sauvegardé et je peux faire :

<BOUCLE1(CARTO_CARTES)>
  <a href="#URL_CARTE">#TITRE</a>
  <p>#TEXTE</p>
</BOUCLE1>
</blockquote>

[/oct 2007]


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;
</code><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><code>
$tables_des_serveurs_sql['basilic']['bauthors'] = array(
                         'field' => &$basilic_authors,
                         'key' => &$basilic_authors_key);
</code><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 config/inc_connect-basilic.php:
<code>
<?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...