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