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