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

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

Backport de [107574] : Amélioration de [107572] : comme proposé par cerdic, quand on trouve une jointure ET qu'on détecte que l'objet peut être classé avec polyhier, alors on cherche les deux liaisons avec un OR. Sinon c'est que l'un ou que l'autre.

File size: 12.2 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                // si le champ id_rubrique est recuperer par jointure, c'est le type et la primary de la table jointe
209                // qu'il faut chercher dans la table spip_rubriques_liens (ie cas des evenements)
210                if ($cle AND $desc) {
211                        $type_jointure = objet_type($boucle->from[$cle]);
212                        $primary_jointure = $cle . "." . id_table_objet($boucle->from[$cle]);
213                }
214        }
215        else $cle = $boucle->id_table;
216
217
218        $c = "sql_in('$cle" . ".$champ', \$b = calcul_branche_polyhier_in($arg,".($tous===true?'true':"'directs'").")"
219          . ($not ? ", 'NOT'" : '') . ")";
220        $where[] = $c;
221       
222        if ($tous!=='directs'
223          AND in_array(table_objet_sql($boucle->type_requete),array_keys(lister_tables_objets_sql()))){
224                // S'il y a une jointure, on cherche toujours les liaisons avec celle-ci
225                if (isset($type_jointure)) {
226                        $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\'')";
227                        $where_jointure = "array('IN', '$primary_jointure', '(SELECT * FROM('.$sous_jointure.') AS subquery)')";
228                }
229               
230                // S'il n'y a pas de jointure (cas par défaut) ou que l'objet est explicitement configuré pour être classé avec polyhier
231                // on cherche les liaisons sur l'objet
232                if (
233                        !isset($type_jointure)
234                        or (include_spip('inc/config') and in_array(table_objet_sql($type), lire_config('polyhier/lier_objets', array())))
235                ) {
236                        $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\'')";
237                        $where_objet = "array('IN', '$primary', '(SELECT * FROM('.$sous_objet.') AS subquery)')";
238                }
239               
240                // S'il y a les deux, on fait un OR
241                if (isset($where_jointure) and isset($where_objet)) {
242                        $where[] = "array('OR', $where_jointure, $where_objet)";
243                }
244                // Sinon s'il n'y a que jointure
245                elseif (isset($where_jointure)) {
246                        $where[] = $where_jointure;
247                }
248                // Sinon que sur l'objet
249                else {
250                        $where[] = $where_objet;
251                }
252        }
253
254        if (count($where)==2)
255                $where = "array('OR',".$where[0].",".$where[1].")";
256        else
257                $where = reset($where);
258
259        $boucle->where[]= !$crit->cond ? $where :
260          ("($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}
270
271function critere_branche_complete_dist($idb, &$boucles, $crit) {
272        critere_branche($idb, $boucles, $crit, true);
273}
274
275/*
276 * Déclarer un fonction générique pour pouvoir chercher dans les champs des rubriques liées
277 *
278 */
279function inc_rechercher_joints_objet_rubrique_dist($table, $table_liee, $ids_trouves, $serveur){
280        $cle_depart = id_table_objet($table);
281        $s = sql_select(
282                "id_objet as $cle_depart, id_parent as id_rubrique",
283                'spip_rubriques_liens',
284                array("objet='$table'", sql_in('id_parent', $ids_trouves)),
285                '','','','',$serveur
286        );
287        return array($cle_depart, 'id_rubrique', $s);
288}
289
290
291
292/**
293 * Compile la balise `#URL_POLYHIER{#ID_RUBRIQUE,article,#ID_ARTICLE}`
294 * qui génère l'URL d'un article contextualisee a l'une de ses rubriques parentes
295 *
296 * Si la rubrique passee en argument n'est pas une rubrique parente elle est ignoree
297 * Si les URLs ne contiennent pas l'URL de la rubrique parente (URL arbo), la rubrique contextuelle est ajoutee en query string
298 *
299 * @balise
300 * @example
301 *     ```
302 *     #URL_POLYHIER{#ENV{id_rubrique,#ID_RUBRIQUE},article,#ID_ARTICLE}
303 *     ```
304 * @param Champ $p
305 *     Pile au niveau de la balise
306 * @return Champ
307 *     Pile complétée par le code à générer
308 */
309function balise_URL_POLYHIER_dist($p) {
310
311        $_id_rubrique = interprete_argument_balise(1, $p);
312        $_type = interprete_argument_balise(2, $p);
313        $_id = interprete_argument_balise(3, $p);
314
315        $code = "urlencode_1738(generer_url_polyhier_entite($_id, $_type, $_id_rubrique))";
316        $p->code = $code;
317        if (!$p->etoile) {
318                $p->code = "vider_url($code)";
319        }
320        $p->interdire_scripts = false;
321
322        return $p;
323}
324
325/**
326 * Generer l'URL polyhierarchique d'un objet relativement a une rubrique parente secondaire
327 * on cherche le parent secondaire qui est dans la branche de la rubrique fournie et on le passe en argument
328 * de l'URL. Si le module URL le gere (arbopoly) l'URL reposera sur l'URL de ce parent secondaire,
329 * sinon elle restera en argument
330 *
331 * a charge pour les squelettes de gerer la presence du id_rubrique=xxx dans le contexte de la page de l'objet concerne
332 *
333 * Ne fonctionne que si l'objet est lui même rattache en polyhierarchie,
334 * pas si il est enfant direct d'une rubrique enfant secondaire
335 *
336 * @param int $id_objet
337 * @param string $objet
338 * @param int $id_rubrique
339 * @param string $args
340 * @param string $ancre
341 * @return string
342 */
343function generer_url_polyhier_entite($id_objet, $objet, $id_rubrique=null, $args='', $ancre='') {
344
345        // si id_rubrique contextuel passe en argument et si c'est bien un parent polyhierarchique
346        $parents_poly = sql_allfetsel('id_parent','spip_rubriques_liens', 'objet='.sql_quote($objet). ' AND id_objet='.intval($id_objet));
347        $parents_poly = array_map('reset',$parents_poly);
348
349        $maxiter = 100;
350        $branche = $r = array($id_rubrique);
351        while (!($id_parent = array_intersect($parents_poly, $r))
352          and $maxiter--
353          and $filles = sql_allfetsel('id_rubrique','spip_rubriques',sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $branche, 'NOT'))) {
354                $r = array_map('reset', $filles);
355                $branche = array_merge($branche, $r);
356        }
357
358        if ($id_parent = reset($id_parent)) {
359                // le vrai parent
360                $champ_parent = ($objet == 'rubrique' ? 'id_parent' : 'id_rubrique');
361                $args .= ($args?'&':'')."$champ_parent=$id_parent";
362        }
363        $url = generer_url_entite($id_objet, $objet, $args, $ancre, true);
364        return $url;
365}
Note: See TracBrowser for help on using the repository browser.