Subversion Repositories eFlore/Applications.del

Rev

Rev 2013 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1818 jpm 1
<?php
2
/**
3
 * Statistiques par année sur l'utilisation de Identiplante / Pictoflora
4
 *
5
 * @see Documentation : <http://www.tela-botanica.org/wikini/DevInformatiques/wakka.php?wiki=AppliDelStats>
6
 *
7
 * @category   DEL
8
 * @package    Services
9
 * @subpackage Statistiques
10
 * @version    0.1
11
 * @author     Mathias CHOUET <mathias@tela-botanica.org>
12
 * @author     Jean-Pascal MILCENT <jpm@tela-botanica.org>
13
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
14
 * @license    GPL v3 <http://www.gnu.org/licenses/gpl.txt>
15
 * @license    CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
16
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
17
 */
18
class StatistiquesParAnnee {
19
 
20
	private $conteneur;
21
	private $contexte;
22
	private $navigation;
23
	private $bdd;
24
 
25
	private $annee = null;
26
	private $type = 'tout';
27
	private $methode = '';
28
 
29
	public function __construct(Conteneur $conteneur = null) {
30
		$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur;
31
		$this->contexte = $conteneur->getContexte();
32
		$this->navigation = $conteneur->getNavigation();
33
		$this->bdd = $this->conteneur->getBdd();
34
	}
35
 
36
	public function consulter() {
37
		$this->intitialiserParametresEtRessources();
38
		$this->verifierPreRequis();
39
 
40
		$resultat = new ResultatService();
41
		$resultat->corps = call_user_func(array($this, $this->methode));
42
		return $resultat;
43
	}
44
 
45
	private function intitialiserParametresEtRessources() {
46
		$this->type = $this->contexte->getRessource(2) != null ? $this->contexte->getRessource(2) : $this->type;
47
		$this->methode = $this->obtenirNomMethode($this->type);
48
		$this->annee =(int) $this->contexte->getQS('annee') != null ? intval($this->contexte->getQS('annee')) : null;
49
	}
50
 
51
	private function verifierPreRequis() {
52
		$erreurs = array();
53
 
54
		if ($this->annee != null && !is_int($this->annee)) {
55
			$erreurs[] = "Le paramètre 'annee' doit être un entier.";
56
		}
57
 
58
		if (method_exists($this, $this->obtenirNomMethode($this->type)) === false) {
59
			$erreurs[] = "Les stats de type '{$this->type}' n'existent pas.";
60
		}
61
 
62
		if (!empty($erreurs)) {
63
			$msg = "Erreur de configuration :\n".implode("\n", $erreurs)."\n\n".Statistiques::getDoc();
64
			throw new Exception($msg, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
65
		}
66
	}
67
 
68
	private function obtenirNomMethode($mot) {
69
		$classeNom = 'get'.str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot))));
70
		return $classeNom;
71
	}
72
 
73
	// retourne toutes les stats pour l'année spécifiée
74
	private function getTout() {
75
		$obsIdentifieesFinAnneePlus = $this->getPourcentageObsIdentifieesFinAnneePlus();
76
		$participants = $this->getParticipants();
77
 
78
		return array(
79
			'annee' => $this->annee,
80
			'moyenneObsSansNomParMois' => $this->getMoyenneObsSansNomParMois(),
81
			'moyenneObsIdentifieesParMois' => $this->getMoyenneObsIdentifieesParMois(),
82
			'pourcentageObsIdentifieesEnFinDAnnee' => $this->getPourcentageObsIdentifieesFinAnnee(),
83
			'pourcentageObsIdentifieesEnFinDAnneePlusPlus' => $obsIdentifieesFinAnneePlus['pourcentage'],
84
			'moyenneActionsParJour' => $this->getMoyenneActionsParJour(),
85
			'personnesEnvoyantUnePropositionParMois' => $participants['nombre']
86
		);
87
	}
88
 
89
	// proxy pour le widget de stats
90
	private function getObservations() {
91
		return $this->getTout();
92
	}
93
 
94
	// Retourne le nombre moyen d'observations non identifiées envoyées par mois, pour l'année $annee
