Lodel + Solr

Posted by Jean-André Santoni on October 3, 2011 · Leave a Comment 

Lodel + Solr

Few months ago, we started a complete rewrite of the new version of Calenda powered by Lodel. The biggest part of the public side of Calenda—programaticaly speaking—is its search engine: this engine is used everywhere, not only on the result pages, but also on the front page and the event page.

Our search engine choice is Lucene/Solr, we already use it to index and provide faceted search on all the contents from Revues.org, Hypotheses.org and the actual Calenda. Solr is fast, powerful, easy to use and to maintain, and supported by a strong community. It also provides a very interesting functionnality: dynamic fields.

Dynamic fields

Here is a detailed explanation about dynamic fields.

Solr configuration file is a simple, almost flat, XML file. Is is called schema.xml.

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.4">

    <types>

        <fieldType name="int" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
        <fieldType name="string" sortMissingLast="true" omitNorms="true"/>

        <fieldType name="text" positionIncrementGap="100">
            <analyzer type="index">
                <tokenizer/>
                <filter/>
            </analyzer>
            <analyzer type="query">
                <tokenizer/>
                <filter/>
            </analyzer>
        </fieldType>

    </types>

    <fields>

        <field name="id" type="string" indexed="true" stored="true" required="true"/>
        <field name="nature" type="string" indexed="true" stored="true" required="true"/>
        <field name="class" type="string" indexed="true" stored="true" required="true"/>
        <field name="type" type="string" indexed="true" stored="true" required="true"/>
        <field name="idtype" type="int" indexed="true" stored="true"/>
        <field name="idparent" type="int" indexed="true" stored="true"/>
        <field name="status" type="int" indexed="true" stored="true"/>
        <field name="text" type="text" indexed="true" stored="false" multiValued="true"/>

    </fields>

    <uniqueKey>id</uniqueKey>

    <defaultSearchField>text</defaultSearchField>

    <solrQueryParser defaultOperator="OR"/>

    <copyField source="*" dest="text"/>

</schema>

It allows you define field names and types describing your data. For example, the unique ID, the title, subtitle, etc. This is OK to solve simple problems, but sometimes, we don’t know what our data will be composed of. This is what dynamic fields are for: they make you schema.xml less hard-coded.
As you may already know, Lodel main feature is its customizable Editorial Model: you can define your database structure directly from the back office. Thanks to the dynamic fields, we wrote a schema.xml able to handle any data from Lodel, whatever your Editorial Model looks like!
This means that our work with Solr can be useful for any Lodel users, so we plan to distribute it in the next release.

Our schema.xml

Here is the schema.xml so far:

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.4">

    <types>

        <fieldType name="int" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
        <fieldType name="string" sortMissingLast="true" omitNorms="true"/>

        <fieldType name="text" positionIncrementGap="100">
            <analyzer type="index">
                <tokenizer/>
                <filter/>
            </analyzer>
            <analyzer type="query">
                <tokenizer/>
                <filter/>
            </analyzer>
        </fieldType>

    </types>

    <fields>

        <field name="id" type="string" indexed="true" stored="true" required="true"/>
        <field name="nature" type="string" indexed="true" stored="true" required="true"/>
        <field name="class" type="string" indexed="true" stored="true" required="true"/>
        <field name="type" type="string" indexed="true" stored="true" required="true"/>
        <field name="idtype" type="int" indexed="true" stored="true"/>
        <field name="idparent" type="int" indexed="true" stored="true"/>
        <field name="status" type="int" indexed="true" stored="true"/>
        <field name="text" type="text" indexed="true" stored="false" multiValued="true"/>

        <dynamicField name="*_int" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_entries" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_persons" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_file" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_boolean" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_tinytext" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_email" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_date" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_url" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_text" type="text" indexed="true" stored="true"/>
        <dynamicField name="*_mltext" type="text" indexed="true" stored="true"/>

        <dynamicField name="*_int_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_entries_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_persons_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_file_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_boolean_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_tinytext_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_email_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_date_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_url_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_text_m" type="text" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_mltext_m" type="text" indexed="true" stored="true" multiValued="true"/>

    </fields>

    <uniqueKey>id</uniqueKey>

    <defaultSearchField>text</defaultSearchField>

    <solrQueryParser defaultOperator="OR"/>

    <copyField source="*" dest="text"/>

