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

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

Revert d'une partie de [96182] : non on ne doit pas aller chercher les liens indirects sur une autre table que celle demandé. Cette modif casse complètement de nombreux squelettes qui marchaient bien avant (on vient seulement de le voir et comprendre pourquoi).

Le principe des tables de liens avec objet/id_objet c'est de pouvoir les utiliser sur les objets que l'on veut. Donc ensuite quand on demande les liens de rubrique pour les objets "patates", on VEUT les liens avec "patates", pas avec un autre objet calculé et remplacé en cachette comme ça. Quand on demande "les événements liés en polyhier aux rubriques de la branche 30" on veut bien les événements qui y sont liés, pas les événements des articles de cette branche ce qui n'a rien à voir.

Si des gens ont besoin d'une fonctionnalité différente en cherchant les articles parents liés, c'est autre chose, et il faudrait un autre critère ou bien un paramètre explicite supplémentaire à ce critère. Mais le fonctionnement normal, cohérent, toujours sur l'objet demandé, doit rester le même.

File size: 12.0 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        }
221        else {
222                $cle = $boucle->id_table;
223        }
224
225        $where = array();
226
227        // On construit en avance la liste des rubriques
228        $boucle->hash .= "
229        // {branche}
230        if ($arg) {
231                \$in_rub = calcul_branche_polyhier_in($arg," . ($tous === true ? 'true' : "'directs'") . ");
232        }
233        ";
234       
235        // Si c'est tout ou que directs ET qu'on a trouvé un "id_rubrique" quelque part
236        // on ajoute le critère de branche principale, avec le champ id_rubrique
237        if ($tous !== 'indirects' and $cle) {
238                $where[] = "sql_in(
239                        '{$cle}.{$champ}',
240                        \$in_rub"
241                        . ($not ? ", 'NOT'" : '')
242                . ")";
243        }
244       
245        // Si c'est tout ou que indirects, on ajoute le critère de branche secondaire, avec la table de liens
246        if ($tous !== 'directs') {
247               
248                $sous = "sql_get_select('rl.id_objet','spip_rubriques_liens as rl',sql_in('rl.id_parent',\$in_rub" . ($not ? ", 'NOT'" : '') . ").' AND rl.objet=\'$type\'')";
249                $where[] = "array('IN', '$primary', '(SELECT * FROM('.$sous.') AS subquery)')";
250        }
251       
252        // S'il y a les deux critères, c'est l'un ou l'autre
253        if (count($where) == 2) {
254                $where = "array('OR'," . $where[0] . "," . $where[1] . ")";
255        }
256        else {
257                $where = reset($where);
258        }
259       
260        $boucle->where[] = !$crit->cond ? $where : ("($arg ? $where : " . ($not ? "'0=1'" : "'1=1'") . ')');
261}
262
263function critere_branche_principale_dist($idb, &$boucles, $crit) {
264        critere_branche($idb, $boucles, $crit, 'directs');
265}
266// un alias
267function critere_branche_directe_dist($idb, &$boucles, $crit) {
268        critere_branche($idb, $boucles, $crit, 'directs');
269}
270function critere_branche_indirecte_dist($idb, &$boucles, $crit) {
271        critere_branche($idb, $boucles, $crit, 'indirects');
272}
273function critere_branche_complete_dist($idb, &$boucles, $crit) {
274        critere_branche($idb, $boucles, $crit, true);
275}
276
277/*
278 * Déclarer un fonction générique pour pouvoir chercher dans les champs des rubriques liées
279 *
280 */
281function inc_rechercher_joints_objet_rubrique_dist($table, $table_liee, $ids_trouves, $serveur) {
282        $cle_depart = id_table_objet($table);
283       
284        $s = sql_select(
285                "id_objet as $cle_depart, id_parent as id_rubrique",
286                'spip_rubriques_liens',
287                array("objet='$table'", sql_in('id_parent', $ids_trouves)),
288                '', '', '', '', $serveur
289        );
290       
291        return array($cle_depart, 'id_rubrique', $s);
292}
293
294/**
295 * Filtre pour appeler polyhier_get_enfants depuis un squelette
296 * @param $id_parent
297 * @param string $objet
298 * @param string $serveur
299 * @return array
300 */
301function filtre_polyhier_get_enfants_dist($id_parent, $objet='', $serveur='') {
302        include_spip('inc/polyhier');
303        return polyhier_get_enfants($id_parent, $objet, $serveur);
304}
305
306function filtre_polyhier_lister_enfants($objet,$ids){
307        $fond = "prive/objets/liste/".table_objet($objet);
308        if (trouver_fond($fond)){
309                $primary = id_table_objet($objet);
310                return recuperer_fond($fond,array($primary=>$ids));
311        }
312}
313
314
315/**
316 * Compile la balise `#URL_POLYHIER{#ID_RUBRIQUE,article,#ID_ARTICLE}`
317 * qui génère l'URL d'un article contextualisee a l'une de ses rubriques parentes
318 *
319 * Si la rubrique passee en argument n'est pas une rubrique parente elle est ignoree
320 * Si les URLs ne contiennent pas l'URL de la rubrique parente (URL arbo), la rubrique contextuelle est ajoutee en query string
321 *
322 * @balise
323 * @example
324 *     ```
325 *     #URL_POLYHIER{#ENV{id_rubrique,#ID_RUBRIQUE},article,#ID_ARTICLE}
326 *     ```
327 * @param Champ $p
328 *     Pile au niveau de la balise
329 * @return Champ
330 *     Pile complétée par le code à générer
331 */
332function balise_URL_POLYHIER_dist($p) {
333
334        $_id_rubrique = interprete_argument_balise(1, $p);
335        $_type = interprete_argument_balise(2, $p);
336        $_id = interprete_argument_balise(3, $p);
337
338        $code = "urlencode_1738(generer_url_polyhier_entite($_id, $_type, $_id_rubrique))";
339        $p->code = $code;
340        if (!$p->etoile) {
341                $p->code = "vider_url($code)";
342        }
343        $p->interdire_scripts = false;
344
345        return $p;
346}
347
348/**
349 * Generer l'URL polyhierarchique d'un objet relativement a une rubrique parente secondaire
350 * on cherche le parent secondaire qui est dans la branche de la rubrique fournie et on le passe en argument
351 * de l'URL. Si le module URL le gere (arbopoly) l'URL reposera sur l'URL de ce parent secondaire,
352 * sinon elle restera en argument
353 *
354 * a charge pour les squelettes de gerer la presence du id_rubrique=xxx dans le contexte de la page de l'objet concerne
355 *
356 * Ne fonctionne que si l'objet est lui même rattache en polyhierarchie,
357 * pas si il est enfant direct d'une rubrique enfant secondaire
358 *
359 * @param int $id_objet
360 * @param string $objet
361 * @param int $id_rubrique
362 * @param string $args
363 * @param string $ancre
364 * @return string
365 */
366function generer_url_polyhier_entite($id_objet, $objet, $id_rubrique=null, $args='', $ancre='') {
367
368        // si id_rubrique contextuel passe en argument et si c'est bien un parent polyhierarchique
369        $parents_poly = sql_allfetsel('id_parent','spip_rubriques_liens', 'objet='.sql_quote($objet). ' AND id_objet='.intval($id_objet));
370        $parents_poly = array_map('reset',$parents_poly);
371
372        $maxiter = 100;
373        $branche = $r = array($id_rubrique);
374        while (!($id_parent = array_intersect($parents_poly, $r))
375          and $maxiter--
376          and $filles = sql_allfetsel('id_rubrique','spip_rubriques',sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $branche, 'NOT'))) {
377                $r = array_map('reset', $filles);
378                $branche = array_merge($branche, $r);
379        }
380
381        if ($id_parent = reset($id_parent)) {
382                // le vrai parent
383                $champ_parent = ($objet == 'rubrique' ? 'id_parent' : 'id_rubrique');
384                $args .= ($args?'&':'')."$champ_parent=$id_parent";
385        }
386        $url = generer_url_entite($id_objet, $objet, $args, $ancre, true);
387        return $url;
388}
Note: See TracBrowser for help on using the repository browser.