95
	private function getMoyenneObsSansNomParMois() {
96
		$sqlTableTmp = "SELECT COUNT(*) AS compte, ".
97
			"	CONCAT(YEAR(date_transmission),'-',MONTH(date_transmission)) AS anneemois ".
98
			"FROM del_observation ".
99
			"WHERE (mots_cles_texte LIKE '%aDeterminer%' ".
100
				"OR certitude = 'aDeterminer' ".
101
				"OR certitude = 'douteux' ".
102
				// Obs n'ayant pas de nom_sel_nn (détermination non choisie parmi le référentiel)
103
				"OR nom_sel_nn IS NULL ".
104
				"OR nom_sel_nn = 0 ".
105
				"OR id_observation IN ({$this->getSqlObsSansNom()}) ".
106
			') '.
107
			(($this->annee !== null) ? "AND YEAR(date_transmission) = '{$this->annee}' " : '').
108
			'GROUP BY anneemois '.
109
			'ORDER BY anneemois DESC ';
110
 
111
		$requete = "SELECT AVG(parMois.compte) AS moyenne FROM ($sqlTableTmp) AS parMois ".
112
			' -- '.__FILE__.' : '.__LINE__;
113
		$resultat = $this->bdd->recupererTous($requete);
114
		return intval($resultat[0]['moyenne']);
115
	}
116
 
117
	private function getSqlObsSansNom() {
118
		$sqlObsSansNom = "SELECT DISTINCT ce_observation ".
119
			"FROM del_commentaire ".
120
			"WHERE proposition_initiale = 1 ".
121
			"AND (nom_sel_nn IS NULL OR nom_sel_nn = '') ";
122
		return $sqlObsSansNom;
123
	}
124
 
125
	// Retourne la moyenne par mois sur l'année en cours, des propositions marquées comme "retenues"
126
	// dont le dernier vote est dans l'année considérée (comptées en groupant par mois du dernier vote)
127
	private function getMoyenneObsIdentifieesParMois() {
128
		// Compte et date du dernier vote des propositions marquées comme "retenues"
129
		$sqlTableTmp1 = "SELECT COUNT(*), MAX(dcv.date) AS maxdate ".
130
			"FROM del_commentaire AS dc ".
131
			"	LEFT JOIN del_commentaire_vote dcv ON dcv.ce_proposition = dc.id_commentaire ".
132
			" WHERE proposition_retenue = 1 ".
133
			" GROUP BY dc.id_commentaire ".
134
			(($this->annee !== null) ? "HAVING MAX(YEAR(dcv.date)) = '{$this->annee}' " : '');
135
 
136
		$sqlTableTmp2 = 'SELECT COUNT(*) AS valideesparmois, '.
137
			"	CONCAT(YEAR(maxdate), '-', MONTH(maxdate)) AS anneemois ".
138
			"FROM ($sqlTableTmp1) AS temp ".
139
			"GROUP BY anneemois ";
140
 
141
		$requete = "SELECT AVG(valideesparmois) AS moyenne FROM ($sqlTableTmp2) AS temp2 ".
142
			' -- '.__FILE__.' : '.__LINE__;
143
 
144
		$resultat = $this->bdd->recupererTous($requete);
145
		return intval($resultat[0]['moyenne']);
146
	}
147
 
148
	// Version améliorée mais non optimale (prend en compte les consensus non validés)
149
	// @TODO on devrait croiser les IDS pour ne pas prendre en compte les obs validées ou en
150
	// 		consensus, mais qui datent des années précédentes
151
	// @ACHTUNG mache pas, dépasse les 100% (voir Wiki)
