source: spip-zone/_contribs_/_filtres_/rhizome/inc-rhizome.php3

Last change on this file was 747, checked in by francois@…, 16 years ago

orthographe : rhyzome -> rhizome

+ diverses petites coquilles

File size: 13.2 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  inc-rhisome.php3                                                       *
5 *  Jeu de filtres pour mettre en place une navigation non hierarchique    *
6 *  ("rhisomique") dans SPIP                                               *
7 *                                                                         *
8 *  Version: 0.1                                                           *
9 *                                                                         *
10 *  Explications ici:                                                      *
11 *  http://www.spip-contrib.net/ecrire/articles.php3?id_article=1072       *
12 *                                                                         *
13 *  Copyright (c) 2005 Francois Schreuer                                   *
14 *                                                                         *
15 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
16 \***************************************************************************/
17
18
19/***************** Configuration *******************/
20
21// Nombre maximal de liens d'un meme type a renvoyer par le filtre
22define('_RHIZOME_MAX_RETOUR', '7');
23
24// Les groupes de mots-cles concernes par le rhizome (on ne cherchera a faire des liens
25// que vers les mots-cles appartenant a ces groupes)
26# define('_RHIZOME_GROUPES', '4,6'); // separes par des virgules
27# !!! parametrage marche pas encore, allez a la ligne 120 changer ca a la main !!!
28
29// Chaines html entourant chaque item renvoye
30define('_RHIZOME_DEBUT_HTML', '<li>');
31define('_RHIZOME_FIN_HTML', '</li>');
32define('_RHIZOME_DEBUT_HTML_GENERAL', '<ul>');
33define('_RHIZOME_FIN_HTML_GENERAL', '</ul>');
34
35// Seuil de l'indice total en dessous duquel la liaison ne se fait pas
36// Augmenter la valeur pour diminuer le nombre de resultats
37define('_RHIZOME_MIN_INDICE_TOTAL', '0.05');
38
39// Nombre minimal d'articles que deux objets ont en commun en dessous duquel on ne renvoie pas de resultat
40define('_RHIZOME_MIN_INTERSECTION', '3');
41
42// Les quatre (x2) parametres suivants permettent de configurer le filtre indice_interet_propre
43// Mettre 0 pour annuler un sous-indice (et donc donner plus d'importance proportionnelle aux autres
44// Exemple pour le premier parametre: duree en jours pendant laquelle on estime que les articles site sont utiles
45// Sur un site dont le contenu est rapidement perime, mettre une petite valeur (30 ou 60 par exemple)
46// Sur un site ou la date du contenu n'a pas d'importance, mettre une grande valeur ou neutraliser
47// cette partie de l'indice en le mettant à 0
48define('_RHIZOME_ARTICLE_DUREE', '365');
49        // Choisir la fonction de calcul du sous-indice
50        // Valeurs possibles:
51        //    log : fonction logarithmique (avantage les valeurs eleves)
52        //    1er : fonction du 1er degre (totalement continue, moins discriminante)
53        define('_RHIZOME_ARTICLE_DUREE_MODE', '1er');
54// Nombre de messages de forums donnant lieu au maximum de points sur ce critere
55define('_RHIZOME_ARTICLE_FORUMS', '10');
56        // Idem supra
57        define('_RHIZOME_ARTICLE_FORUMS_MODE', '1er');
58// Longueur d'un article donnant lieu au maximum des points sur ce critere
59define('_RHIZOME_ARTICLE_LONGUEUR', '40000');
60        // Idem supra
61        define('_RHIZOME_ARTICLE_LONGUEUR_MODE', '1er');
62// Popularite d'un article donnant lieu au maximum des points sur ce critere
63define('_RHIZOME_ARTICLE_POPULARITE', '100');
64        // Idem supra
65        define('_RHIZOME_ARTICLE_POPULARIT_MODE', '1er');
66// NB: Si les quatre criteres sont annules, l'indice renverra systematiquement la valeur 1
67
68/************* Fin de la configuration *************/
69
70
71//
72// Renvoie la liste des objets lies a un objet
73//
74// Parametres :
75//
76//   $type         : le type d'objet passé en variable principale (par defaut : 'mot')
77//                   valeurs possibles : 'mot'
78//                   valeurs possibles a terme : 'mot', 'auteur', 'article'
79//
80//   $mode         : le type d'objet que le filtre retournera
81//                   valeurs possibles : les memes que pour $type
82//
83// Il y a donc theoriquement neuf usages possibles du filtre rhizome :
84//
85//  Le seul usage deja operationnel est :
86//     [(#ID_MOT|rhizome{'mot','mot'})] alias [(#ID_MOT|rhizome)]
87//
88//  Les 8 suivants devraient l'etre sous peu :
89//     [(#ID_MOT|rhizome{'mot','auteur'})]
90//     [(#ID_MOT|rhizome{'mot','article'})]
91//     [(#ID_AUTEUR|rhizome{'auteur','mot'})]
92//     [(#ID_AUTEUR|rhizome{'auteur','auteur'})]
93//     [(#ID_AUTEUR|rhizome{'auteur','article'})]
94//     [(#ID_ARTICLE|rhizome{'article','mot'})]
95//     [(#ID_ARTICLE|rhizome{'article','auteur'})]
96//     [(#ID_ARTICLE|rhizome{'article','article'})]
97//
98function rhizome ($id, $type='', $mode='', $debut_html='', $fin_html='', $debut_html_general='', $fin_html_general='')
99{
100
101        // On verifie les variables
102        if(empty($type)) $type = 'mot';
103        if(empty($mode)) $mode = $type;
104        if(empty($debut_html)) $debut_html = _RHIZOME_DEBUT_HTML;
105        if(empty($fin_html)) $fin_html = _RHIZOME_FIN_HTML;
106        if(empty($debut_html_general)) $debut_html_general = _RHIZOME_DEBUT_HTML_GENERAL;
107        if(empty($fin_html_general)) $fin_html_general = _RHIZOME_FIN_HTML_GENERAL;
108
109
110        switch($type)
111        {
112
113                case'mot':
114                        // On initialise le compteur du tableau
115                        $i = 0;
116                        // On passe en revue tous les mots-cles du site appartenant aux groupes ok
117                        // TODO - Parametrer les groupes
118                        $q = spip_query("SELECT id_mot,titre FROM spip_mots WHERE id_mot!= '$id' AND id_groupe IN (4,6)");
119                        while ($r =  spip_fetch_array($q))
120                        {
121                                $id_mot_courant = $r['id_mot'];
122                                // Pour chaque mot, on compte le nombre d'articles qu'il a en commun avec le mot courant
123                                // NB: on ne se limite pas aux articles publies pour avoir une masse critique plus importante
124                                //     Pour limiter aux articles publies, il suffit d'ajouter: AND articles.statut='publie'
125                                $intersection = spip_fetch_array(spip_query("SELECT
126                                        COUNT(articles.id_article) AS compteur
127                                        FROM
128                                                spip_mots_articles AS mots_articles_2,
129                                                spip_mots_articles AS mots_articles_3,
130                                                spip_articles AS articles
131                                        WHERE
132                                                (articles.id_article = mots_articles_2.id_article
133                                                AND mots_articles_2.id_mot = '$id_mot_courant')
134                                                AND (articles.id_article = mots_articles_3.id_article
135                                                AND mots_articles_3.id_mot = '$id')
136                                        "));
137                                // Si le nombre d'article est inferieur au minimum requis, on ne va pas plus loin
138                                if($intersection['compteur'] >= _RHIZOME_MIN_INTERSECTION)
139                                {
140                                        // Le nombre de mots appartenant a un mot OU a l'autre
141                                        $unoulautre = spip_fetch_array(spip_query("SELECT
142                                                COUNT(distinct id_article) AS compteur
143                                                FROM spip_mots_articles
144                                                WHERE id_mot in ($id_mot_courant,$id)
145                                        "));
146                                        // On calcule l'indice de pertinence en comparant l'intersection des deux mots à leur union
147                                        // NB: signification de la division de $unoulautre['compteur'] par 5 :
148                                        // on considere que la liaisons entre deux mots ayant 20% d'articles en commun est pertinente a 100%
149                                        $pertinence = calculer_indice($intersection['compteur'], $unoulautre['compteur'] / 5);
150                                        // On recupere l'indice d'interet propre du mot en question
151                                        $interet = indice_interet_propre($id_mot_courant,$type);
152                                        // On attenue un peu la portee de l'indice d'interet
153                                        $interet = ($interet / 3) + 0.667;
154                                        // On pondere l'indice de pertinence par l'indice d'interet (et on arrondit)
155                                        $indice_total = round($interet * $pertinence,3);
156                                        // Si la valeur de l'indice total depasse le seuil requis,
157                                        // on stocke le tout dans un tableau
158                                        if($indice_total > _RHIZOME_MIN_INDICE_TOTAL) {
159                                                $tableau[$i]['indice_total'] = $indice_total;
160                                                $tableau[$i]['titre'] = $r['titre'];
161                                                $tableau[$i]['id_mot'] = $r['id_mot'];
162                                                $tableau[$i]['intersection'] = $intersection['compteur'];
163                                                $tableau[$i]['union'] = $unoulautre['compteur'];
164                                                $tableau[$i]['indice_interet'] = $interet;
165                                                $tableau[$i]['indice_pertinence'] = $pertinence;
166                                                $i++;
167                                        }
168                                }
169                        }
170
171                        // On trie le tableau
172                        if(count($tableau) > 1)
173                                $tableau = tri_multi($tableau, 'indice_total', SORT_DESC);
174
175                        // On genere l'affichage html a partir du tableau
176                        for($j=0; $j != count($tableau); $j++) {
177                                if($j < _RHIZOME_MAX_RETOUR) {
178                                        $retour .= $debut_html.'<a href="'.
179                                                generer_url_mot($tableau[$j]['id_mot']).'" title="Pertinence de la liaison&nbsp;: '.
180                                                ceil($tableau[$j]['indice_total']*100).'&nbsp;%">'.
181                                                $tableau[$j]['titre'].'</a>'.$fin_html;
182                                }
183                        }
184                break;
185        }
186
187        $retour = trim($retour);
188        if ($retour)
189                return $debut_html_general.$retour.$fin_html_general;
190        else
191                return '';
192}
193
194function indice_interet_propre($id,$type='') {
195        if(empty($type)) $type = 'article';
196        switch($type) {
197                case'article':
198                        $r = spip_fetch_array(spip_query("SELECT popularite,
199                                UNIX_TIMESTAMP(date) AS date,
200                                UNIX_TIMESTAMP(date_redac) AS date_redac,
201                                UNIX_TIMESTAMP(date_modif) AS date_modif,
202                                LENGTH(texte) AS longueur
203                                FROM spip_articles
204                                WHERE statut='publie'
205                                AND id_article='$id'"));
206                        // On compte le nombre de message de forums lies a cet article
207                        $nb_forum = spip_fetch_array(spip_query("SELECT COUNT(*) AS forums
208                                FROM spip_forum WHERE statut='public' AND id_article='$id'"));
209
210                        // Si elle est definie, on se base sur la date de publication anterieure
211                        /*
212                        if($r['date_modif'] != '0000-00-00 00:00:00')
213                                $date = $r['date_modif'];
214                        // Sinon, on prend la date normale
215                        else
216                        */
217                        $date = $r['date'];
218                        // On finit par recuperer l'age en jours de l'article
219                        $age = ceil((time() - $date) / (24*60*60));
220
221                        // Construction de l'indice
222                        // On commence par creer des sous-indices ayant chacun une valeur comprise entre 0 et 1
223                        // Les indices sont calcules par la fonction calculer_indice() ci-dessous
224                        // Le troisieme parametre de la fonction calculer_indice definit la fonction de calcul
225                                // Age
226                                $age = _RHIZOME_ARTICLE_DUREE - $age; // On inverse (plus l'age est petit, mieux c'est)
227                                $indice_age = calculer_indice($age,
228                                        _RHIZOME_ARTICLE_DUREE,
229                                        _RHIZOME_ARTICLE_DUREE_MODE);
230
231                                // Nb de forums
232                                $indice_forum = calculer_indice($nb_forum['forums'],
233                                        _RHIZOME_ARTICLE_FORUMS,
234                                        _RHIZOME_ARTICLE_FORUMS_MODE);
235
236                                // Longueur du texte
237                                $indice_longueur = calculer_indice($r['longueur'],
238                                        _RHIZOME_ARTICLE_LONGUEUR,
239                                        _RHIZOME_ARTICLE_LONGUEUR_MODE);
240
241                                // Popularite relative
242                                // TODO: ponderer par la popularite totale du site (ce sera plus pertinent
243                                // mais dans la mesure ou la valeur de l'indice n'est utilisee que de maniere
244                                // relative, ca n'affectera pas la pertinence du filtre rhizome
245                                $indice_popularite = calculer_indice($r['popularite'],
246                                        _RHIZOME_ARTICLE_POPULARITE,
247                                        _RHIZOME_ARTICLE_POPULARITE_MODE);
248
249                        // On agrege les valeurs des differents sous-indices
250                        // Valeur brute, simple somme des sous-indices
251                        $indice = $indice_age + $indice_forum + $indice_longueur + $indice_popularite;
252                        // Calcul du nombre de criteres actifs
253                        $nb_criteres_utilises = 0;
254                        if(_RHIZOME_ARTICLE_DUREE > 0) $nb_criteres_utilises++;
255                        if(_RHIZOME_ARTICLE_FORUMS > 0) $nb_criteres_utilises++;
256                        if(_RHIZOME_ARTICLE_LONGUEUR > 0) $nb_criteres_utilises++;
257                        if(_RHIZOME_ARTICLE_POPULARITE > 0) $nb_criteres_utilises++;
258                        // On evite une division par 0 : si aucun critere n'est actif, l'indice vaut 1
259                        if($nb_criteres_utilises == 0)
260                                $indice = '1';
261                        else
262                        // Ponderation de la valeur brute de l'indice par le nombre de criteres utilises
263                        // NB: chacune a ici la meme ponderation - peut-etre qu'il faudra changer ca
264                        // On en profite pour arrondir a trois decimales
265                                $indice = round($indice / $nb_criteres_utilises, 3);
266
267                break;
268
269                // TODO: configuration fine comme pour case'article'
270                case'mot':
271                        // On compte le nombre d'articles lies a ce mot
272                        $nb_article = spip_fetch_array(spip_query("SELECT
273                                COUNT(*) AS compteur
274                                FROM spip_mots_articles
275                                WHERE id_mot='$id'"));
276                        // On compte le nombre de sites syndiques lies a ce mot
277                        $nb_syndic = spip_fetch_array(spip_query("SELECT
278                                COUNT(*)AS compteur
279                                FROM spip_mots_syndic WHERE id_mot='$id'"));
280                        // On construit l'indice
281                        $indice_article = calculer_indice($nb_article['compteur'],20);
282                        $indice_syndic = calculer_indice($nb_syndic['compteur'],10);
283                        $indice = round(($indice_article * 3 / 4) + ($indice_syndic / 4) , 3);
284                break;
285
286                case'auteur':
287                        $nb_article = spip_query("SELECT COUNT(*) FROM spip_auteurs_articles WHERE id_auteur='$id'");
288                        $indice_article = calculer_indice($nb_article,50);
289                        $indice = $indice_article;
290                break;
291
292        }
293
294        // Par construction, l'indice ne peut pas etre superieur a 1, mais on ne sait jamais
295        if($indice > 1) $indice = 1;
296
297        // Et on renvoie l'indice
298        return $indice;
299}
300
301
302//
303// Calculer un indice dont la valeur est comprise entre 0 et 1
304//   Par defaut, simple fonction du premier degre
305//   NB: Possibilite d'utiliser une fonction logarithmique en passant 'log' en troisieme argument
306//
307function calculer_indice($val, $max, $mode='') {
308        // Si $max est egal a zero, l'indice le sera aussi
309        if($max == 0)
310                return 0;
311        // Sinon, on calcule sa valeur entre 0 et 1
312        else {
313                if($val < 1) $val = 1;
314                if($val > $max) $val = $max;
315                if($mode=='log')
316                        return log($val,$max);
317                else
318                        return $val/$max;
319        }
320}
321
322
323//
324// Trier le tableau
325//
326function tri_multi($tableau, $col, $direction = SORT_DESC) {
327        foreach($tableau as $k=>$v){
328                $cle[$k] = $v[$col];
329        }
330        array_multisort($cle, $direction, $tableau);
331        return $tableau;
332}
333
334?>
Note: See TracBrowser for help on using the repository browser.