Hi Pierre,
Thanks for the (very detailed) reply.
On 08/10/2008, at 12:02 AM, Pierre Andrews wrote:
Hello Thomas,
There is an article in french that is a bit more detailled here:
Accés SPIP aux tables non-SPIP et jointures - SPIP-Contrib
Yet another interesting document I missed. From now on, the spip-contrib.net "site plan" and my web-browser's find function will be my first port of call. I'm learning more and more French search terms every day. 
For creating tables of your own, it is quite easy with spip 1.9.2 and 2.0 as SPIP will gladly do Everything for you if you tell him the schema of the table.
For an example, check out the plugin:
http://trac.spip.org/trac/spip-zone/browser/_plugins_/_dev_/basefiltrageip
it is unfinished, but has the table declaration/creation already done.
First thing to do is create a description of the schema of the table;
This is reasonably straight forward.
Then you declare the relations between them (joints):
http://trac.spip.org/trac/spip-zone/browser/_plugins_/_dev_/basefiltrageip/base/basefiltrageip_db.php#L52
The joints is what you want to use to tell SPIP that your new keywords/documents tables relate to your new object. For example, in spip by default, you have:
$tables_jointures['spip_articles']= 'mots_articles';
$tables_jointures['spip_articles']= 'auteurs_articles';
$tables_jointures['spip_articles']= 'documents_articles';
Does this tell SPIP to join spip_articles with spip_mots_articles? Or to join spip_articles to spip_mots THROUGH spip_mots_articles?
Also: can you explain why the key have 'spip_' and the values do not? If I understood the reasons for these sorts of differences, I think I'd be less confused.
You can also define more "complex" joint criterion with:
global $exceptions_des_jointures;
$exceptions_des_jointures['titre_mot'] = array('spip_mots', 'titre');
$exceptions_des_jointures['type_mot'] = array('spip_mots', 'type');
and also the name of the loop for the table:
http://trac.spip.org/trac/spip-zone/browser/_plugins_/_dev_/basefiltrageip/base/basefiltrageip_db.php#L55
(if you do not do this table_des_tables thing, then SPIP doesn't know that BOUCLE_(XXX) is about the table spip_xxx)
If I use the code:
$table_des_tables['xxx'] = 'yyy';
Does this mean that loop XXX is about table yyy, or that loop YYY is about table xxx?
Once you do that, you should tell the plugin how to install itself when it's activated:
http://trac.spip.org/trac/spip-zone/browser/_plugins_/_dev_/basefiltrageip/plugin.xml#L25
This tells spip to call the functions in
/basefiltrageip_upgrade.php
This file should contain a function:
function prefix_install($action)
The function can be called with 3 actions:
- $action=='test' every time the plugin admin page is loaded (hence, it should be light) and should return true if the plugin is installed properly and up to date and false otherwise
- $action=='install' will be called if the test returned false. In this case, the plugin should install or upgrade itself (i.e. create tables, etc. etc.)
- $action=='uninstall' is called when the user click the uninstall button (and not when he deactivates the plugin). This should remove everything the plugin installed (i.e. drop tables)
This is pretty clear from the documentation and examples. Thanks.
Here, the interesting part is the install part:
http://trac.spip.org/trac/spip-zone/browser/_plugins_/_dev_/basefiltrageip/base/basefiltrageip_upgrade.php#L7
This is where tables should be created/updated, this can be done by spip automatically (as the code exists to do it for spip tables), just do:
include_spip('base/basefiltrageip_db'); include_spip('base/create');
include_spip('base/abstract_sql');
creer_base();
creer_base will create the tables... or upgrade them according to the description in $tables_principales.
(beware: this will also upgrade the other tables described in $tables_principales at the time of call...)
This is what I was thinking (in my reply to George's link to the Boucles_sans_tables plugin). Does SPIP just check that the tables exist? Or does it check the schema (columns, types, etc) as well?
Once you have done all of this, then you can loop on your new tables withou declaring any criterion or any tags functions as SPIP knows how to map them to the SQL schema. If you want special processing (propre, etc.) applied to a field before returning it as a tag, you can do:
$table_des_traitements['TEXTE']= 'propre(%s)';
the second is for specifying a particular processing for a field in one specific table. (see ecrire/public/interfaces.php)
So this means that #TEXTE (which comes from the `texte` column) will be processed with propre(). Can I do:
$table_des_traitements['TEXTE']= 'propre(%s)';
$table_des_traitements['TEXTE']= 'translate_to_pirate(%s)';
To do propre(), then translate_to_pirate()? Or does that need a single line like be 'translate_to_pirate(propre(%s))'? If I only want to process `spip_things.texte` is it like this?:
$table_des_traitements['TEXTE']['things']= 'translate_to_pirate(%s)';
You can also define more complex criterion and tags by defining functions if you do not want more than a processed SQL field (like #INTRODUCTION etc.). This has a bit more documentation and example around (in french
):
CreerSaBalise
http://www.spip-contrib.net/NouvelleBalise
I haven't seen these pages, but the code for balise_INTRODUCTION_dist() was pretty clear.
See http://trac.spip.org/trac/spip-zone/browser/_plugins_/_stable_/FpipR/1.9.2/balise for a bunch of basic examples (this plugin has also examples of new loops).
A new tag is created by making a file
balise/new_tag.php
in your plugin directory and defining the function. Here is an example from the FpipR plugin:
<?php
function balise_ISFAMILY_dist($p) {
$isfamily = champ_sql('isfamily',$p);
$id_photo = champ_sql('id_photo',$p);
$p->code = "(($isfamily)?$isfamily:FpipR_photos_getPerms($id_photo,'isfamily'))";
return $p;
}
?>
The tricky part to understand here is that this function is executed when the template cache is computed... hence, you will NEVER have real values from a specific instance in the function. This code is executed BEFORE any call to the sql database is done and before the loop is executed.
The balise_XXX is responsible for computing php code that will be executed when the loop is executed. The code can be static code when it doesn't depend on the loop context (i.e. db fields), or it can be php code that will be executed when the html cache is computed.
Also note that the code you return will be used to compute the html cache, so it cannot depend on specific form entries from the user etc.. in that case, you need to create a form tag which is a whole different story 
I'll need to figure out how to create dynamic tags later on, but I've seen a few example of that, so it shouldn't be too bad. 
Anyway, back to the example...
- champ_sql returns code to get the value of a sql field (but does not yet contain that value) in the table of the loop where the tag is used. In the example, we get the fields isfamily and id_photo.
- $p->code contains the code you want to execute later when the loop is executed. A good thing to do here is avoid putting complex code (you will get mixup in quotting, etc. etc.) but make a function in you <function> file of the plugin that will do the hard job. For example, here we call: FpipR_photos_getPerms($id_photo,'isfamily')
there are other more complex things you can do with $p, I let you see the examples around spip-zone and in http://trac.rezo.net/trac/spip/browser/branches/spip-1.9.2/ecrire/public/balises.php
You can see the resulting code by adding var_mode=debug and choosing the code tab. It is very useful to experiment and try things to see what happens.
I will let you experiment with all these and send a later mail about the criterion.
Thanks again for the information. Reading the code is fine, but it's much better when someone explains it.
Pierre
PS: So, you have an internal documentation wiki? why not just directly having it public on doc.spip.org and spip-contrib wiki? it will help everyone 
We use a wiki to document the way we do things at Bouncing Orange, including the way we use SPIP. Most of the SPIP pages are written when we've just figured out how to do something after fighting with SPIP for an hour or two, so there's sometimes a little bad language involved.
There are a few things in there that might be useful to other SPIP users, so I'll see if I can find some time to clean-up and post a few articles.
Cheers,
Thomas Sutton
Web Developer
bouncingorange
graphic + web design