152
	private function getPourcentageObsIdentifieesFinAnneePlus() {
153
		// Obs ayant atteint un consensus cette année
154
		$requete = "SELECT COUNT(*) AS nombre ".
155
			"FROM (SELECT id_observation, id_commentaire, id_vote, nbvotes ".
156
			"FROM (SELECT do.id_observation, dc.id_commentaire, dcv.id_vote, COUNT(dcv.id_vote) AS nbvotes ".
157
			"FROM del_commentaire AS dc ".
158
			"	LEFT JOIN del_observation AS do ON (do.id_observation = dc.ce_observation) ".
159
			"	LEFT JOIN del_commentaire_vote AS dcv ON (dc.id_commentaire = dcv.ce_proposition) ".
160
			"AND dcv.valeur = 1 ".
161
			"AND dc.proposition_retenue = 0 ".
162
			"GROUP BY dc.id_commentaire ".
163
			(($this->annee != null) ? " HAVING MAX(YEAR(dcv.date)) = '{$this->annee}' " : '').
164
			" ) AS temp ".
165
			"GROUP BY id_observation ".
166
			") AS temp2 ".
167
			' -- '.__FILE__.' : '.__LINE__;
168
		$obsEnConsensus = $this->bdd->recupererTous($requete);
169
		$oc = intval($obsEnConsensus[0]['nombre']);
170
 
171
		// Obs ayant une "proposition retenue" cette année
172
		$requete = "SELECT COUNT(*) AS nombre ".
173
			"FROM (SELECT COUNT(DISTINCT id_observation), MAX(dcv.date) AS maxdate ".
174
			"FROM del_commentaire AS dc ".
175
			"	LEFT JOIN del_commentaire_vote AS dcv ON (dcv.ce_proposition = dc.id_commentaire) ".
176
			"	LEFT JOIN del_observation AS do ON (do.id_observation = dc.ce_observation) ".
177
			"WHERE proposition_retenue = 1 ".
178
			(($this->annee != null) ? "AND YEAR(do.date_transmission) = '{$this->annee}' " : '').
179
			"GROUP BY dc.id_commentaire ".
180
			(($this->annee != null) ? "HAVING MAX(YEAR(dcv.date)) = '{$this->annee}' " : '').
181
			") as temp ".
182
			' -- '.__FILE__.' : '.__LINE__;
183
		$nbObsValidees = $this->bdd->recupererTous($requete);
184
		$ov = intval($nbObsValidees[0]['nombre']);
185
 
186
		// Nombre d'obs sans nom soumises cette année
187
		$requete = "SELECT COUNT(*) AS nombre ".
188
			"FROM del_observation ".
189
			"WHERE (mots_cles_texte LIKE '%aDeterminer%' ".
190
			"OR certitude = 'aDeterminer' ".
191
			"OR certitude = 'douteux' ".
192
			"OR nom_sel_nn IS NULL ".
193
			"OR nom_sel_nn = 0 ".
194
			"OR id_observation IN ({$this->getSqlObsSansNom()})".
195
			') '.
196
			(($this->annee != null) ? "AND YEAR(date_transmission) = '{$this->annee}' " : '').
197
			' -- '.__FILE__.' : '.__LINE__;
198
		$nbObsSansNom = $this->bdd->recupererTous($requete);
199
		$osn = intval($nbObsSansNom[0]['nombre']);
200
 
201
		return array(
202
			'observationsEnConsensus' => $oc,
203
			'observationsValidees' => $ov,
204
			'observationsSansNom' => $osn,
205
			'pourcentage' => ($osn == 0 ? 0 : round(((($oc + $ov) / $osn) * 100), 2))
206
		);
207
	}
208
 
209
	private function getPourcentageObsIdentifieesFinAnnee() {
210
		$requete = "SELECT ( ".
211
			"SELECT COUNT(*) FROM ( ".
212
				"SELECT COUNT(DISTINCT id_observation), MAX(dcv.date) AS maxdate ".
213
				"FROM del_commentaire AS dc ".
214
				"	LEFT JOIN del_commentaire_vote AS dcv ON (dcv.ce_proposition = dc.id_commentaire) ".
215
				"	LEFT JOIN del_observation AS do ON (do.id_observation = dc.ce_observation) ".
216
				"WHERE proposition_retenue = 1 ".
217
				(($this->annee != null) ? "AND YEAR(do.date_transmission) = '{$this->annee}' " : '').
218
				"GROUP BY dc.id_commentaire ".
219
				(($this->annee != null) ? "HAVING MAX(YEAR(dcv.date)) = '{$this->annee}' " : '').
220
			") AS temp)".
221
			" / ".
222
			"(SELECT COUNT(*) ".
223
			"FROM del_observation ".
224
			"WHERE (mots_cles_texte LIKE '%aDeterminer%' ".
225
			"OR certitude = 'aDeterminer' ".
226
			"OR certitude = 'douteux' ".
227
			"OR nom_sel_nn IS NULL ".
228
			"OR nom_sel_nn = 0 ".
229
				"OR id_observation IN ( ".
230
				"SELECT DISTINCT ce_observation ".
231
				"FROM del_commentaire ".
232
				"WHERE proposition_initiale = 1 ".
233
				"AND (nom_sel_nn IS NULL OR nom_sel_nn = '') ".
234
				") ".
235
			") ".
236
			(($this->annee != null) ? "AND YEAR(date_transmission) = '{$this->annee}' " : '').
237
		") * 100 AS pourcentage ".
238
		' -- '.__FILE__.' : '.__LINE__;
239
		$resultat = $this->bdd->recupererTous($requete);
240
		return floatval($resultat[0]['pourcentage']);
241
	}
