Subversion Repositories eFlore/Applications.del

Rev

Rev 2210 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1375 raphael 1
<?php
1845 jpm 2
// declare(encoding='UTF-8');
1375 raphael 3
/**
1845 jpm 4
 * Web service récupèrant toutes les observations et, pour chacune d'elle, les images qui lui sont associées.
1375 raphael 5
 *
1845 jpm 6
 * ATTENTION : le web service commence par récupérer seulement les id des obs (1er requete SQL), puis dans une
7
 * deuxième requête SQL récupère les informations complémentaires. Il s'avère qu'en procédant ainsi le web service
8
 * est 3 fois plus rapide !
1375 raphael 9
 *
1845 jpm 10
 * @category   DEL
11
 * @package    Services
12
 * @subpackage Observations
13
 * @version    0.1
14
 * @author     Mathias CHOUET <mathias@tela-botanica.org>
15
 * @author     Jean-Pascal MILCENT <jpm@tela-botanica.org>
16
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
17
 * @license    GPL v3 <http://www.gnu.org/licenses/gpl.txt>
18
 * @license    CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
19
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
1375 raphael 20
 */
1451 raphael 21
class ListeObservations {
1375 raphael 22
 
1793 jpm 23
	private $conteneur;
24
	private $bdd;
1845 jpm 25
	private $navigation;
26
	private $filtrage;
27
	private $sql;
1881 jpm 28
 
1845 jpm 29
	private $mappings = array();
30
	private $paramsFiltres = array();
1375 raphael 31
 
1881 jpm 32
	private $idsObsOrdonnees = array();
33
	private $infosObs = array();
34
	private $infosObsOrdonnee = array();
2049 aurelien 35
 
36
	private $evenementsObs = array();
1375 raphael 37
 
1881 jpm 38
 
1845 jpm 39
	public function __construct(Conteneur $conteneur) {
40
		$this->conteneur = $conteneur;
41
		$this->conteneur->chargerConfiguration('config_departements_bruts.ini');
1375 raphael 42
 
1793 jpm 43
		$this->bdd = $this->conteneur->getBdd();
1845 jpm 44
		$this->filtrage = $this->conteneur->getParametresFiltrage();
45
		$this->sql = $this->conteneur->getSql();
46
		$this->navigation = $this->conteneur->getNavigation();
1375 raphael 47
 
1845 jpm 48
		$this->mappings['votes'] = $this->conteneur->getParametreTableau('votes.mapping');
49
		$this->mappings['commentaires'] = $this->conteneur->getParametreTableau('commentaires.mapping');
50
	}
1666 jpm 51
 
1793 jpm 52
	public function consulter($ressources, $parametres) {
1845 jpm 53
		$this->paramsFiltres = $this->filtrage->filtrerUrlParamsAppliObs();
1871 jpm 54
		$this->sql->setAppli(Sql::APPLI_OBS);
1845 jpm 55
		$this->sql->setParametres($this->paramsFiltres);
56
		$this->sql->ajouterContraintes();
57
		$this->sql->ajouterConstrainteAppliObs();
58
		$this->sql->definirOrdreSqlAppliObs();
1666 jpm 59
 
1881 jpm 60
		$this->idsObsOrdonnees = $this->getIdObs();
1845 jpm 61
		$this->navigation->setTotal($this->sql->getTotalLignesTrouvees());
1666 jpm 62
 
1845 jpm 63
		// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats
64
		$resultat = new ResultatService();
65
		$resultat->corps = array('entete' => $this->navigation->getEntete(), 'resultats' => array());
1881 jpm 66
		if (count($this->idsObsOrdonnees) > 0) {
1666 jpm 67
 
1793 jpm 68
			// 2) récupération des données nécessaires pour ces observations (obs + images)
1881 jpm 69
			$this->infosObs = $this->getInfosObs();
1793 jpm 70
			// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output
1881 jpm 71
			$this->infosObsOrdonnees = $this->formaterObservations();
72
			// 4) Ajouter commentaires + votes à $this->infosObsOrdonnees
73
			$this->chargerDeterminations();
1666 jpm 74
 
1845 jpm 75
			$resultat->corps = array(
2140 mathias 76
				'entete' => $this->navigation->getEntete(),
1933 aurelien 77
				// 5) Applatissage du tableau afin de garder l'ordre de tri
78
				// (qui n'est pas garanti dans un objet json)
79
				'resultats' => array_values($this->infosObsOrdonnees));
1618 mathias 80
		}
81
		return $resultat;
1793 jpm 82
	}
1375 raphael 83
 
1793 jpm 84
	// SQL helpers
85
	/*
86
	 * Retourne une liste ordonnée d'id d'observation correspondant aux critères
87
	 * passés dans p et aux clauses where/join présentes dans le tableau $req
88
	 *
89
	 * @param p: $params (filtrés sauf escape-string)
90
	 * @param req: le tableau représentant les composants de la requete SQL
91
	 * @param db: l'instance de db
92
	 */
1845 jpm 93
	private function getIdObs() {
2049 aurelien 94
 
95
		$requete = $this->renvoyerRequeteSelonType();
96
 
1871 jpm 97
		//Debug::printr($requete);
1845 jpm 98
		$resultats = $this->bdd->recupererTous($requete);
1375 raphael 99
 
1845 jpm 100
		$idObs = array();
101
		if ($resultats !== false ) {
102
			foreach ($resultats as $resultat) {
103
				$idObs[] = $resultat['id_observation'];
104
			}
1793 jpm 105
		}
1845 jpm 106
		return $idObs;
1375 raphael 107
	}
2049 aurelien 108
 
109
	private function renvoyerRequeteSelonType() {
2140 mathias 110
		if($this->monActiviteEstDemandee()) {
111
			$gestion_utilisateur = new GestionUtilisateur($this->conteneur);
2077 mathias 112
			$utilisateur = $gestion_utilisateur->getUtilisateur();
2140 mathias 113
			if ($utilisateur['connecte'] === true) {
114
				$id_utilisateur = $utilisateur['id_utilisateur'];
2077 mathias 115
				$requete = $this->sql->getRequeteIdObsMonactiviteTout($id_utilisateur, $this->sql->getLimit()).' -- '.__FILE__.':'.__LINE__;
116
				// Enregistrement de la date de consultation pour ne pas réafficher des événements déjà consultés
117
				$gestion_utilisateur->setDerniereDateConsultationEvenements($id_utilisateur, date('Y-m-d H:i:s'));
118
			} else {
119
				//TODO: que faire si l'on n'est pas connecté ?
2140 mathias 120
			}
121
		} else {
122
			$requete = 'SELECT SQL_CALC_FOUND_ROWS id_observation '.
123
					'FROM del_observation AS do '.
124
					$this->sql->getJoin().
125
					'WHERE '.$this->sql->getWhere().
126
					$this->sql->getGroupBy().
127
					$this->sql->getOrderBy().
128
					$this->sql->getLimit().
129
					' -- '.__FILE__.':'.__LINE__;
2049 aurelien 130
		}
2140 mathias 131
		/*echo "REQ: "; var_dump($requete);
132
		exit;*/
2049 aurelien 133
		return $requete;
134
	}
135
 
136
	private function monActiviteEstDemandee() {
2052 aurelien 137
		return isset($this->paramsFiltres['masque.type']) && in_array('monactivite',array_keys($this->paramsFiltres['masque.type']));
2049 aurelien 138
	}
1375 raphael 139
 
1793 jpm 140
	/**
1845 jpm 141
	 * Après avoir récupérer seulement les ids dans une première requête, nous récupérons maintenant les infos.
142
	 * Le web service est ainsi 3 fois plus rapide.
1793 jpm 143
	 */
1881 jpm 144
	private function getInfosObs() {
145
		$idsObsConcat = implode(',', $this->idsObsOrdonnees);
1978 aurelien 146
		$requete = "SELECT id_observation, nom_sel AS `determination.ns`, nt AS `determination.nt`, ".
1845 jpm 147
			'nom_sel_nn AS `determination.nn`, famille AS `determination.famille`, '.
1994 aurelien 148
			'nom_referentiel AS `determination.referentiel`, ce_zone_geo AS id_zone_geo, pays, '.
1871 jpm 149
			'zone_geo, lieudit, station, milieu, date_observation, do.mots_cles_texte, '.
150
			'do.date_transmission, do.commentaire, '.
151
			'do.ce_utilisateur AS `auteur.id`, do.prenom_utilisateur AS `auteur.prenom`, '.
2213 arthur 152
			'do.nom_utilisateur AS `auteur.nom`, do.courriel_utilisateur AS `auteur.courriel`, '.
1845 jpm 153
			'id_image, date_prise_de_vue AS `date`, hauteur, largeur, nom_original '.
1871 jpm 154
			'FROM del_observation AS do '.
155
			'	LEFT JOIN del_image AS di ON (do.id_observation = di.ce_observation) '.
1845 jpm 156
			"WHERE id_observation IN ($idsObsConcat) ".
157
			' -- '.__FILE__.':'.__LINE__;
2049 aurelien 158
 
2140 mathias 159
		if ($this->monActiviteEstDemandee()) {
160
			$this->stockerEvenementsObs($idsObsConcat);
2049 aurelien 161
		}
162
 
1922 jpm 163
		//Debug::printr($requete);
1845 jpm 164
		return $this->bdd->recupererTous($requete);
1793 jpm 165
	}
2049 aurelien 166
 
2140 mathias 167
	private function stockerEvenementsObs($idsObsConcat) {
168
			$gestion_utilisateur = new GestionUtilisateur($this->conteneur);
169
			$utilisateur = $gestion_utilisateur->getUtilisateur();
170
			$id_utilisateur = $utilisateur['id_utilisateur'];
171
 
2059 aurelien 172
			$evenements = $this->sql->getEvenementsObs($idsObsConcat, $id_utilisateur);
2049 aurelien 173
			$this->evenements_obs = array();
174
 
175
			foreach($evenements as &$evenement) {
2067 aurelien 176
				$this->affecterTypeEvenement($evenement, $id_utilisateur, $evenement['id_observation']);
2049 aurelien 177
			}
178
	}
1375 raphael 179
 
2067 aurelien 180
	private function affecterTypeEvenement(&$evenement, $id_utilisateur, $id_observation) {
181
 
182
		$type = "";
183
		$infos = "";
184
 
2140 mathias 185
		// La date maximale détermine le type d'évènement
186
		switch($evenement['date_max']) {
187
			// Quelqu'un a fait un nouveau commentaire ou proposition
188
			case $evenement['date_com']:
189
				if(!empty($evenement['nom_sel_com'])) {
2067 aurelien 190
					$type = 'nouvelle_proposition';
2140 mathias 191
					$infos = $evenement['proposition_commentaire_nom_sel'];
192
				} else {
2067 aurelien 193
					$type = 'nouveau_commentaire';
2140 mathias 194
					$infos = $evenement['proposition_commentaire_texte'];
2049 aurelien 195
				}
196
 
197
				// J'ai commenté ou fait une proposition
198
				if($evenement['utilisateur_commentaire'] == $id_utilisateur) {
199
					$type .= "_vous_a_obs_autre";
2140 mathias 200
				} else {
2049 aurelien 201
					$type .= "_autre_sur_obs_vous";
2140 mathias 202
				}
2063 aurelien 203
				break;
204
 
205
			// Quelqu'un a répondu à un de mes commentaires ou une de mes propositions
206
			case $evenement['date_com_reponse']:
2140 mathias 207
					if(!empty($evenement['nom_sel_com_parent'])) {
208
						$type = 'nouvelle_reponse_autre_sur_proposition_vous';
209
					} else {
210
						$type = 'nouvelle_reponse_autre_sur_commentaire_vous';
2067 aurelien 211
					}
2140 mathias 212
					$infos = $evenement['proposition_commentaire_texte_commente'];
213
				break;
214
				// Quelqu'un a fait un nouveau vote
215
			case $evenement['date_vote']:
2056 aurelien 216
				$type = 'nouveau_vote';
217
				// Sur une proposition qui n'est pas à moi sur une observation à moi
2058 aurelien 218
				if($evenement['utilisateur_commentaire_vote'] != $evenement['utilisateur_observation'] && $evenement['utilisateur_commentaire_vote'] != $id_utilisateur) {
2056 aurelien 219
					$type .= "_autre_sur_com_autre_obs_vous";
220
				} else {
2057 aurelien 221
					// Sur une proposition qui est à moi sur une observation (à moi ou non)
2056 aurelien 222
					$type .= "_autre_sur_com_vous";
2067 aurelien 223
				}
2140 mathias 224
				$infos = $evenement['proposition_commentaire_nom_sel_votee'];
225
				break;
226
 
227
				// Quelqu'un a validé une proposition
228
			case $evenement['date_validation']:
2067 aurelien 229
				$type = "nouvelle_validation_autre_sur_prop_vous";
2140 mathias 230
				$infos = $evenement['proposition_validee_nom_sel'];
231
				// $type = "nouvelle_validation_vous_a_prop_autre";
232
				break;
233
				// Cas qui ne devrait jamais arriver
234
			default:
2067 aurelien 235
				$type = 'inconnu';
2140 mathias 236
				$infos = "";
2049 aurelien 237
		}
2067 aurelien 238
 
239
		$infos_evts = array('type' => $type, 'infos_complementaires' => $infos);
240
		// La requête est un peu trop complexe et certains évènements sortent en doublons
241
		// donc on dédoublonne ici (mais ça n'est pas une solution pérenne)
242
		// TODO: optimiser et simplifier ceci
243
		if(empty($this->evenementsObs[$id_observation])) {
244
			$this->evenementsObs[$id_observation] = array();
245
		}
246
		if(array_search($infos_evts, $this->evenementsObs[$id_observation]) === false) {
247
			$this->evenementsObs[$id_observation][] = $infos_evts;
248
		}
2049 aurelien 249
	}
250
 
1793 jpm 251
	/**
1845 jpm 252
	 * Les informations étant extraites d'une vue dont les infos des obs sont dupliquées pour chaque image,
253
	 * il nous faut maintenant récupérer qu'une seule fois les données d'observations et y intégrer les données
254
	 * des images.
1793 jpm 255
	 */
1881 jpm 256
	private function formaterObservations() {
257
		$observations = array_map('array_filter', $this->infosObs);
258
		$obsFormatees = array_flip($this->idsObsOrdonnees);// Permet de garder l'ordre de sortie !
1922 jpm 259
		foreach ($observations as &$obs) {
1845 jpm 260
			$this->nettoyerAuteur($obs);
1881 jpm 261
 
262
			$id = $obs['id_observation'];
1922 jpm 263
			// ATTENTION : la requête retourne de nombreuses lignes avec les mêmes données (test de l'existence nécessaire)
264
			if (is_array($obsFormatees[$id]) === false) {
265
				$obsFormatees[$id] = $obs;
266
			}
267
			$obsFormatees[$id]['images'][] = $this->extraireInfosImage($obs);
2049 aurelien 268
 
269
			if(isset($this->evenementsObs[$id])) {
270
				$obsFormatees[$id]['evenements'] = $this->evenementsObs[$id];
271
			}
1793 jpm 272
		}
1845 jpm 273
		return $obsFormatees;
274
	}
1494 raphael 275
 
1845 jpm 276
	private function nettoyerAuteur(&$obs) {
277
		// car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID
278
		// mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaire
279
		if (!isset($obs['auteur.id']) || !is_numeric($obs['auteur.id'])) {
280
			$obs['auteur.id'] = "0";
1375 raphael 281
		}
1845 jpm 282
		if (!isset($obs['auteur.nom'])) {
283
			$obs['auteur.nom'] = '[inconnu]';
284
		}
1416 raphael 285
	}
1375 raphael 286
 
1845 jpm 287
	private function extraireInfosImage(&$obs) {
288
		$champsImageAffichables = array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original');
289
		$image = array_intersect_key($obs, array_flip($champsImageAffichables));
290
		$urlImgTpl = $this->conteneur->getParametre('cel_img_url_tpl');
291
		$image['binaire.href'] = sprintf($urlImgTpl, $image['id_image'], 'XL');
1498 raphael 292
 
1845 jpm 293
		unset($obs['id_image'], $obs['date'], $obs['hauteur'], $obs['largeur'], $obs['nom_original']);
294
		return $image;
295
	}
1498 raphael 296
 
1793 jpm 297
	/**
298
	 * Récupérer toutes les déterminations et le nombre de commentaire au total
299
	 * @param array $observations la liste des observations à mettre à jour
300
	 */
1881 jpm 301
	private function chargerDeterminations() {
302
		$idObsConcat = implode(',', $this->idsObsOrdonnees);
1845 jpm 303
		$requete = 'SELECT * '.
304
			'FROM del_commentaire AS dc '.
305
			'WHERE dc.nom_sel IS NOT NULL '.
306
			"AND ce_observation IN ($idObsConcat) ".
307
			'-- '.__FILE__.':'.__LINE__;
1933 aurelien 308
 
309
		$commentaires = $this->chargerNombreCommentaireObs();
1375 raphael 310
 
1845 jpm 311
		$propositions = $this->bdd->recupererTous($requete);
312
		if ($propositions) {
313
			foreach ($propositions as $proposition) {
314
				$idObs = $proposition['ce_observation'];
315
				$idComment = $proposition['id_commentaire'];
316
				$comment = $this->formaterDetermination($idComment, $proposition);
317
				if ($comment) {
1881 jpm 318
					$this->infosObsOrdonnees[$idObs]['commentaires'][$idComment] = $comment;
1845 jpm 319
				}
1933 aurelien 320
				$this->infosObsOrdonnees[$idObs]['nb_commentaires'] = isset($commentaires[$idObs]) ? $commentaires[$idObs] : 0;
1845 jpm 321
			}
1793 jpm 322
		}
1494 raphael 323
	}
324
 
1845 jpm 325
	private function formaterDetermination($propositionId, $propositionInfos) {
326
		if (!$propositionInfos) return NULL;
1494 raphael 327
 
1845 jpm 328
		$propositionFormatee = array();
329
		foreach ($this->mappings['commentaires'] as $nomChamp => $nomAttributJson) {
330
			if (isset($propositionInfos[$nomChamp])) {
331
				$propositionFormatee[$nomAttributJson] = $propositionInfos[$nomChamp];
1793 jpm 332
			}
333
		}
1666 jpm 334
 
1793 jpm 335
		// Charger les votes sur les déterminations
1845 jpm 336
		$requete = "SELECT * FROM del_commentaire_vote WHERE ce_proposition = $propositionId".
337
			'-- '.__FILE__.':'.__LINE__;
338
		$resultatsVotes = $this->bdd->recupererTous($requete);
1793 jpm 339
		foreach ($resultatsVotes as $vote) {
1845 jpm 340
			$propositionFormatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);
1793 jpm 341
		}
1386 raphael 342
 
1845 jpm 343
		$propositionFormatee['nb_commentaires'] = $this->chargerNombreCommentaire($propositionId);
1386 raphael 344
 
1845 jpm 345
		return $propositionFormatee;
1494 raphael 346
	}
