source: spip-zone/_plugins_/polyhierarchie/trunk/polyhier_fonctions.php @ 107579

Last change on this file since 107579 was 107579, checked in by rastapopoulos@…, 2 years ago

ce test n'était pas reporté dans la branche trunk

File size: 13.5 KB
Line 
1<?php
2/*
3 * Plugin Polyhierarchie
4 * (c) 2009-2010 Cedric Morin
5 * Distribue sous licence GPL
6 *
7 */
8
9if (!defined("_ECRIRE_INC_VERSION")) return;
10
11/**
12 * {enfants} ou {enfants #ID_RUBRIQUE}
13 * renvoit tous les enfants d'une rubrique ou article
14 * directs (liens descendants) ou indirects (liens transverses)
15 *
16 * @global <type> $exceptions_des_tables
17 * @param <type> $idb
18 * @param <type> $boucles
19 * @param <type> $crit
20 * @param <type> $tous
21 */
22function critere_enfants($idb, &$boucles, $crit, $tous=true) {
23        global $exceptions_des_tables;
24        $boucle = &$boucles[$idb];
25
26        if (isset($crit->param[0])) {
27                $arg = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
28        }
29        else {
30                $arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles));
31        }
32
33        if ($boucle->type_requete == 'rubriques' or isset($exceptions_des_tables[$boucle->id_table]['id_parent'])) {
34                $id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
35                        $exceptions_des_tables[$boucle->id_table]['id_parent'] :
36                        'id_parent';
37                $mparent = $boucle->id_table . '.' . $id_parent;
38        }
39        else {
40                $mparent = $boucle->id_table . '.id_rubrique';
41        }
42
43        $where = array();
44
45        if ($tous!=='indirects') {
46                $where[] = "is_array(\$r=$arg)?sql_in('$mparent',\$r):array('=', '$mparent', \$r)";
47        }
48
49        if ($tous !== 'directs'
50          AND in_array(table_objet_sql($boucle->type_requete),array_keys(lister_tables_objets_sql()))){
51                $type = objet_type($boucle->type_requete);
52                $cond = "is_array(\$r=$arg)?sql_in('rl.id_parent',\$r):'rl.id_parent='.\$r";
53                $sous = "sql_get_select('rl.id_objet','spip_rubriques_liens as rl',$cond.' AND rl.objet=\'$type\'')";
54                $where[] = "array('IN', '" . $boucle->id_table . "." . $boucle->primary . "', '(SELECT * FROM('.$sous.') AS subquery)')";
55        }
56       
57        if (count($where) == 2) {
58                $where = array("'OR'", $where[0], $where[1]);
59        }
60        else {
61                $where = reset($where);
62        }
63
64        $boucle->where[]= $where;
65}
66
67function critere_enfants_directs_dist($idb, &$boucles, $crit) {
68        critere_enfants($idb, $boucles, $crit, 'directs');
69}
70
71function critere_enfants_indirects_dist($idb, &$boucles, $crit) {
72        critere_enfants($idb, $boucles, $crit, 'indirects');
73}
74
75/**
76 * {parents}
77 * renvoit tous les parents d'une rubrique ou article
78 * {parents #ID_RUBRIQUE}
79 * renvoit tous les parents d'une rubrique
80 * directs (liens ascendants) ou indirects (liens transverses)
81 *
82 * @global <type> $exceptions_des_tables
83 * @param <type> $idb
84 * @param <type> $boucles
85 * @param <type> $crit
86 * @param <type> $tous
87 */
88function critere_parents($idb, &$boucles, $crit, $tous=true) {
89        global $exceptions_des_tables;
90       
91        $boucle = &$boucles[$idb];
92        $boucle_parent = $boucles[$boucle->id_parent];
93
94        $primary = $boucle->id_table.".".$boucle->primary;
95
96        $where = array();
97
98        if ($tous !== 'indirects') {
99                $argp = kwote(calculer_argument_precedent($idb, $boucle_parent->type_requete == 'rubriques' ? 'id_parent' : 'id_rubrique', $boucles));
100                $where[] = "is_array(\$r=$argp)?sql_in('$primary',\$r):array('=', '$primary', \$r)";
101        }
102
103        if ($tous !== 'directs'
104          AND in_array(table_objet_sql($boucle_parent->type_requete),array_keys(lister_tables_objets_sql()))){
105                $arg = kwote(calculer_argument_precedent($idb, id_table_objet(objet_type($boucle_parent->type_requete)), $boucles));
106                $type = objet_type($boucle_parent->type_requete);
107                $sous = "sql_get_select('rl.id_parent','spip_rubriques_liens as rl','rl.id_objet='.$arg.' AND rl.objet=\'$type\'')";
108                $where[] = array("'IN'", "'$primary'", "'(SELECT * FROM('.$sous.') AS subquery)'");
109        }
110       
111        if (count($where) == 2) {
112                $where = array("'OR'", $where[0], $where[1]);
113        }
114        else {
115                $where = reset($where);
116        }
117
118        $boucle->where[] = $where;
119}
120
121function critere_parents_directs_dist($idb, &$boucles, $crit) {
122        critere_parents($idb, $boucles, $crit, 'directs');
123}
124function critere_parent($idb, &$boucles, $crit) {
125        critere_parents($idb, $boucles, $crit, 'directs');
126}
127function critere_parents_indirects_dist($idb, &$boucles, $crit) {
128        critere_parents($idb, $boucles, $crit, 'indirects');
129}
130
131
132/**
133 * Calcul d'une branche
134 * (liste des id_rubrique contenues dans une rubrique donnee)
135 * pour le critere {branche}
136 *
137 * @param <type> $id
138 * @return <type>
139 */
140function calcul_branche_polyhier_in($id, $tous=true) {
141        // normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
142        if (!is_array($id)) {
143                $id = explode(',', $id);
144        }
145        $id = array_map('intval', $id);
146       
147        // Notre branche commence par la rubrique de depart
148        $branche = $id;
149       
150        // On ajoute une generation (les filles de la generation precedente)
151        // jusqu'a epuisement
152        while (
153                $id = array_merge(
154                        $filles_directes = ($tous!=='indirects' ? array_map('reset', sql_allfetsel('id_rubrique', 'spip_rubriques', sql_in('id_parent', $id))) : array()),
155                        $filles_indirectes = ($tous!=='directs' ? array_map('reset', sql_allfetsel('id_objet', 'spip_rubriques_liens', "objet='rubrique' AND " . sql_in('id_parent', $id))) : array())
156                )
157        ) {
158                // enlever les rubriques deja trouvee, sinon on risque de tourner en rond a l'infini en cas
159                // de polyhierarchie bouclee
160                $id = array_diff($id, $branche);
161                $branche = array_merge($branche, $id);
162        }
163       
164        return implode(',', $branche);
165}
166
167
168
169/**
170 * {branche ?} ou {branche #ID_RUBRIQUE}
171 * {branche_directe ?} ou {branche_directe #ID_RUBRIQUE}
172 * {branche_principale ?} ou {branche_principale #ID_RUBRIQUE}
173 * {branche_complete ?} ou {branche_complete #ID_RUBRIQUE}
174 *
175 *
176 * @param <type> $idb
177 * @param <type> $boucles
178 * @param <type> $crit
179 */
180function critere_branche($idb, &$boucles, $crit, $tous='elargie') {
181        $not = $crit->not;
182        $boucle = &$boucles[$idb];
183       
184        // On cherche la ou les rubriques dont on demande la branche
185        if (isset($crit->param[0])) {
186                $arg = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
187        }
188        else {
189                $arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles));
190        }
191       
192
193        $type = objet_type($boucle->type_requete);
194        $primary = $boucle->id_table.".".$boucle->primary;
195
196        //Trouver une jointure
197        $champ = "id_rubrique";
198        $desc = $boucle->show;
199        //Seulement si necessaire
200        if (!array_key_exists($champ, $desc['field'])){
201                $trouver_table = charger_fonction("trouver_table", "base");
202                $cle = "";
203                // peut-etre deja une jointure qui fournit id_rubrique ?
204                foreach($boucle->from as $k=>$t){
205                        $desc = $trouver_table($t);
206                        if (isset($desc['field']['id_rubrique'])){
207                                $cle = $k;
208                                break;
209                        }
210                }
211                if (!$cle){
212                        $cle = trouver_jointure_champ($champ, $boucle);
213                        $desc = $trouver_table($boucle->from[$cle]);
214                        if (count(trouver_champs_decomposes($champ, $desc))>1){
215                                $decompose = decompose_champ_id_objet($champ);
216                                $champ = array_shift($decompose);
217                                $boucle->where[] = array("'='", _q($cle.".".reset($decompose)), '"'.sql_quote(end($decompose)).'"');
218                        }
219                }
220                // si le champ id_rubrique est récupéré par jointure, c'est le type et la primary de la table jointe
221                // qu'il faut chercher dans la table spip_rubriques_liens (ie cas des evenements)
222                if ($cle AND $desc) {
223                        $type_jointure = objet_type($boucle->from[$cle]);
224                        $primary_jointure = $cle . "." . id_table_objet($boucle->from[$cle]);
225                }
226        }
227        else {
228                $cle = $boucle->id_table;
229        }
230
231        $where = array();
232
233        // On construit en avance la liste des rubriques
234        $boucle->hash .= "
235        // {branche}
236        if ($arg) {
237                \$in_rub = calcul_branche_polyhier_in($arg," . ($tous === true ? 'true' : "'directs'") . ");
238        }
239        ";
240       
241        // Si c'est tout ou que directs ET qu'on a trouvé un "id_rubrique" quelque part
242        // on ajoute le critère de branche principale, avec le champ id_rubrique
243        if ($tous !== 'indirects' and $cle) {
244                $where[] = "sql_in(
245                        '{$cle}.{$champ}',
246                        \$in_rub"
247                        . ($not ? ", 'NOT'" : '')
248                . ")";
249        }
250       
251        // Si c'est tout ou que indirects, on ajoute le critère de branche secondaire, avec la table de liens
252        if (
253                $tous !== 'directs'
254                and in_array(table_objet_sql($boucle->type_requete), array_keys(lister_tables_objets_sql()))
255        ) {
256                // S'il y a une jointure, on cherche toujours les liaisons avec celle-ci
257                if (isset($type_jointure)) {
258                        $sous_jointure = "sql_get_select('rl.id_objet','spip_rubriques_liens as rl',sql_in('rl.id_parent',\$in_rub" . ($not ? ", 'NOT'" : '') . ").' AND rl.objet=\'$type_jointure\'')";
259                        $where_jointure = "array('IN', '$primary_jointure', '(SELECT * FROM('.$sous_jointure.') AS subquery)')";
260                }
261               
262                // S'il n'y a pas de jointure (cas par défaut) ou que l'objet est explicitement configuré pour être classé avec polyhier
263                // on cherche les liaisons sur l'objet
264                if (
265                        !isset($type_jointure)
266                        or (include_spip('inc/config') and in_array(table_objet_sql($type), lire_config('polyhier/lier_objets', array())))
267                ) {
268                        $sous_objet = "sql_get_select('rl.id_objet','spip_rubriques_liens as rl',sql_in('rl.id_parent',\$in_rub" . ($not ? ", 'NOT'" : '') . ").' AND rl.objet=\'$type\'')";
269                        $where_objet = "array('IN', '$primary', '(SELECT * FROM('.$sous_objet.') AS subquery)')";
270                }
271               
272                // S'il y a les deux, on fait un OR
273                if (isset($where_jointure) and isset($where_objet)) {
274                        $where[] = "array('OR', $where_jointure, $where_objet)";
275                }
276                // Sinon s'il n'y a que jointure
277                elseif (isset($where_jointure)) {
278                        $where[] = $where_jointure;
279                }
280                // Sinon que sur l'objet
281                else {
282                        $where[] = $where_objet;
283                }
284        }
285       
286        // S'il y a les deux critères, c'est l'un ou l'autre
287        if (count($where) == 2) {
288                $where = "array('OR'," . $where[0] . "," . $where[1] . ")";
289        }
290        else {
291                $where = reset($where);
292        }
293       
294        $boucle->where[] = !$crit->cond ? $where : ("($arg ? $where : " . ($not ? "'0=1'" : "'1=1'") . ')');
295}
296
297function critere_branche_principale_dist($idb, &$boucles, $crit) {
298        critere_branche($idb, $boucles, $crit, 'directs');
299}
300// un alias
301function critere_branche_directe_dist($idb, &$boucles, $crit) {
302        critere_branche($idb, $boucles, $crit, 'directs');
303}
304function critere_branche_indirecte_dist($idb, &$boucles, $crit) {
305        critere_branche($idb, $boucles, $crit, 'indirects');
306}
307function critere_branche_complete_dist($idb, &$boucles, $crit) {
308        critere_branche($idb, $boucles, $crit, true);
309}
310
311/*
312 * Déclarer un fonction générique pour pouvoir chercher dans les champs des rubriques liées
313 *
314 */
315function inc_rechercher_joints_objet_rubrique_dist($table, $table_liee, $ids_trouves, $serveur) {
316        $cle_depart = id_table_objet($table);
317       
318        $s = sql_select(
319                "id_objet as $cle_depart, id_parent as id_rubrique",
320                'spip_rubriques_liens',
321                array("objet='$table'", sql_in('id_parent', $ids_trouves)),
322                '', '', '', '', $serveur
323        );
324       
325        return array($cle_depart, 'id_rubrique', $s);
326}
327
328/**
329 * Filtre pour appeler polyhier_get_enfants depuis un squelette
330 * @param $id_parent
331 * @param string $objet
332 * @param string $serveur
333 * @return array
334 */
335function filtre_polyhier_get_enfants_dist($id_parent, $objet='', $serveur='') {
336        include_spip('inc/polyhier');
337        return polyhier_get_enfants($id_parent, $objet, $serveur);
338}
339
340function filtre_polyhier_lister_enfants($objet,$ids){
341        $fond = "prive/objets/liste/".table_objet($objet);
342        if (trouver_fond($fond)){
343                $primary = id_table_objet($objet);
344                return recuperer_fond($fond,array($primary=>$ids));
345        }
346}
347
348
349/**
350 * Compile la balise `#URL_POLYHIER{#ID_RUBRIQUE,article,#ID_ARTICLE}`
351 * qui génère l'URL d'un article contextualisee a l'une de ses rubriques parentes
352 *
353 * Si la rubrique passee en argument n'est pas une rubrique parente elle est ignoree
354 * Si les URLs ne contiennent pas l'URL de la rubrique parente (URL arbo), la rubrique contextuelle est ajoutee en query string
355 *
356 * @balise
357 * @example
358 *     ```
359 *     #URL_POLYHIER{#ENV{id_rubrique,#ID_RUBRIQUE},article,#ID_ARTICLE}
360 *     ```
361 * @param Champ $p
362 *     Pile au niveau de la balise
363 * @return Champ
364 *     Pile complétée par le code à générer
365 */
366function balise_URL_POLYHIER_dist($p) {
367
368        $_id_rubrique = interprete_argument_balise(1, $p);
369        $_type = interprete_argument_balise(2, $p);
370        $_id = interprete_argument_balise(3, $p);
371
372        $code = "urlencode_1738(generer_url_polyhier_entite($_id, $_type, $_id_rubrique))";
373        $p->code = $code;
374        if (!$p->etoile) {
375                $p->code = "vider_url($code)";
376        }
377        $p->interdire_scripts = false;
378
379        return $p;
380}
381
382/**
383 * Generer l'URL polyhierarchique d'un objet relativement a une rubrique parente secondaire
384 * on cherche le parent secondaire qui est dans la branche de la rubrique fournie et on le passe en argument
385 * de l'URL. Si le module URL le gere (arbopoly) l'URL reposera sur l'URL de ce parent secondaire,
386 * sinon elle restera en argument
387 *
388 * a charge pour les squelettes de gerer la presence du id_rubrique=xxx dans le contexte de la page de l'objet concerne
389 *
390 * Ne fonctionne que si l'objet est lui même rattache en polyhierarchie,
391 * pas si il est enfant direct d'une rubrique enfant secondaire
392 *
393 * @param int $id_objet
394 * @param string $objet
395 * @param int $id_rubrique
396 * @param string $args
397 * @param string $ancre
398 * @return string
399 */
400function generer_url_polyhier_entite($id_objet, $objet, $id_rubrique=null, $args='', $ancre='') {
401
402        // si id_rubrique contextuel passe en argument et si c'est bien un parent polyhierarchique
403        $parents_poly = sql_allfetsel('id_parent','spip_rubriques_liens', 'objet='.sql_quote($objet). ' AND id_objet='.intval($id_objet));
404        $parents_poly = array_map('reset',$parents_poly);
405
406        $maxiter = 100;
407        $branche = $r = array($id_rubrique);
408        while (!($id_parent = array_intersect($parents_poly, $r))
409          and $maxiter--
410          and $filles = sql_allfetsel('id_rubrique','spip_rubriques',sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $branche, 'NOT'))) {
411                $r = array_map('reset', $filles);
412                $branche = array_merge($branche, $r);
413        }
414
415        if ($id_parent = reset($id_parent)) {
416                // le vrai parent
417                $champ_parent = ($objet == 'rubrique' ? 'id_parent' : 'id_rubrique');
418                $args .= ($args?'&':'')."$champ_parent=$id_parent";
419        }
420        $url = generer_url_entite($id_objet, $objet, $args, $ancre, true);
421        return $url;
422}
Note: See TracBrowser for help on using the repository browser.