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

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

Juste un peu de nettoyage pour y voir plus clair et comparer avec le trunk + quand même un qui n'était pas défini avant d'être rempli.

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        $type = objet_type($boucle->type_requete);
193        $primary = $boucle->id_table.".".$boucle->primary;
194
195        //Trouver une jointure
196        $champ = "id_rubrique";
197        $desc = $boucle->show;
198        //Seulement si necessaire
199        if (!array_key_exists($champ, $desc['field'])){
200                $trouver_table = charger_fonction("trouver_table", "base");
201                $cle = "";
202                // peut-etre deja une jointure qui fournit id_rubrique ?
203                foreach($boucle->from as $k=>$t){
204                        $desc = $trouver_table($t);
205                        if (isset($desc['field']['id_rubrique'])){
206                                $cle = $k;
207                                break;
208                        }
209                }
210                if (!$cle){
211                        $cle = trouver_jointure_champ($champ, $boucle);
212                        $desc = $trouver_table($boucle->from[$cle]);
213                        if (count(trouver_champs_decomposes($champ, $desc))>1){
214                                $decompose = decompose_champ_id_objet($champ);
215                                $champ = array_shift($decompose);
216                                $boucle->where[] = array("'='", _q($cle.".".reset($decompose)), '"'.sql_quote(end($decompose)).'"');
217                        }
218                }
219                // si le champ id_rubrique est récupéré par jointure, c'est le type et la primary de la table jointe
220                // qu'il faut chercher dans la table spip_rubriques_liens (ie cas des evenements)
221                if ($cle AND $desc) {
222                        $type_jointure = objet_type($boucle->from[$cle]);
223                        $primary_jointure = $cle . "." . id_table_objet($boucle->from[$cle]);
224                }
225        }
226        else {
227                $cle = $boucle->id_table;
228        }
229
230        $where = array();
231
232        // On construit en avance la liste des rubriques
233        $boucle->hash .= "
234        // {branche}
235        if ($arg) {
236                \$in_rub = calcul_branche_polyhier_in($arg," . ($tous === true ? 'true' : "'directs'") . ");
237        }
238        ";
239       
240        // Si c'est tout ou que directs ET qu'on a trouvé un "id_rubrique" quelque part
241        // on ajoute le critère de branche principale, avec le champ id_rubrique
242        if ($tous !== 'indirects' and $cle) {
243                $where[] = "sql_in(
244                        '{$cle}.{$champ}',
245                        \$in_rub"
246                        . ($not ? ", 'NOT'" : '')
247                . ")";
248        }
249       
250        // Si c'est tout ou que indirects, on ajoute le critère de branche secondaire, avec la table de liens
251        if (
252                $tous !== 'directs'
253                and in_array(table_objet_sql($boucle->type_requete), array_keys(lister_tables_objets_sql()))
254        ) {
255                // S'il y a une jointure, on cherche toujours les liaisons avec celle-ci
256                if (isset($type_jointure)) {
257                        $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\'')";
258                        $where_jointure = "array('IN', '$primary_jointure', '(SELECT * FROM('.$sous_jointure.') AS subquery)')";
259                }
260               
261                // S'il n'y a pas de jointure (cas par défaut) ou que l'objet est explicitement configuré pour être classé avec polyhier
262                // on cherche les liaisons sur l'objet
263                if (
264                        !isset($type_jointure)
265                        or (include_spip('inc/config') and in_array(table_objet_sql($type), lire_config('polyhier/lier_objets', array())))
266                ) {
267                        $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\'')";
268                        $where_objet = "array('IN', '$primary', '(SELECT * FROM('.$sous_objet.') AS subquery)')";
269                }
270               
271                // S'il y a les deux, on fait un OR
272                if (isset($where_jointure) and isset($where_objet)) {
273                        $where[] = "array('OR', $where_jointure, $where_objet)";
274                }
275                // Sinon s'il n'y a que jointure
276                elseif (isset($where_jointure)) {
277                        $where[] = $where_jointure;
278                }
279                // Sinon que sur l'objet
280                else {
281                        $where[] = $where_objet;
282                }
283        }
284       
285        // S'il y a les deux critères, c'est l'un ou l'autre
286        if (count($where) == 2) {
287                $where = "array('OR'," . $where[0] . "," . $where[1] . ")";
288        }
289        else {
290                $where = reset($where);
291        }
292       
293        $boucle->where[] = !$crit->cond ? $where : ("($arg ? $where : " . ($not ? "'0=1'" : "'1=1'") . ')');
294}
295
296function critere_branche_principale_dist($idb, &$boucles, $crit) {
297        critere_branche($idb, $boucles, $crit, 'directs');
298}
299// un alias
300function critere_branche_directe_dist($idb, &$boucles, $crit) {
301        critere_branche($idb, $boucles, $crit, 'directs');
302}
303function critere_branche_indirecte_dist($idb, &$boucles, $crit) {
304        critere_branche($idb, $boucles, $crit, 'indirects');
305}
306function critere_branche_complete_dist($idb, &$boucles, $crit) {
307        critere_branche($idb, $boucles, $crit, true);
308}
309
310/*
311 * Déclarer un fonction générique pour pouvoir chercher dans les champs des rubriques liées
312 *
313 */
314function inc_rechercher_joints_objet_rubrique_dist($table, $table_liee, $ids_trouves, $serveur) {
315        $cle_depart = id_table_objet($table);
316       
317        $s = sql_select(
318                "id_objet as $cle_depart, id_parent as id_rubrique",
319                'spip_rubriques_liens',
320                array("objet='$table'", sql_in('id_parent', $ids_trouves)),
321                '', '', '', '', $serveur
322        );
323       
324        return array($cle_depart, 'id_rubrique', $s);
325}
326
327/**
328 * Filtre pour appeler polyhier_get_enfants depuis un squelette
329 * @param $id_parent
330 * @param string $objet
331 * @param string $serveur
332 * @return array
333 */
334function filtre_polyhier_get_enfants_dist($id_parent, $objet='', $serveur='') {
335        include_spip('inc/polyhier');
336        return polyhier_get_enfants($id_parent, $objet, $serveur);
337}
338
339function filtre_polyhier_lister_enfants($objet,$ids){
340        $fond = "prive/objets/liste/".table_objet($objet);
341        if (trouver_fond($fond)){
342                $primary = id_table_objet($objet);
343                return recuperer_fond($fond,array($primary=>$ids));
344        }
345}
346
347
348/**
349 * Compile la balise `#URL_POLYHIER{#ID_RUBRIQUE,article,#ID_ARTICLE}`
350 * qui génère l'URL d'un article contextualisee a l'une de ses rubriques parentes
351 *
352 * Si la rubrique passee en argument n'est pas une rubrique parente elle est ignoree
353 * Si les URLs ne contiennent pas l'URL de la rubrique parente (URL arbo), la rubrique contextuelle est ajoutee en query string
354 *
355 * @balise
356 * @example
357 *     ```
358 *     #URL_POLYHIER{#ENV{id_rubrique,#ID_RUBRIQUE},article,#ID_ARTICLE}
359 *     ```
360 * @param Champ $p
361 *     Pile au niveau de la balise
362 * @return Champ
363 *     Pile complétée par le code à générer
364 */
365function balise_URL_POLYHIER_dist($p) {
366
367        $_id_rubrique = interprete_argument_balise(1, $p);
368        $_type = interprete_argument_balise(2, $p);
369        $_id = interprete_argument_balise(3, $p);
370
371        $code = "urlencode_1738(generer_url_polyhier_entite($_id, $_type, $_id_rubrique))";
372        $p->code = $code;
373        if (!$p->etoile) {
374                $p->code = "vider_url($code)";
375        }
376        $p->interdire_scripts = false;
377
378        return $p;
379}
380
381/**
382 * Generer l'URL polyhierarchique d'un objet relativement a une rubrique parente secondaire
383 * on cherche le parent secondaire qui est dans la branche de la rubrique fournie et on le passe en argument
384 * de l'URL. Si le module URL le gere (arbopoly) l'URL reposera sur l'URL de ce parent secondaire,
385 * sinon elle restera en argument
386 *
387 * a charge pour les squelettes de gerer la presence du id_rubrique=xxx dans le contexte de la page de l'objet concerne
388 *
389 * Ne fonctionne que si l'objet est lui même rattache en polyhierarchie,
390 * pas si il est enfant direct d'une rubrique enfant secondaire
391 *
392 * @param int $id_objet
393 * @param string $objet
394 * @param int $id_rubrique
395 * @param string $args
396 * @param string $ancre
397 * @return string
398 */
399function generer_url_polyhier_entite($id_objet, $objet, $id_rubrique=null, $args='', $ancre='') {
400
401        // si id_rubrique contextuel passe en argument et si c'est bien un parent polyhierarchique
402        $parents_poly = sql_allfetsel('id_parent','spip_rubriques_liens', 'objet='.sql_quote($objet). ' AND id_objet='.intval($id_objet));
403        $parents_poly = array_map('reset',$parents_poly);
404
405        $maxiter = 100;
406        $branche = $r = array($id_rubrique);
407        while (!($id_parent = array_intersect($parents_poly, $r))
408          and $maxiter--
409          and $filles = sql_allfetsel('id_rubrique','spip_rubriques',sql_in('id_parent', $r) . " AND " . sql_in('id_rubrique', $branche, 'NOT'))) {
410                $r = array_map('reset', $filles);
411                $branche = array_merge($branche, $r);
412        }
413
414        if ($id_parent = reset($id_parent)) {
415                // le vrai parent
416                $champ_parent = ($objet == 'rubrique' ? 'id_parent' : 'id_rubrique');
417                $args .= ($args?'&':'')."$champ_parent=$id_parent";
418        }
419        $url = generer_url_entite($id_objet, $objet, $args, $ancre, true);
420        return $url;
421}
Note: See TracBrowser for help on using the repository browser.