</schema>

Indexing content

So I started to write a simple PHP script to index content from Lodel SQL database.

Solr provides a web service to receive the data through POST requests. You can generate XML and use CURL to send it to Solr and get your content indexed, but the easiest way is to use a library which take care of the boring part. The best library I found for PHP is called Solarium. It is full featured, well documented, and similar to other Solr libraries in Python and Perl.

The script is only few lines of PHP and is pretty safe explanatory:

<?php

require('Solarium/Autoloader.php');
Solarium_Autoloader::register();

$client = new Solarium_Client();

$adapter = $client->getAdapter();
$adapter->setPort(8989);

// Delete all documents
$update = $client->createUpdate();
$update->addDeleteQuery('*:*');
$update->addCommit();
$result = $client->update($update);

// Connect the db
$dbh = new PDO('mysql:host=localhost;dbname=xxxx', 'xxxx', 'xxxx', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8") );

$docs = array();

function update($client, &$docs) {
    $update = $client->createUpdate();
    $update->addDocuments($docs);
    $update->addCommit();
    $result = $client->update($update);
    $docs = array();
    echo ".";
}

$objects = $dbh->prepare("SELECT * FROM objects WHERE class IN ('entities')");
$objects->execute();
while ( $object = $objects->fetch() ) {

    $doc = new Solarium_Document_ReadWrite();
    $doc->id = $object[id];
    $doc->nature = $object['class'];

    switch ($object['class']) {
        case 'entities':
            $entities = $dbh->prepare("SELECT e.*, t.type, t.class FROM entities e, types t WHERE e.id = ? AND e.idtype = t.id");
            $entities->execute(array($object[id]));
            $entity = $entities->fetch();

            foreach (array('idtype','type','class','idparent','status') as $k) {
                $doc->addField($k, $entity[$k]);
            }

            $things = $dbh->prepare("SELECT * FROM $entity[class] WHERE identity = $object[id]");
            $things->execute();
            $thing = $things->fetch();

            $tablefields = $dbh->prepare("SELECT * FROM tablefields WHERE class = '$entity[class]'");
            $tablefields->execute();
            while ($f = $tablefields->fetch()) {
                $v = preg_replace('/[\p{Cc}]/', '', $thing[$f[name]]);
                if ($v)
                    $doc->addField($f[name].'_'.$f[type], $v);
            }

            $relations = $dbh->prepare("SELECT r.id2, r.nature, et.type FROM relations r, entries e, entrytypes et WHERE id1 = $object[id] AND r.id2 = e.id AND e.idtype = et.id");
            $relations->execute();
            while ($r = $relations->fetch()) {
                $doc->addField('R_'.$r[nature].'_'.$r[type].'_int_m', $r[id2]);
            }

            break;
    }

    $docs[] = $doc;
    if ( count($docs) == 1000 )
        update($client, $docs, $total);
}

update($client, $docs, $total);

?>

There is only one big loop, on the ‘object’ table. An object can be an entity, an entry or a person. For now, it can only index entities, but we plan to support entries and persons in the next move.
The most interesting part is (simplified) here:

while ($f = $tablefields->fetch()) {
    $doc->addField($f[name].'_'.$f[type], $thing[$f[name]]);
}

As you can see, the name of the added Solr field results from the concatenation of its name and type in Lodel. If you defined a multilingual field named ‘title’ in your editorial model, the script will send it to Solr under the name ‘title_mltext’, and Solr will store it using the dynamic field ‘*_mltext’.

To better understand how Solr store our documents, here is the result of a select query:

<response>
    <lst name="responseHeader">
        <int name="status">0</int>
        <int name="QTime">0</int>
        <lst name="params">
            <str name="q">*:*</str>
        </lst>
    </lst>
    <result name="response" numFound="19573" start="0">
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>
            <str name="nature">entities</str>
            <str name="class">event</str>
            <str name="type">event</str>
            <str name="dates_date">2010-12-08</str>
            <str name="id">619209</str>
            <int name="idparent">0</int>
            <int name="idtype">57</int>
            <int name="status">-1</int>
            <str name="title_mltext">
                <r2r:ml lang="fr">Les compagnons de l'Espace</r2r:ml>
            </str>
            <str name="subtitle_mltext">
                <r2r:ml lang="fr">Une exposition de l'Observatoire de l'Espace du CNES</r2r:ml>
            </str>
            <str name="summary_mltext"/>
            <str name="content_mltext">
                <r2r:ml lang="fr"><p>A l'occasion de la 28e &eacute;dition des Journ&eacute;es europ&eacute;ennes du patrimoine, organis&eacute;e par le minist&egrave;re de la Culture et de la communication sur le th&egrave;me<i> Le voyage du patrimoine,</i> l'Observatoire de l'Espace invite le public au si&egrave;ge parisien du CNES, le samedi 17 et le dimanche 18 septembre 2011 de 11h &agrave; 19h pour l'exposition <i>L<b>es compagnons de l'Espace</b>.</i> Chacun&nbsp;pourra&nbsp;venir y&nbsp;d&eacute;couvrir des pi&egrave;ces&nbsp;&eacute;tonnantes issues du patimoine culturel de l'Espace et rencontrer les t&eacute;moins et acteurs de l'aventure spatiale. Cette&nbsp;&eacute;v&egrave;nement in&eacute;dit&nbsp;r&eacute;v&egrave;lera la multiplicit&eacute; des liens que l'Homme tisse avec l'Espace, &agrave; travers les compagnons qui le pr&eacute;c&egrave;dent, l'assistent et le r&eacute;confortent; qu'ils soient fictifs ou r&eacute;els, animaux ou robots, ils sont les partenaires de son exploration.</p><p>Entr&eacute;e libre et gratuite</p><p>Centre National d'Etudes Spatiales&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2, place Maurice Quentin Paris 1er</p><p>M&eacute;tro Chatelet-Les halles/sortie place carr&eacute;e</p><p>Renseignements : 01 44 76 76 18&nbsp; / <a class="mailto:observatoire.espace@cnes.fr">observatoire.espace@cnes.fr</a></p></r2r:ml>
            </str>
            <arr name="R_E_partners_int_m">
                <int>1387273</int>
            </arr>
            <arr name="R_E_places_int_m">
                <int>1434398</int>
            </arr>
            <arr name="R_E_subjects_int_m">
                <int>1387363</int>
            </arr>
            <arr name="R_E_type_int_m">
                <int>1387268</int>
            </arr>
            <arr name="R_E_websites_int_m">
                <int>1396551</int>
            </arr>
        </doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
    </result>
</response>

Querying Solr from Lodel

Now that our data is indexed, we want to query Solr from inside Lodel. To ease the process, I started to code a very simple LodelScript loop, and placed it in the dedicated file loops_local.php:

<?php

function loop_solr($context, $funcname, $arguments) {

    $localcontext = $context;

    if (function_exists("code_before_$funcname"))
        call_user_func("code_before_$funcname", $localcontext);

    $client = new Solarium_Client();

    $adapter = $client->getAdapter();
    if (isset($arguments[port]))
        $adapter->setPort($arguments[port]);

    $query = $client->createSelect();
    if (isset($arguments[query]))
        $query->setQuery($arguments[query]);

    $resultset = $client->select($query);

    $context[nbresults] = $resultset->getNumFound();

    $count = 0;
    foreach ($resultset as $document) {

        $localcontext = $context;
        $localcontext[count] = ++$count;

        foreach($document AS $field => $value) {
            $localcontext[$field] = $value;
        }

        call_user_func("code_do_$funcname", $localcontext);
    }

    if (function_exists("code_after_$funcname"))
        call_user_func("code_after_$funcname", $localcontext);
}

?>

This loop is very similar to the SQL loop and can be used like this:

<h1>À la une</h1>
<LOOP NAME="solr" PORT="8989" QUERY="class:event AND status:1 AND frontpage_boolean:1">
    <BEFORE><ul></BEFORE>
    <DO>
        <li><a class="/[#ID]">[#TITLE_MLTEXT]</a></li>
    </DO>
    <AFTER></ul></AFTER>
</LOOP>

More Like This

Solr provide another nice feature called MoreLikeThis queries. Enable MLT during a query and each Solr result will be filled with similar contents. The similarity is based on the fields you want, and you can even weight them.
So I developed another LodelScript sub-loop, similar to the RSS loop, to support MLT:

<LOOP NAME="solr" PORT="8989" QUERY="id:[#ID]" MLT="1" MLTFL="class,status,title_mltext,body_mltext" COUNT="10">
    <BEFORE><ul></BEFORE>
    <DO>
        <LOOP NAME="morelikethis">
            <BEFORE><ul></BEFORE>
            <DO><li><a class="[#ID]">[#TITLE_MLTEXT]</a></li></DO>
            <AFTER></ul></AFTER>
        </LOOP>
    </DO>
    <AFTER></ul></AFTER>
</LOOP>

This code will list the 10 most similar documents for the current ID, based on the class, status, title_mltext and body_mltext fields.

What next?

This code is still a proof of concept, it needs refactoring, polishing, documentation and integration.

Putting in a separate function the code that indexes a document, in order to call them from an edition hook: this way, any updated object will be re-indexed on the fly.

We also plan to clone the hook system for the indexation function. This would allow us to per-site customize the building of a Solr document before it is sent to Solr without forking the script. A good example of such a hook would be querying GeoNames web service at indexing time to geolocalize your content.

Solr also provides an XLST processor. Writing some simple sheets to transform Solr results into another formats would be a very neat way to add plenty of web services to Lodel.

Filed under 1.0, Tools · Tagged with

Modèle de document pour Word v3.0 : nouvelles macros d’automatisation

Posted by Jean-François Rivière on July 20, 2011 · 1 Comment 

Nous venons de diffuser sur sourcesup la version 3.0 du modèle de document pour Word  https://sourcesup.cru.fr/frs/?group_id=193.

Le version 3.0 est constituée d’une archive zip qui contient :

  • le modèle revuesorg_fr.dot, qui contient les styles déclarés dans le modèle éditorial de Revues.org distribué avec Lodel (modèle à utiliser par défaut) ;
  • le modèle revuesorg_complet.dot, qui contient un plus grand nombre de styles (résumés dans des langues supplémentaires, index supplémentaires, etc.). L’utilisation de ce modèle de document nécessite la modification du modèle éditorial dans Lodel ;
  • les modèles macros_revuesorg_win.dot et macros_revuesorg_mac.dot. Ces deux modèles contiennent des macros qui permettent d’automatiser certaines corrections de stylage et d’erreurs typographiques (une version pour Windows et une version pour MacOS).
  • documentation_modele_revuesorg_3.0.doc : la documentation d’installation et d’utilisation des macros

Cette version du modèle de document introduit des macros Word qui permettent d’automatiser la correction et le nettoyage des textes. Ces macros permettent de gagner beaucoup de temps dans la préparation des textes. Les macros disponibles à ce jour (20/07/2011) sont les suivantes  :

  • Macros de corrections de stylage
    • Supprimer les mises en forme et les styles de caractères locaux dans le corps de texte
    • Trier les métadonnées
    • Vérifier les paragraphes
    • Vérifier les niveaux de titre
    • Rendre les liens hypertextes actifs
  • Macros de corrections typographiques
    • Rétablir les espaces insécables dans le corps de texte
    • Remplacer les apostrophes verticales par des apostrophes typographiques
    • Supprimer les doubles sauts de paragraphe
    • Supprimer les points à la fin des titres
    • Remplacer les guillemets droits par des guillemets anglais / Remplacer les guillemets droits par des guillemets français
    • Effacer le surlignement
    • Inverser les italiques dans la sélection en cours / Inverser les italiques dans tout le document
  • Macros pour les notes de bas de page
    • Supprimer les mises en forme et les styles de caractères locaux dans les notes de bas de page
    • Supprimer les doubles sauts de paragraphe dans les notes de bas de page
    • Rétablir les espaces insécables dans les notes de bas de page
    • Renumérotation des notes
    • Supprimer les points après les numéros de notes
  • Traitements avancés
    • Traitement par lot
    • Transformer les équations Word en images

Vous trouverez plus de détail sur l’utilisation de ces macros dans la documentation diffusée avec les modèles.

Merci à Jean-Baptiste Bertrand qui a développé ces macros qui font gagner énormément de temps et améliore la qualité des données publiées dans Lodel !

 

Filed under Tools · Tagged with lodel 0.9, lodel 1.0, modèle

Mise à jour du modèle de document pour OpenOffice

Posted by Jean-François Rivière on July 20, 2011 · Leave a Comment 

Nous avons déposé récemment sur sourcesup une nouvelle version du modèle de document pour Open/Libre Office : https://sourcesup.cru.fr/frs/?group_id=193 (Lodel modele revues.org (OOo) 1.0).
Cette version corrige quelques bugs mineurs, améliore la mise en forme des styles de paragraphe “titre illustration”, “legende illustration”, “credits illustration” et des styles de caractères liés aux auteurs “affiliation”, “courriel”…
Une documentation d’installation est incluse (readme.txt) dans l’archive zip.
Cette documentation est aussi disponible sur le wiki de Lodel : www.lodel.org/wiki/index.php/Mod%C3%A8le_de_document_pour_OpenOffice

Filed under Tools · Tagged with lodel 0.9, lodel 1.0, modèle

Pas de nouvelles de Lodel?

Posted by Nahuel on June 29, 2011 · Leave a Comment 

Il n’y a pas eu de nouvelles concernant les nouveautés de Lodel depuis un moment, il est maintenant temps de faire un petit point sur ces derniers mois de développement, qui ont permis d’apporter un certain nombre d’améliorations et de préparer la sortie de Lodel 1.0.

Ce qui est indiqué ci-dessous, n’est présent que sur les branches de bugfixes, et le tronc de développement.

Gestion des RSS

Jusqu’à très récemment la gestion des flux RSS était faite par MagpieRSS, cette librairie n’est plus maintenue depuis 2005 si l’on croit ce que l’on voit sur le site du projet. De plus cette librairie utilise beaucoup de fonction de PHP qui sont dépréciés dans les nouvelles version de PHP, en particulier la version 5.3, qui est présent dans la dernière version stable de Debian.

À partir de ce constat, nous avons cherché une librairie de lecture de flux RSS, écrite pour PHP 5.3 et ultérieur, utilisant les concepts objet, et qui soit encore maintenu. Nous en avons trouvé plusieurs, mais la plupart avaient une lacune sur un des critères principaux: le projet n’était pas maintenu.

Nous avons eu la change de trouver une librairie très bien écrite, qui est toujours maintenue à l’heure actuelle, et qui fonctionne beaucoup mieux de MagpieRSS: SimplePie.

Le travail d’intégration de cette librairie n’a pas été bien compliqué, car elle est relativement compatible avec MagpieRSS.
Cette modification sera présente dans Lodel 1.0, et Lodel 0.9.1, qui devront bientôt voir le jour.

Gestion du Cache

Lodel existe depuis longtemps, les besoins ont beaucoup évolués depuis les premières utilisations, et les fonctionnalités sont apparues au fil des besoins. Aujourd’hui, Lodel est utilisé dans des architectures à haute disponibilité, ce qui fait de nouveau évoluer les besoins.

La structure du cache de lodel ne correspondait plus au besoin des architectures HA(High Availability), le cache doit pouvoir être totalement séparé du code; C’est pourquoi, nous avons réécrit la gestion de cache afin de pouvoir spécifier un répertoire spécifique qui contiendra tout le cache, et rien que le cache.

Cela permet de pouvoir stocker le cache sur un serveur distant, ou dans la ram, ou sur un système de fichier particulier afin d’obtenir de meilleures performances.

Cette fonctionnalité sera aussi disponible dans Lodel 1.0, 0.9.1, et sur la branche de bugfix de la version 0.8.

Lodel 1.0

Venons-en à la future version majeure de lodel, beaucoup de travail a été fait pour améliorer et faire évoluer lodel.

Tout d’abord, l’interface a été un peu revue, les couleurs ont changé, et certains processus, comme l’import de documents, ont étés revus.

La principale nouveauté dans Lodel 1.0 est l’abandon de ServOO à l’avantage de OpenText/OTX, qui permet la conversion des documents Office vers de la TEI, par conséquent Lodel sait maintenant importer de la TEI. Plusieurs revues utilisent déjà cette fonctionnalité, et stylent leurs documents directement en TEI (Discours, Journal of the Text Encoding Initiative). Il n’y a donc plus besoin d’un outil aussi lourd que Microsoft ou Open/Libre Office. Pour les plus aventureux un éditeur texte suffit, pour les moins téméraires il existe différents outils d’éditions XML, comme Oxygen ou bien XML Editor

Filed under updates · Tagged with

Mon premier plugin dans lodel

Posted by durand on January 24, 2011 · 1 Comment 

Nous souhaitons afficher la météo d’une ville choisie, dans l’interface administrateur de notre site lodel bacasable. Un plugin est tout à fait adapté pour réaliser cette nouvelle fonctionnalité. Nous l’appellerons meteo.

Pour démarrer

Un coup d’œil dans la documentation lodel : www.lodel.org/wiki/index.php/Plugins

Premiers pas

Les fichiers de base seront situés dans le répertoire  share/plugins/custom/meteo

  • fichier config.xml : au départ, seul le trigger postview est configuré, il permet d’intercepter l’affichage de la page en intégrant l’ajout de la ligne Météo dans la liste des Outils sur la page d’administration du site (onglet Administration).
    NB : nous ajoutons dès à présent le trigger preview, même si nous ne l’utilisons pas tout de suite (voir le paragraphe Remarques ci-dessous)
<?xml version="1.0" encoding="utf-8" ?>
<LodelPlugin>
 <title>Meteo</title>
 <description>Affichage de la météo</description>
 <sql>0</sql>
 <hookType>class</hookType>
 <triggers>preview,postview</triggers>
 <parameters>
 </parameters>
</LodelPlugin>
  • fichier meteo.php : il contient la définition de la classe meteo, elle-même extension de la classe plugins. Pour ajouter la fonctionnalité Météo dans la liste des actions possibles, il suffit de modifier, avant l’affichage de la page, la liste des fonctionnalités disponibles en ajoutant l’item Météo après l’item Plugins. Météo pointe sur un lien du type ?do=_meteo_list, ce que lodel interprétera comme un appel à la fonction list du plugin meteo.
<?php
class meteo extends Plugins
{
public function enableAction(&$context, &$error) {}

public function disableAction(&$context, &$error) {}

public function preview(&$context) {}

public function postview (&$context)
 {
 if(!defined('backoffice-admin') || C::get('do') || C::get('lo')
    || ($context['view']['tpl'] != 'index')) return;
 if(!parent::_checkRights(LEVEL_REDACTOR)) { return; }       
 View::$page = preg_replace('/(Plugins<\/a><\/li>)/',
    '\\1<li><a class="./?do=_meteo_list">Météo</a></li>', View::$page);
 }

public function listAction (&$context, &$error)
 {
 echo "La météo du jour" ;
 return "_ajax" ;  
 }
}
?>
  • il faut maintenant activer ce plugins meteo au niveau de l’installation générale de lodel : le menu Configuration / Plugins permet d’activer le plugin meteo pour tous les sites (ne pas confondre avec installer sur tous les sites). Il faudra ensuite l’activer au niveau du site lodel bacasable (menu Administration / Outils / Plugins).
    En rechargeant la page d’administration du site, nous voyons bien apparaître l’item Météo sous le terme Plugins : un clic et La météo du jour s’affiche bien dans l’interface.

Le plus dur est fait, il faut maintenant adapter les scripts et permettre l’affichage personnalisé dans un br.

Mise en forme à l’aide d’un template

  • nous allons associer à ce plugin un template contenant des lignes au format html, il sera situé dans le sous-répertoire tpl du plugin. Appelons-le meteotpl.html (dans share/plugins/custom/meteo/tpl).
    <html>
     <head>
     <CONTENT VERSION="1.0" LANG="fr" CHARSET="utf-8"/>    
     <TITLE>La météo</TITLE>
     </head>
     <body>
     <h1>La météo du jour</h1>
     </body>
    </html>
  • la méthode preview doit être modifiée pour associer ce template meteotpl à la classe meteo
    public function preview (&$context)
    {
    // vérification que l'on est positionné ni dans l'interface d'administration
    // ni dans le template d'affichage de la météo
    if(!defined('backoffice-admin') || $context['view']['tpl'] != 'meteotpl') return;
    // ajout du fichier de template dans la classe qui gère le contexte    
    C::set('view.base_rep.meteotpl', 'meteo');    
    }
  • la fonction listAction du script meteo.php doit faire appel à ce template meteotpl
    public function listAction (&$context, &$error)
     {
     View::getView()->renderCached('meteotpl') ;
     return "_ajax" ;  
     }
    }
  • vider le cache et recharger la page : le titre est maintenant mis en forme
  • et maintenant, pour terminer, affichage de l’url france.meteofrance.com/ dans un br : il suffit de modifier le contenu de la balise body dans le fichier template meteotpl.html
    <html>
     <head>
     <CONTENT VERSION="1.0" LANG="fr" CHARSET="utf-8"/>
     <TITLE>La météo</TITLE>
     </head>
     <body>
     <br name="stats" src="/img/spacer.gif"> 
     </body>
    </html>

Encore plus loin : ajout de paramètres

Nous souhaitons paramétrer les prévisions en fonction de notre ville de résidence. Tout ceci, uniquement dans l’interface d’administration, sans modification des scripts.
Par exemple, pour Marseille, l’url est de la forme

france.meteofrance.com/france/meteo?PREVISIONS_PORTLET.path=previsionsville/130550

Comme nous modifions en profondeur  les caractéristiques du plugin, il faut détruire le plugin dans la table plugins du site bacasable et dans la table mainplugins de l’installation générale.

  • modification du fichier config.xml : ajout d’un paramètre ville (par défaut le code correspond à la ville de Marseille)
    <?xml version="1.0" encoding="utf-8" ?>
    <LodelPlugin>
     <title>Meteo</title>
     <description>Affichage de la météo</description>
     <sql>0</sql>
     <hookType>class</hookType>
     <triggers>preview,postview</triggers>
     <parameters>
     <param name="ville" title="Ville" type="text" defaultValue="130550" allowedValues="" required="true"/>
     </parameters>
    </LodelPlugin>
  • activation du plugin au niveau de l’installation générale et au niveau du site bacasable
  • modification de la méthode preview pour récupérer la valeur du paramètre ville : il est stocké dans l’attribut _config de l’objet. L’url est construite en tenant compte de cette valeur, elle est stockée dans le contexte C.
    public function preview (&$context)
    {
    if(!defined('backoffice-admin') || $context['view']['tpl'] != 'meteotpl') return;
    C::set('view.base_rep.meteotpl', 'meteo');    
    $ville = $this->_config['ville']['value'] ;
    C::set('urlmeteo', "france.meteofrance.com/france/meteo?PREVISIONS_PORTLET.path=previsionsville/".$ville) ;
    }
  • modification du template pour intégrer la variable urlmeteo en faisant appel à la variable lodelscript associée [#URLMETEO]
    <html>
     <head>
     <CONTENT VERSION="1.0" LANG="fr" CHARSET="utf-8"/>    
     <TITLE>La météo</TITLE>
     </head>
     <body>
     <br name="stats" src="/img/spacer.gif"> [#URLMETEO]" scrolling="yes"   FRAMEBORDER="no"></br>
     </body>
    </html>
  • exécution !
    • sur la page france.meteofrance.com/, nous indiquons la ville qui nous concerne et repérons son identifiant numérique (formulaire Rechercher), par exemple 212310 pour Dijon
    • dans l’interface d’administration du site bacasable, nous sélectionnons le menu Plugins / Configurer correspondant au plugin meteo et nous indiquons la valeur 212310
    • le lien bacasable/lodel/admin/?do=_meteo_list correspondant à l’item Météo affiche bien la météo de la ville de Dijon.

Remarques et astuces

  • activation du plugin uniquement par l’administrateur lodel
public function enableAction(&$context, &$error)
     {
     if(!parent::_checkRights(LEVEL_ADMINLODEL)) { return; }
     }
  • en cas de modification importante du plugin, ajout de trigger par exemple, il faut le détruire directement dans la table mainplugins du serveur lodel et dans la table plugins du site.
  • en cas d’erreur, vider manuellement le cache : CACHE/triggers

Filed under 0.9, Tools · Tagged with

Un nouveau modèle de document pour OpenOffice

Posted by Jean-François Rivière on January 18, 2011 · 1 Comment 

Un nouveau modèle de document permettant d’appliquer les styles pour Lodel avec OpenOffice est maintenant disponible.

Ce modèle remplace l’extension “Lodel stylist” pour OpenOffice qui ne fonctionne pas dans la version 3 d’OpenOffice. Il permet d’appliquer les styles déclarés dans le modèle éditorial distribué avec la version 0.9 de Lodel.

Il est distribué en licence GPL (version 1.0 beta) sur SourceSup : https://sourcesup.cru.fr/frs/?group_id=193 (modele_revuesorg_OO.zip)

L’archive zip contient  2 fichiers :

  • modele_revuesorg_fr.ott : le modèle de document
  • raccourcis_modele_revorg_fr.cfg : le fichier de configuration des raccourcis claviers permettant d’appliquer les styles de documents.

Comment l’utiliser

  • Dans OpenOffice writter, vérifier le niveau de sécurité pour l’execution des macros :  menu Outils > Options > Openoffice.org > Sécurité > Sécurité des macros > choisir “Niveau de sécurité moyen”.
  • Un double clic sur modele_revuesorg_fr.ott ouvre un nouveau document basé sur le modèle (autoriser l’exécution des macros, bien-sûr).
  • Le menu  ”Lodel” disponible dans la barre des menus permet d’appliquer les styles déclarés dans Lodel.
  • Pour attacher les raccourcis claviers permettant d’appliquer les styles : menu Outils > Personnaliser > Clavier > Charger : choisir le fichier “raccourcis_modele_revorg_fr.cfg” et valider. Les raccourcis clavier sont alors actifs. Ils sont affichés dans le menu “Lodel” en  face des styles correspondants.

Restrictions connues

  • Les listes à puces sont interprétées par Servoo comme des listes ordonnées : les listes à puces seront affichées dans Lodel comme des listes numérotées.
  • La touche “alt” n’est disponible dans les raccrourcis clavier d’OpenOffice que depuis la version 3.2. Pour les versions antérieures, la plupart des raccourcis clavier ne sont pas disponibles.
  • Dans OpenOffice, les images ne sont pas nécessairement contenu dans un paragraphe distinct. Il faut veiller à insérer un paragraphe stylé en “Standard” ou en “Annexe” et contenant l’ancre de l’image.
  • Il faut enregistrer le document au format sxw. Ne pas utiliser format le format doc ou odt.

Crédits
Matthieu Heuzé, Jean-François Rivière

Ce modèle est distribué en licence GPL, en version beta. Merci de faire état de vos essais, qu’ils soient fructueux ou non, sur la liste lodel-users (https://listes.cru.fr/sympa/info/lodel-users) ou en commentaire de ce billet.

Personnalisation du modèle

Il est bien-sûr possible d’ajouter d’autres styles correspondant à un autre modèle éditorial.

Le principe de ce modèle de document est le suivant :

  • le modèle de document contient des styles de paragraphes dont les noms sont déclarés dans le modèle éditorial de Lodel ;
  • le modèle contient des macros qui appliquent ces styles (un macro, très simple, par style) ;
  • le modèle contient enfin un menu personnalisé qui permet d’exécuter ces macros.

Les raccourcis clavier permettant d’exécuter les macros ne peuvent être enregistrées dans le modèle. C’est pour cette raison qu’il faut les charger depuis un fichier différent.

Pour ajouter un style pour un autre modèle éditorial au menu Lodel :

  • Ouvrez le modèle de document dans OpenOffice 3.2 (veillez à ouvrir le modèle de document, pas un nouveau document basé sur le modèle).
  • Ajoutez un style dans le modèle de do
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.