242
 
243
	// Retourne la moyenne sur l'année du nombre d'actions (commentaire ou vote) par jour
244
	private function getMoyenneActionsParJour() {
245
		// nombre de commentaires sur l'année
246
		$sqlNbreCommentaires = 'SELECT COUNT(*) FROM del_commentaire '.
247
			($this->annee != null ? "WHERE YEAR(date) = '{$this->annee}' " : '');
248
 
249
		// nombre de votes sur l'année
250
		$sqlNbreVotes = 'SELECT COUNT(*) FROM del_commentaire_vote '.
251
			($this->annee != null ? "WHERE YEAR(date) = '{$this->annee}' " : '');
252
 
253
		// nombre de jours écoulés dans l'année*
254
		$sqlNbreJours = "SELECT 365 * (YEAR(now()) - MIN(YEAR(date)) + 1) FROM del_commentaire_vote WHERE YEAR(date) != 0 ";
255
		if ($this->annee != null) {
256
			$sqlNbreJours = "SELECT IF(YEAR(CURDATE()) = '{$this->annee}', DAYOFYEAR(CURDATE()), 365) ";
257
		}
258
 
259
		// nombre d'actions / nombre de jours
260
		$requete = "SELECT ((($sqlNbreCommentaires) + ($sqlNbreVotes)) / ($sqlNbreJours)) AS moyenne ".
261
			' -- '.__FILE__.' : '.__LINE__;
262
 
263
		$resultat = $this->bdd->recupererTous($requete);
264
		return intval($resultat[0]['moyenne']);
265
	}
266
 
267
	// Retourne le nombre et la liste des personnes ayant sur l'année une moyenne de participation par mois >= 1
268
	private function getParticipants() {
269
		// Faire la moyenne par utilisateur et par mois
270
		$requete = "SELECT cal.nbmois, SUM(somme) / cal.nbmois as moyenne, ce_utilisateur, utilisateur_courriel ".
271
			"FROM ".
272
				// Compter le nombre de participations pour chaque utilisateur à chaque mois de cette année
273
				"(SELECT COUNT(*) as somme, CONCAT(YEAR(date),'-',MONTH(date)) AS anneemois, ".
274
				"ce_utilisateur, utilisateur_courriel, id_commentaire ".
275
				"FROM del_commentaire ".
276
				"WHERE ce_proposition = '' ".
277
				"AND nom_sel_nn != '' ".
278
				"AND nom_sel_nn IS NOT NULL ".
279
				(($this->annee != null) ? " AND YEAR(date) = '{$this->annee}' " : '').
280
				"GROUP BY anneemois, ce_utilisateur, utilisateur_courriel) AS ppm, ".
281
			// Trouver le nombre de mois différents lors desquels les utilisateurs ont participé, cette année
282
			// Pour l'année en cours par ex, retournera 2 si on est en février (voire un au début du mois).
283
				"(SELECT COUNT(distinct CONCAT(YEAR(date),'-',MONTH(date))) AS nbmois ".
284
				"FROM del_commentaire ".
285
				"WHERE ce_proposition = '' ".
286
				(($this->annee != null) ? "AND YEAR(date) = '{$this->annee}' " : '').
287
				"AND nom_sel_nn != '' ".
288
				"AND nom_sel_nn IS NOT NULL) AS cal ".
289
			"GROUP BY ce_utilisateur, utilisateur_courriel ".
290
			"HAVING SUM(somme) / cal.nbmois >= 1 ".
291
			"ORDER BY moyenne ".
292
			' -- '.__FILE__.' : '.__LINE__;
293
 
294
		$resultat = $this->bdd->recupererTous($requete);
295
		$cpt = count($resultat);
296
		$retour = array(
297
			'nombre' => intval($cpt),
298
			'donnees' => $resultat
299
		);
300
		return $retour;
301
	}
302
}