source: spip-zone/_plugins_/groupes_mots_arborescents/gma_fonctions.php @ 63401

Last change on this file since 63401 was 63401, checked in by marcimat@…, 9 years ago

Plugin «Groupes de mots arborescents» de préfixe «gma» qui permet de faire des hiérarchies de groupes de mots.

Il ne fonctionne pour l'instant qu'avec la version trunk du plugin mots.

On peut donc créer une arborescence de groupes de mots, et mettre des mots dans chaque groupe.

  • Les propriétés d'un sous groupe de mots héritent automatiquement du groupe racine (et ne sont pas modifiable hors du groupe racine)
  • Le squelettes de liaison des mots clés sont sur surchargés pour ne lister que les groupes racines, et afficher dans les sélecteurs l'arborescence complète des groupes et mots.
  • On ne peut supprimer un groupe que si le groupe n'a pas de sous groupe

Par ailleurs, on utilise une implémentation de QueryPath? (http://querypath.org/) (non sans mal) pour modifier le code HTML du formulaire de groupes de mots.

Cette librairie quoi que très bien s'appuie sur la classe domDocument elle même s'appuyant sur libxml2 qui a un léger bug lors de l'import d'un texte HTML qui possède des CDATA dans des scripts : la librairie double alors ces échappements par des nouveaux ! Du coup, on les enlève avant d'utiliser la librairie (qui de toutes façons les remets).

Cette librairie pourrait être mise dans un plugin spécifique car très pratique une fois les soucis réglés (CDATA et passer le texte en unicode avant importation).

File size: 7.6 KB
Line 
1<?php
2
3/**
4 * Plugin Groupes arborescents de mots clés
5 * (c) 2012 Marcillaud Matthieu
6 * Licence GNU/GPL
7 */
8
9if (!defined('_ECRIRE_INC_VERSION')) return;
10
11
12/**
13 * Gère des héritages sur les groupes et mots
14 *
15 * Sur les tables groupes
16 * - définir les groupes racines
17 * - définir les configs héritées (de la racine)
18 * Sur les mots
19 * - définir les groupes racines
20 *
21 * @example
22 *              gma_definir_heritages();  // recalcule tout
23 *              gma_definir_heritages(3); // recalcule le groupe 3 et ses enfants
24 *
25 * @param int $id_parent
26 *              Identifiant du groupe à modifier
27 *              C'est le seul paramètre éventuellement a passer
28 * @param null|array $heritage
29 *              Config a heriter aux enfants
30 * @param bool $update_mots
31 *              Met a jour les mots au passage (id_groupe_racine)
32 * @return void
33**/
34function gma_definir_heritages($id_groupe = null, $heritage=null, $update_mots=true) {
35        // liste des champs de config
36        static $champs_herites = null;
37        static $champs = array('id_groupe', 'id_parent', 'id_groupe_racine');
38
39        if (is_null($champs_herites)) {
40                // liste des champs qui doivent hériter du groupe racine automatiquement
41                $champs_herites = pipeline('groupes_mots_arborescents_heritages', array(
42                        'unseul', 'obligatoire', 'comite', 'forum', 'minirezo', 'tables_liees'
43                ));
44                // ajout des héritages à la liste des champs
45                $champs += $champs_herites;
46        }
47
48        // pas de groupe spécifique ?
49        if (is_null($id_groupe)) {
50                // on applique notre fonction à tous les groupes racines
51                $groupes = sql_allfetsel($champs, 'spip_groupes_mots', 'id_parent=' . sql_quote(0));
52                foreach ($groupes as $groupe) {
53                        $id_groupe = $groupe['id_groupe'];
54                        // le reste est la config a faire hériter
55                        unset($groupe['id_groupe'], $groupe['id_parent']);
56                        $groupe['id_groupe_racine'] = $id_groupe;
57                        gma_definir_heritages($id_groupe, $groupe);
58                }
59                return true;
60        }
61
62        // pas de vide par erreur
63        if (!$id_groupe) {
64                return false;
65        }
66
67        // pour le groupe en cours
68        // on retrouve la racine et la config s'ils ne sont pas connus,
69        // si possible dans le groupe parent (s'il existe)
70        if (is_null($heritage)) {
71                $heritage = sql_fetsel($champs, 'spip_groupes_mots', 'id_groupe=' . sql_quote($id_groupe));
72                if (!$heritage) {
73                        return false;
74                }
75                if ($heritage['id_parent']) {
76                        $heritage = sql_fetsel($champs, 'spip_groupes_mots', 'id_groupe=' . sql_quote($heritage['id_parent']));
77                }
78                // le reste est la config a faire hériter
79                unset($heritage['id_groupe'], $heritage['id_parent']);
80        }
81
82        // a ce stade, on a la racine et la config
83        // pour chaque groupe enfant, on les transmets
84        $groupes = calcul_branche_groupe_in($id_groupe);
85        sql_updateq('spip_groupes_mots', $heritage, sql_in('id_groupe', $groupes));
86
87        // pour chaque mots du groupe, on definit la racine
88        if ($update_mots) {
89                sql_updateq('spip_mots',
90                        array('id_groupe_racine' => $heritage['id_groupe_racine']),
91                        sql_in('id_groupe', $groupes));
92        }
93
94}
95
96
97
98
99/**
100 * Calcul d'une branche de groupes de mots
101 *
102 * Liste des id_groupes contenus dans un groupe de mots donné
103 * pour le critere {branche_groupe}
104 *
105 * @internal
106 *     Fonction quasiment identique a inc_calcul_branche_in_dist() du core
107 *
108 * @param string|int|array $id
109 *     Identifiant du groupe dont on veut récuperer toute la branche
110 * @return string
111 *     Liste des ids, séparés par des virgules
112 */
113function calcul_branche_groupe_in($id) {
114        static $b = array();
115
116        // normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
117        if (!is_array($id)) $id = explode(',',$id);
118        $id = join(',', array_map('intval', $id));
119        if (isset($b[$id]))
120                return $b[$id];
121
122        // Notre branche commence par la rubrique de depart
123        $branche = $r = $id;
124
125        // On ajoute une generation (les filles de la generation precedente)
126        // jusqu'a epuisement
127        while ($filles = sql_allfetsel(
128                                        'id_groupe',
129                                        'spip_groupes_mots',
130                                        sql_in('id_parent', $r)." AND ". sql_in('id_groupe', $r, 'NOT')
131                                        )) {
132                $r = join(',', array_map('array_shift', $filles));
133                $branche .= ',' . $r;
134        }
135
136        # securite pour ne pas plomber la conso memoire sur les sites prolifiques
137        if (strlen($branche)<10000)
138                $b[$id] = $branche;
139        return $branche;
140}
141
142
143
144/**
145 * Sélectionne dans une boucle les éléments appartenant à une branche d'un groupe de mot
146 *
147 * Calcule une branche d'un groupe de mots et conditionne la boucle avec.
148 * Cherche l'identifiant du groupe dans les boucles parentes ou par jointure
149 * et calcule la liste des identifiants de groupes de toute la branche
150 *
151 * @internal
152 *              Copie quasi identique de critere_branche_dist()
153 *
154 * @param string $idb
155 *              Identifiant de la boucle
156 * @param array $boucles
157 *              AST du squelette
158 * @param array $crit
159 *              Paramètres du critère dans cette boucle
160 * @return
161 *              AST complété de la condition where au niveau de la boucle,
162 *              restreignant celle ci aux groupes de la branche
163**/
164function critere_branche_groupe_dist($idb, &$boucles, $crit){
165
166        $not = $crit->not;
167        $boucle = &$boucles[$idb];
168        $arg = calculer_argument_precedent($idb, 'id_groupe', $boucles);
169
170        //Trouver une jointure
171        $champ = "id_groupe";
172        $desc = $boucle->show;
173        //Seulement si necessaire
174        if (!array_key_exists($champ, $desc['field'])){
175                $cle = trouver_jointure_champ($champ, $boucle);
176                $trouver_table = charger_fonction("trouver_table", "base");
177                $desc = $trouver_table($boucle->from[$cle]);
178                if (count(trouver_champs_decomposes($champ, $desc))>1){
179                        $decompose = decompose_champ_id_objet($champ);
180                        $champ = array_shift($decompose);
181                        $boucle->where[] = array("'='", _q($cle.".".reset($decompose)), '"'.sql_quote(end($decompose)).'"');
182                }
183        }
184        else $cle = $boucle->id_table;
185
186        $c = "sql_in('$cle".".$champ', calcul_branche_groupe_in($arg)"
187             .($not ? ", 'NOT'" : '').")";
188        $boucle->where[] = !$crit->cond ? $c :
189                ("($arg ? $c : ".($not ? "'0=1'" : "'1=1'").')');
190}
191
192
193
194/**
195 * Boucle HIERARCHIE_GROUPES_MOTS
196**/
197function boucle_HIERARCHIE_GROUPES_MOTS_dist($id_boucle, &$boucles) {
198        return boucle_HIERARCHIE_PARENT_dist($id_boucle, $boucles, 'id_groupe', 'spip_groupes_mots');
199}
200
201
202
203if (!function_exists('boucle_HIERARCHIE_PARENT_dist')) {
204/**
205 * Boucle HIERARCHIE mais
206 * qui n'est pas dependante d'un id_rubrique
207 *
208**/
209function boucle_HIERARCHIE_PARENT_dist($id_boucle, &$boucles, $primary, $table) {
210        $boucle = &$boucles[$id_boucle];
211        $id_table = $boucle->id_table . "." . $primary;
212
213        // Si la boucle mere est une boucle de $TABLE il faut ignorer la feuille
214        // sauf en presence du critere {tout} (vu par phraser_html)
215        // ou {id_article} qui positionne aussi le {tout}
216
217        $boucle->hierarchie = 'if (!($id_objet = intval('
218        . calculer_argument_precedent($boucle->id_boucle, $primary, $boucles)
219        . ")))\n\t\treturn '';\n\t"
220        . '$hierarchie = '
221        . (isset($boucle->modificateur['tout']) ? '",$id_objet"' : "''")
222        . ";\n\t"
223        . 'while ($id_objet = sql_getfetsel("id_parent","' . $table . '","' . $primary . '=" . $id_objet,"","","", "", $connect)) {
224                $hierarchie = ",$id_objet$hierarchie";
225        }
226        if (!$hierarchie) return "";
227        $hierarchie = substr($hierarchie,1);';
228
229        // On enlève l'ancien critère "id_truc" du where
230        // provenant de <BOUCLE_h(HIERARCHIE_TRUC){id_truc} />
231        foreach ($boucle->where as $cle=>$where) {
232                if (count($where) == 3
233                        and ($where[0] == "'='" or $where[0] == '"="')
234                        and ($where[1] == "'$id_table'" or $where[1] == '"'.$id_table.'"')){
235                                unset($boucle->where[$cle]);
236                                $boucle->where = array_values($boucle->where); // recalculer les cles du tableau
237                }
238        }
239
240        $boucle->where[] = array("'IN'", "'$id_table'", '"($hierarchie)"');
241
242        $order = "FIELD($id_table, \$hierarchie)";
243
244        if (!isset($boucle->default_order[0]) OR $boucle->default_order[0] != " DESC")
245                $boucle->default_order[] = "\"$order\"";
246        else
247                $boucle->default_order[0] = "\"$order DESC\"";
248        return calculer_boucle($id_boucle, $boucles); 
249}
250}
251
252?>
Note: See TracBrowser for help on using the repository browser.