source: spip-zone/_plugins_/polyhierarchie/branches/v2.0/polyhier_fonctions.php @ 107572

Last change on this file since 107572 was 107572, checked in by rastapopoulos@…, 19 months ago

Backport de [107571] : Revert d'une partie de [96181] : 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: 10.8 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        if ($boucle->type_requete == 'rubriques' OR isset($exceptions_des_tables[$boucle->id_table]['id_parent'])) {
33                $id_parent = isset($exceptions_des_tables[$boucle->id_table]['id_parent']) ?
34                        $exceptions_des_tables[$boucle->id_table]['id_parent'] :
35                        'id_parent';
36                $mparent = $boucle->id_table . '.' . $id_parent;
37        }
38        else {
39                $mparent = $boucle->id_table . '.id_rubrique';
40        }
41
42        $where = array();
43
44        if ($tous!=='indirects')
45                $where[] = "is_array(\$r=$arg)?sql_in('$mparent',\$r):array('=', '$mparent', \$r)";
46
47        if ($tous!=='directs'
48          AND in_array(table_objet_sql($boucle->type_requete),array_keys(lister_tables_objets_sql()))){
49                $type = objet_type($boucle->type_requete);
50                $cond = "is_array(\$r=$arg)?sql_in('rl.id_parent',\$r):'rl.id_parent='.\$r";
51                $sous = "sql_get_select('rl.id_objet','spip_rubriques_liens as rl',$cond.' AND rl.objet=\'$type\'')";
52                $where[] = "array('IN', '".$boucle->id_table.".".$boucle->primary."', '(SELECT * FROM('.$sous.') AS subquery)')";
53        }
54        if (count($where)==2)
55                $where = array("'OR'",$where[0],$where[1]);
56        else
57                $where = reset($where);
58
59        $boucle->where[]= $where;
60}
61
62function critere_enfants_directs_dist($idb, &$boucles, $crit) {
63        critere_enfants($idb, $boucles, $crit, 'directs');
64}
65
66function critere_enfants_indirects_dist($idb, &$boucles, $crit) {
67        critere_enfants($idb, $boucles, $crit, 'indirects');
68}
69
70/**
71 * {parents}
72 * renvoit tous les parents d'une rubrique ou article
73 * {parents #ID_RUBRIQUE}
74 * renvoit tous les parents d'une rubrique
75 * directs (liens ascendants) ou indirects (liens transverses)
76 *
77 * @global <type> $exceptions_des_tables
78 * @param <type> $idb
79 * @param <type> $boucles
80 * @param <type> $crit
81 * @param <type> $tous
82 */
83function critere_parents($idb, &$boucles, $crit, $tous=true) {
84        global $exceptions_des_tables;
85        $boucle = &$boucles[$idb];
86        $boucle_parent = $boucles[$boucle->id_parent];
87
88        $primary = $boucle->id_table.".".$boucle->primary;
89
90        $where = array();
91
92        if ($tous!=='indirects'){
93                $argp = kwote(calculer_argument_precedent($idb, $boucle_parent->type_requete == 'rubriques' ? 'id_parent' : 'id_rubrique', $boucles));
94                $where[] = "is_array(\$r=$argp)?sql_in('$primary',\$r):array('=', '$primary', \$r)";
95        }
96
97        if ($tous!=='directs'
98          AND in_array(table_objet_sql($boucle_parent->type_requete),array_keys(lister_tables_objets_sql()))){
99                $arg = kwote(calculer_argument_precedent($idb, id_table_objet(objet_type($boucle_parent->type_requete)), $boucles));
100                $type = objet_type($boucle_parent->type_requete);
101                $sous = "sql_get_select('rl.id_parent','spip_rubriques_liens as rl','rl.id_objet='.$arg.' AND rl.objet=\'$type\'')";
102                $where[] = array("'IN'", "'$primary'", "'(SELECT * FROM('.$sous.') AS subquery)'");
103        }
104        if (count($where)==2)
105                $where = array("'OR'",$where[0],$where[1]);
106        else
107                $where = reset($where);
108
109        $boucle->where[]= $where;
110}
111
112function critere_parents_directs_dist($idb, &$boucles, $crit) {
113        critere_parents($idb, $boucles, $crit, 'directs');
114}
115function critere_parent($idb, &$boucles, $crit) {
116        critere_parents($idb, $boucles, $crit, 'directs');
117}
118
119function critere_parents_indirects_dist($idb, &$boucles, $crit) {
120        critere_parents($idb, $boucles, $crit, 'indirects');
121}
122
123
124/**
125 * Calcul d'une branche
126 * (liste des id_rubrique contenues dans une rubrique donnee)
127 * pour le critere {branche}
128 *
129 * @param <type> $id
130 * @return <type>
131 */
132function calcul_branche_polyhier_in($id, $tous=true) {
133
134        // normaliser $id qui a pu arriver comme un array, comme un entier, ou comme une chaine NN,NN,NN
135        if (!is_array($id)) $id = explode(',',$id);
136        $id = array_map('intval', $id);
137
138        // Notre branche commence par la rubrique de depart
139        $branche = $id;
140
141        // On ajoute une generation (les filles de la generation precedente)
142        // jusqu'a epuisement
143        while (
144                $id = array_merge(
145                $filles_directes = ($tous!=='indirects'?array_map('reset',sql_allfetsel('id_rubrique', 'spip_rubriques',sql_in('id_parent', $id))):array()),
146                $filles_indirectes = ($tous!=='directs'?array_map('reset',sql_allfetsel('id_objet', 'spip_rubriques_liens',"objet='rubrique' AND " . sql_in('id_parent', $id))):array())
147                )) {
148
149                // enlever les rubriques deja trouvee, sinon on risque de tourner en rond a l'infini en cas
150                // de polyhierarchie bouclee
151                $id = array_diff($id,$branche);
152                $branche = array_merge($branche,$id);
153        }
154
155        return implode(',',$branche);
156}
157
158
159
160/**
161 * {branche ?} ou {branche #ID_RUBRIQUE}
162 * {branche_directe ?} ou {branche_directe #ID_RUBRIQUE}
163 * {branche_principale ?} ou {branche_principale #ID_RUBRIQUE}
164 * {branche_complete ?} ou {branche_complete #ID_RUBRIQUE}
165 *
166 *
167 * @param <type> $idb
168 * @param <type> $boucles
169 * @param <type> $crit
170 */
171function critere_branche($idb, &$boucles, $crit, $tous='elargie') {
172
173        $not = $crit->not;
174        $boucle = &$boucles[$idb];
175        if (isset($crit->param[0])){
176                $arg = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
177        }
178        else
179                $arg = kwote(calculer_argument_precedent($idb, 'id_rubrique', $boucles));
180
181        $type = objet_type($boucle->type_requete);
182        $primary = $boucle->id_table.".".$boucle->primary;
183
184        //Trouver une jointure
185        $champ = "id_rubrique";
186        $desc = $boucle->show;
187        //Seulement si necessaire
188        if (!array_key_exists($champ, $desc['field'])){
189                $trouver_table = charger_fonction("trouver_table", "base");
190                $cle = "";
191                // peut-etre deja une jointure qui fournit id_rubrique ?
192                foreach($boucle->from as $k=>$t){
193                        $desc = $trouver_table($t);
194                        if (isset($desc['field']['id_rubrique'])){
195                                $cle = $k;
196                                break;
197                        }
198                }
199                if (!$cle){
200                        $cle = trouver_jointure_champ($champ, $boucle);
201                        $desc = $trouver_table($boucle->from[$cle]);
202                        if (count(trouver_champs_decomposes($champ, $desc))>1){
203                                $decompose = decompose_champ_id_objet($champ);
204                                $champ = array_shift($decompose);
205                                $boucle->where[] = array("'='", _q($cle.".".reset($decompose)), '"'.sql_quote(end($decompose)).'"');
206                        }
207                }
208        }
209        else $cle = $boucle->id_table;
210
211
212        $c = "sql_in('$cle" . ".$champ', \$b = calcul_branche_polyhier_in($arg,".($tous===true?'true':"'directs'").")"
213          . ($not ? ", 'NOT'" : '') . ")";
214        $where[] = $c;
215       
216        if ($tous!=='directs'
217          AND in_array(table_objet_sql($boucle->type_requete),array_keys(lister_tables_objets_sql()))){
218                $sous = "sql_get_select('rl.id_objet','spip_rubriques_liens as rl',sql_in('rl.id_parent',\$b" . ($not ? ", 'NOT'" : '') . ").' AND rl.objet=\'$type\'')";
219                $where[] = "array('IN', '$primary', '(SELECT * FROM('.$sous.') AS subquery)')";
220        }
221
222        if (count($where)==2)
223                $where = "array('OR',".$where[0].",".$where[1].")";
224        else
225                $where = reset($where);
226
227        $boucle->where[]= !$crit->cond ? $where :
228          ("($arg ? $where : " . ($not ? "'0=1'" : "'1=1'") .')');
229}
230
231function critere_branche_principale_dist($idb, &$boucles, $crit) {
232        critere_branche($idb, $boucles, $crit, 'directs');
233}
234// un alias
235function critere_branche_directe_dist($idb, &$boucles, $crit) {
236        critere_branche($idb, $boucles, $crit, 'directs');
237}
238
239function critere_branche_complete_dist($idb, &$boucles, $crit) {
240        critere_branche($idb, $boucles, $crit, true);
241}
242
243/*
244 * Déclarer un fonction générique pour pouvoir chercher dans les champs des rubriques liées
245 *
246 */
247function inc_rechercher_joints_objet_rubrique_dist($table, $table_liee, $ids_trouves, $serveur){
248        $cle_depart = id_table_objet($table);
249        $s = sql_select(
250                "id_objet as $cle_depart, id_parent as id_rubrique",
251                'spip_rubriques_liens',
252                array("objet='$table'", sql_in('id_parent', $ids_trouves)),
253                '','','','',$serveur
254        );
255        return array($cle_depart, 'id_rubrique', $s);
256}
257
258
259
260/**
261 * Compile la balise `#URL_POLYHIER{#ID_RUBRIQUE,article,#ID_ARTICLE}`
262 * qui génère l'URL d'un article contextualisee a l'une de ses rubriques parentes
263 *
264 * Si la rubrique passee en argument n'est pas une rubrique parente elle est ignoree
265 * Si les URLs ne contiennent pas l'URL de la rubrique parente (URL arbo), la rubrique contextuelle est ajoutee en query string
266 *
267 * @balise
268 * @example
269 *     ```
270 *     #URL_POLYHIER{#ENV{id_rubrique,#ID_RUBRIQUE},article,#ID_ARTICLE}
271 *     ```
272 * @param Champ $p
273 *     Pile au niveau de la balise
274 * @return Champ
275 *     Pile complétée par le code à générer
276 */
277function balise_URL_POLYHIER_dist($p) {
278
279        $_id_rubrique = interprete_argument_balise(1, $p);
280        $_type = interprete_argument_balise(2, $p);
281        $_id = interprete_argument_balise(3, $p);
282
283        $code = "urlencode_1738(generer_url_polyhier_entite($_id, $_type, $_id_rubrique))";
284        $p->code = $code;
285        if (!$p->etoile) {
286                $p->code = "vider_url($code)";
287        }
288        $p->interdire_scripts = false;
289
290        return $p;
291}
292
293/**
294 * Generer l'URL polyhierarchique d'un objet relativement a une rubrique parente secondaire
295 * on cherche le parent secondaire qui est dans la branche de la rubrique fournie et on le passe en argument
296 * de l'URL. Si le module URL le gere (arbopoly) l'URL reposera sur l'URL de ce parent secondaire,
297 * sinon elle restera en argument
298 *
299 * a charge pour les squelettes de gerer la presence du id_rubrique=xxx dans le contexte de la page de l'objet concerne
300 *
301 * Ne fonctionne que si l'objet est lui même rattache en polyhierarchie,
302 * pas si il est enfant direct d'une rubrique enfant secondaire
303 *
304 * @param int $id_objet
305 * @param string $objet
306 * @param int $id_rubrique
307 * @param string $args
308 * @param string $ancre
309 * @return string
310 */
311function generer_url_polyhier_entite($id_objet, $objet, $id_rubrique=null, $args='', $ancre='') {
312
313        // si id_rubrique contextuel passe en argument et si c'est bien un parent polyhierarchique
314        $parents_poly = sql_allfetsel('id_parent','spip_rubriques_liens', 'objet='.sql_quote($objet). ' AND id_objet='.intval($id_objet));
315        $parents_poly = array_map('reset',$parents_poly);
316
317        $maxiter = 100;
318        $branche = $r = array($id_rubrique);
319        while (!($id_parent = array_intersect($parents_poly, $r))
320          and $maxiter--
321          and $filles = sql_allfetsel('id_rubrique','spip_rubriques',sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $branche, 'NOT'))) {
322                $r = array_map('reset', $filles);
323                $branche = array_merge($branche, $r);
324        }
325
326        if ($id_parent = reset($id_parent)) {
327                // le vrai parent
328                $champ_parent = ($objet == 'rubrique' ? 'id_parent' : 'id_rubrique');
329                $args .= ($args?'&':'')."$champ_parent=$id_parent";
330        }
331        $url = generer_url_entite($id_objet, $objet, $args, $ancre, true);
332        return $url;
333}
Note: See TracBrowser for help on using the repository browser.