~maj plugins
[ptitvelo/web/www.git] / www / plugins / spip-bonux-3 / public / spip_bonux_criteres.php
1 <?php
2 /**
3 * Plugin Spip-Bonux
4 * Le plugin qui lave plus SPIP que SPIP
5 * (c) 2008 Mathieu Marcillaud, Cedric Morin, Tetue
6 * Licence GPL
7 *
8 */
9
10 if (!defined('_ECRIRE_INC_VERSION')) return;
11
12 /**
13 * Permet de faire un comptage par table liee
14 *
15 * @syntaxe `{compteur table[, champ]}`
16 * @link http://www.spip-contrib.net/Classer-les-articles-par-nombre-de#forum409210
17 *
18 * @example
19 * Pour avoir les auteurs classes par articles et
20 * le nombre d'article de chacun :
21 *
22 * ```
23 * <BOUCLE1(AUTEURS){compteur articles}{par compteur_articles}>
24 * #ID_AUTEUR : #COMPTEUR{articles}
25 * </BOUCLE1>
26 * ```
27 *
28 * @note
29 * Avec un seul argument {compteur autre_table} le groupby est fait
30 * implicitement sur la cle primaire de la boucle en cours.
31 * Avec un second argument {compteur autre_table,champ_fusion}
32 * le groupby est fait sur le champ_fusion"
33 *
34 * @param string $idb
35 * Identifiant de la boucle
36 * @param Boucle[] $boucles
37 * AST du squelette
38 * @param Critere $crit
39 * Paramètres du critère dans cette boucle
40 * @param bool $left
41 * true pour utiliser un left join plutôt qu'un inner join.
42 * @return void
43 */
44 function critere_compteur($idb, &$boucles, $crit, $left=false){
45 $boucle = &$boucles[$idb];
46
47 if (isset($crit->param[1])) {
48 $_fusion = calculer_liste($crit->param[1], array(), $boucles, $boucle->id_parent);
49 } else {
50 $_fusion = "''";
51 }
52 $params = $crit->param;
53 $table = reset($params);
54 $table = $table[0]->texte;
55 $op = false;
56 if (preg_match(',^(\w+)([<>=])([0-9]+)$,',$table,$r)){
57 $table=$r[1];
58 if (count($r)>=3) $op=$r[2];
59 if (count($r)>=4) $op_val=$r[3];
60 }
61 $type = objet_type($table);
62 $type_id = id_table_objet($type);
63
64 /**
65 * Si la clé primaire est une clé multiple, on prend la première partie
66 * Utile pour compter les versions de spip_versions par exemple
67 */
68 if (count($types = explode(',',$type_id)) > 1)
69 $type_id = $types[0];
70 $table_sql = table_objet_sql($type);
71
72 $trouver_table = charger_fonction('trouver_table','base');
73 $arrivee = array($table, $trouver_table($table, $boucle->sql_serveur));
74 $depart = array($boucle->id_table,$trouver_table($boucle->id_table, $boucle->sql_serveur));
75
76 // noter les jointures deja installees
77 $joins = array_keys($boucle->from);
78 if ($compt = calculer_jointure($boucle,$depart,$arrivee)){
79 if ($_fusion!="''"){
80 // en cas de jointure, on ne veut pas du group_by sur la cle primaire !
81 // cela casse le compteur !
82 foreach($boucle->group as $k=>$group)
83 if ($group == $boucle->id_table.'.'.$boucle->primary)
84 unset($boucle->group[$k]);
85 $boucle->group[] = '".($gb='.$_fusion.')."';
86 }
87
88 $boucle->select[]= "COUNT($compt.$type_id) AS compteur_$table";
89 if ($op)
90 $boucle->having[]= array("'".$op."'", "'compteur_".$table."'",$op_val);
91 if ($left){
92 foreach($boucle->from as $k=>$val){
93 if (!in_array($k, $joins)){
94 $boucle->from_type[$k] = 'left';
95 }
96 }
97 }
98 }
99 }
100
101 /**
102 * {compteur_left xxx} permet de faire la meme chose que {compteur xxx}
103 * mais avec un LEFT JOIN pour ne pas ignorer ceux qui ont un compteur nul
104 * @param <type> $idb
105 * @param <type> $boucles
106 * @param <type> $crit
107 */
108 function critere_compteur_left($idb, &$boucles, $crit){
109 critere_compteur($idb, $boucles, $crit, true);
110 }
111
112 /** Critere {somme champ} #SOMME{champ} */
113 function critere_somme($idb, &$boucles, $crit){
114 calcul_critere_fonctions(array('SUM'=>'somme'), $idb, $boucles, $crit);
115 }
116
117 /** Critere {compte champ} #COMPTE{champ} */
118 function critere_compte($idb, &$boucles, $crit){
119 calcul_critere_fonctions(array('COUNT'=>'compte'), $idb, $boucles, $crit);
120 }
121
122 /** Critere {moyenne champ} #MOYENNE{champ} */
123 function critere_moyenne($idb, &$boucles, $crit){
124 calcul_critere_fonctions(array('AVG'=>'moyenne'), $idb, $boucles, $crit);
125 }
126
127 /** Critere {minimum champ} #MINIMUM{champ} */
128 function critere_minimum($idb, &$boucles, $crit){
129 calcul_critere_fonctions(array('MIN'=>'minimum'), $idb, $boucles, $crit);
130 }
131
132 /** Critere {maximum champ} #MAXIMUM{champ} */
133 function critere_maximum($idb, &$boucles, $crit){
134 calcul_critere_fonctions(array('MAX'=>'maximum'), $idb, $boucles, $crit);
135 }
136
137 /** Critere {stats champ} calcul la totale : somme, compte, minimum, moyenne, maximum */
138 function critere_stats($idb, &$boucles, $crit){
139 calcul_critere_fonctions(array(
140 'SUM'=>'somme',
141 'COUNT'=>'compte',
142 'AVG'=>'moyenne',
143 'MIN'=>'minimum',
144 'MAX'=>'maximum',
145 ), $idb, $boucles, $crit);
146 }
147
148 /* $func : array(FUNC => balise) */
149 function calcul_critere_fonctions($func, $idb, &$boucles, $crit) {
150 $boucle = &$boucles[$idb];
151
152 $params = $crit->param;
153 $champ = reset($params);
154 $champ = $champ[0]->texte;
155
156 // option DISTINCT {compte DISTINCT(id_article) }
157 $filter="";
158 if (preg_match('/^([a-zA-Z]+)\(\s*([a-zA-Z_]+)\s*\)$/', trim($champ), $r)) {
159 $filter = $r[1]; // DISTINCT
160 $champ = $r[2]; // id_article
161 }
162
163 $sel = $filter ? "$filter($champ)" : $champ;
164 foreach ($func as $f => $as) {
165 $boucle->select[]= "$f($sel) AS $as" . "_$champ";
166 }
167 }
168
169
170 ?>