1375 raphael 347
 
1793 jpm 348
	/**
349
	 * Formater un vote en fonction du fichier de configuration config_votes.ini
350
	 * @param $votes array()
351
	 */
352
	private function formaterVote($vote) {
1845 jpm 353
		$voteFormate = array();
354
		foreach ($vote as $nomChamp => $valeur) {
355
			$voteFormate[$this->mappings['votes'][$nomChamp]] = $valeur;
1375 raphael 356
		}
1845 jpm 357
		return $voteFormate;
1375 raphael 358
	}
1933 aurelien 359
 
360
	private function chargerNombreCommentaireObs() {
2140 mathias 361
		$idObsConcat = implode(',', $this->idsObsOrdonnees);
362
		$requete = 'SELECT ce_observation, COUNT( id_commentaire ) AS nb '.
363
				'FROM del_commentaire '.
364
				"WHERE ce_observation IN ($idObsConcat) ".
365
				'GROUP BY ce_observation '.
366
				'-- '.__FILE__.':'.__LINE__;
1933 aurelien 367
		$commentaires = $this->bdd->recupererTous($requete);
368
 
369
		$commentaires_par_obs = array();
370
		foreach($commentaires as $commentaire) {
371
			$commentaires_par_obs[$commentaire['ce_observation']] = $commentaire['nb'];
372
		}
2140 mathias 373
 
374
		return $commentaires_par_obs;
1933 aurelien 375
	}
1845 jpm 376
 
377
	private function chargerNombreCommentaire($propositionId) {
378
		$requete = 'SELECT COUNT( id_commentaire ) AS nb '.
379
			'FROM del_commentaire '.
380
			"WHERE ce_proposition = $propositionId ".
381
			'GROUP BY ce_proposition '.
382
			'-- '.__FILE__.':'.__LINE__;
383
		$commentaires = $this->bdd->recuperer($requete);
384
		return $commentaires ? $commentaires['nb'] : 0;
385
	}
2213 arthur 386
}