Subversion Repositories eFlore/Applications.del

Rev

Rev 1881 | Rev 1933 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1881 Rev 1922
1
<?php
1
<?php
2
// declare(encoding='UTF-8');
2
// declare(encoding='UTF-8');
3
/**
3
/**
4
 * Web service récupèrant toutes les observations et, pour chacune d'elle, les images qui lui sont associées.
4
 * Web service récupèrant toutes les observations et, pour chacune d'elle, les images qui lui sont associées.
5
 *
5
 *
6
 * ATTENTION : le web service commence par récupérer seulement les id des obs (1er requete SQL), puis dans une
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
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 !
8
 * est 3 fois plus rapide !
9
 *
9
 *
10
 * @category   DEL
10
 * @category   DEL
11
 * @package    Services
11
 * @package    Services
12
 * @subpackage Observations
12
 * @subpackage Observations
13
 * @version    0.1
13
 * @version    0.1
14
 * @author     Mathias CHOUET <mathias@tela-botanica.org>
14
 * @author     Mathias CHOUET <mathias@tela-botanica.org>
15
 * @author     Jean-Pascal MILCENT <jpm@tela-botanica.org>
15
 * @author     Jean-Pascal MILCENT <jpm@tela-botanica.org>
16
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
16
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
17
 * @license    GPL v3 <http://www.gnu.org/licenses/gpl.txt>
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>
18
 * @license    CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
19
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
19
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
20
 */
20
 */
21
class ListeObservations {
21
class ListeObservations {
22
 
22
 
23
	private $conteneur;
23
	private $conteneur;
24
	private $bdd;
24
	private $bdd;
25
	private $navigation;
25
	private $navigation;
26
	private $filtrage;
26
	private $filtrage;
27
	private $sql;
27
	private $sql;
28
 
28
 
29
	private $mappings = array();
29
	private $mappings = array();
30
	private $paramsFiltres = array();
30
	private $paramsFiltres = array();
31
 
31
 
32
	private $idsObsOrdonnees = array();
32
	private $idsObsOrdonnees = array();
33
	private $infosObs = array();
33
	private $infosObs = array();
34
	private $infosObsOrdonnee = array();
34
	private $infosObsOrdonnee = array();
35
 
35
 
36
 
36
 
37
	public function __construct(Conteneur $conteneur) {
37
	public function __construct(Conteneur $conteneur) {
38
		$this->conteneur = $conteneur;
38
		$this->conteneur = $conteneur;
39
		$this->conteneur->chargerConfiguration('config_departements_bruts.ini');
39
		$this->conteneur->chargerConfiguration('config_departements_bruts.ini');
40
 
40
 
41
		$this->bdd = $this->conteneur->getBdd();
41
		$this->bdd = $this->conteneur->getBdd();
42
		$this->filtrage = $this->conteneur->getParametresFiltrage();
42
		$this->filtrage = $this->conteneur->getParametresFiltrage();
43
		$this->sql = $this->conteneur->getSql();
43
		$this->sql = $this->conteneur->getSql();
44
		$this->navigation = $this->conteneur->getNavigation();
44
		$this->navigation = $this->conteneur->getNavigation();
45
 
45
 
46
		$this->mappings['votes'] = $this->conteneur->getParametreTableau('votes.mapping');
46
		$this->mappings['votes'] = $this->conteneur->getParametreTableau('votes.mapping');
47
		$this->mappings['commentaires'] = $this->conteneur->getParametreTableau('commentaires.mapping');
47
		$this->mappings['commentaires'] = $this->conteneur->getParametreTableau('commentaires.mapping');
48
	}
48
	}
49
 
49
 
50
	public function consulter($ressources, $parametres) {
50
	public function consulter($ressources, $parametres) {
51
		$this->paramsFiltres = $this->filtrage->filtrerUrlParamsAppliObs();
51
		$this->paramsFiltres = $this->filtrage->filtrerUrlParamsAppliObs();
52
		$this->sql->setAppli(Sql::APPLI_OBS);
52
		$this->sql->setAppli(Sql::APPLI_OBS);
53
		$this->sql->setParametres($this->paramsFiltres);
53
		$this->sql->setParametres($this->paramsFiltres);
54
		$this->sql->ajouterContraintes();
54
		$this->sql->ajouterContraintes();
55
		$this->sql->ajouterConstrainteAppliObs();
55
		$this->sql->ajouterConstrainteAppliObs();
56
		$this->sql->definirOrdreSqlAppliObs();
56
		$this->sql->definirOrdreSqlAppliObs();
57
 
57
 
58
		$this->idsObsOrdonnees = $this->getIdObs();
58
		$this->idsObsOrdonnees = $this->getIdObs();
59
		$this->navigation->setTotal($this->sql->getTotalLignesTrouvees());
59
		$this->navigation->setTotal($this->sql->getTotalLignesTrouvees());
60
 
60
 
61
		// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats
61
		// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats
62
		$resultat = new ResultatService();
62
		$resultat = new ResultatService();
63
		$resultat->corps = array('entete' => $this->navigation->getEntete(), 'resultats' => array());
63
		$resultat->corps = array('entete' => $this->navigation->getEntete(), 'resultats' => array());
64
		if (count($this->idsObsOrdonnees) > 0) {
64
		if (count($this->idsObsOrdonnees) > 0) {
65
 
65
 
66
			// 2) récupération des données nécessaires pour ces observations (obs + images)
66
			// 2) récupération des données nécessaires pour ces observations (obs + images)
67
			$this->infosObs = $this->getInfosObs();
67
			$this->infosObs = $this->getInfosObs();
68
 
68
 
69
			// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output
69
			// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output
70
			$this->infosObsOrdonnees = $this->formaterObservations();
70
			$this->infosObsOrdonnees = $this->formaterObservations();
71
 
71
 
72
			// 4) Ajouter commentaires + votes à $this->infosObsOrdonnees
72
			// 4) Ajouter commentaires + votes à $this->infosObsOrdonnees
73
			$this->chargerDeterminations();
73
			$this->chargerDeterminations();
74
 
74
 
75
			$resultat->corps = array(
75
			$resultat->corps = array(
76
				'entete' => $this->navigation->getEntete(),
76
				'entete' => $this->navigation->getEntete(),
77
				//'resultats' => array_values($this->infosObsOrdonnees));
77
				//'resultats' => array_values($this->infosObsOrdonnees));
78
				// TODO : renvoyer un vrai tableau et non un objet
78
				// TODO : renvoyer un vrai tableau et non un objet
79
				'resultats' => $this->infosObsOrdonnees);
79
				'resultats' => $this->infosObsOrdonnees);
80
		}
80
		}
81
		return $resultat;
81
		return $resultat;
82
	}
82
	}
83
 
83
 
84
	// SQL helpers
84
	// SQL helpers
85
	/*
85
	/*
86
	 * Retourne une liste ordonnée d'id d'observation correspondant aux critères
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
87
	 * passés dans p et aux clauses where/join présentes dans le tableau $req
88
	 *
88
	 *
89
	 * @param p: $params (filtrés sauf escape-string)
89
	 * @param p: $params (filtrés sauf escape-string)
90
	 * @param req: le tableau représentant les composants de la requete SQL
90
	 * @param req: le tableau représentant les composants de la requete SQL
91
	 * @param db: l'instance de db
91
	 * @param db: l'instance de db
92
	 */
92
	 */
93
	private function getIdObs() {
93
	private function getIdObs() {
94
		$requete = 'SELECT SQL_CALC_FOUND_ROWS id_observation '.
94
		$requete = 'SELECT SQL_CALC_FOUND_ROWS id_observation '.
95
			'FROM del_observation AS do '.
95
			'FROM del_observation AS do '.
96
			$this->sql->getJoin().
96
			$this->sql->getJoin().
97
			'WHERE '.$this->sql->getWhere().
97
			'WHERE '.$this->sql->getWhere().
98
			$this->sql->getGroupBy().
98
			$this->sql->getGroupBy().
99
			$this->sql->getOrderBy().
99
			$this->sql->getOrderBy().
100
			$this->sql->getLimit().
100
			$this->sql->getLimit().
101
			' -- '.__FILE__.':'.__LINE__;
101
			' -- '.__FILE__.':'.__LINE__;
102
		//Debug::printr($requete);
102
		//Debug::printr($requete);
103
		$resultats = $this->bdd->recupererTous($requete);
103
		$resultats = $this->bdd->recupererTous($requete);
104
 
104
 
105
		$idObs = array();
105
		$idObs = array();
106
		if ($resultats !== false ) {
106
		if ($resultats !== false ) {
107
			foreach ($resultats as $resultat) {
107
			foreach ($resultats as $resultat) {
108
				$idObs[] = $resultat['id_observation'];
108
				$idObs[] = $resultat['id_observation'];
109
			}
109
			}
110
		}
110
		}
111
		return $idObs;
111
		return $idObs;
112
	}
112
	}
113
 
113
 
114
	/**
114
	/**
115
	 * Après avoir récupérer seulement les ids dans une première requête, nous récupérons maintenant les infos.
115
	 * Après avoir récupérer seulement les ids dans une première requête, nous récupérons maintenant les infos.
116
	 * Le web service est ainsi 3 fois plus rapide.
116
	 * Le web service est ainsi 3 fois plus rapide.
117
	 */
117
	 */
118
	private function getInfosObs() {
118
	private function getInfosObs() {
119
		$idsObsConcat = implode(',', $this->idsObsOrdonnees);
119
		$idsObsConcat = implode(',', $this->idsObsOrdonnees);
-
 
120
		// TODO : bizarement MYSQL 5.6 retourne plusieurs fois les mêmes enregistrements d'où le DISTINCT (normalement inutile)
120
		$requete = "SELECT id_observation, nom_sel AS `determination.ns`, nt AS `determination.nt`, ".
121
		$requete = "SELECT DISTINCT id_observation, nom_sel AS `determination.ns`, nt AS `determination.nt`, ".
121
			'nom_sel_nn AS `determination.nn`, famille AS `determination.famille`, '.
122
			'nom_sel_nn AS `determination.nn`, famille AS `determination.famille`, '.
122
			'nom_referentiel AS `determination.referentiel`, ce_zone_geo AS id_zone_geo, '.
123
			'nom_referentiel AS `determination.referentiel`, ce_zone_geo AS id_zone_geo, '.
123
			'zone_geo, lieudit, station, milieu, date_observation, do.mots_cles_texte, '.
124
			'zone_geo, lieudit, station, milieu, date_observation, do.mots_cles_texte, '.
124
			'do.date_transmission, do.commentaire, '.
125
			'do.date_transmission, do.commentaire, '.
125
			'do.ce_utilisateur AS `auteur.id`, do.prenom_utilisateur AS `auteur.prenom`, '.
126
			'do.ce_utilisateur AS `auteur.id`, do.prenom_utilisateur AS `auteur.prenom`, '.
126
			'do.nom_utilisateur AS `auteur.nom`, do.courriel_utilisateur AS `auteur.courriel`, '.
127
			'do.nom_utilisateur AS `auteur.nom`, do.courriel_utilisateur AS `auteur.courriel`, '.
127
			'id_image, date_prise_de_vue AS `date`, hauteur, largeur, nom_original '.
128
			'id_image, date_prise_de_vue AS `date`, hauteur, largeur, nom_original '.
128
			'FROM del_observation AS do '.
129
			'FROM del_observation AS do '.
129
			'	LEFT JOIN del_image AS di ON (do.id_observation = di.ce_observation) '.
130
			'	LEFT JOIN del_image AS di ON (do.id_observation = di.ce_observation) '.
130
			"WHERE id_observation IN ($idsObsConcat) ".
131
			"WHERE id_observation IN ($idsObsConcat) ".
131
			' -- '.__FILE__.':'.__LINE__;
132
			' -- '.__FILE__.':'.__LINE__;
-
 
133
		//Debug::printr($requete);
132
		return $this->bdd->recupererTous($requete);
134
		return $this->bdd->recupererTous($requete);
133
	}
135
	}
134
 
136
 
135
	/**
137
	/**
136
	 * Les informations étant extraites d'une vue dont les infos des obs sont dupliquées pour chaque image,
138
	 * Les informations étant extraites d'une vue dont les infos des obs sont dupliquées pour chaque image,
137
	 * il nous faut maintenant récupérer qu'une seule fois les données d'observations et y intégrer les données
139
	 * il nous faut maintenant récupérer qu'une seule fois les données d'observations et y intégrer les données
138
	 * des images.
140
	 * des images.
139
	 */
141
	 */
140
	private function formaterObservations() {
142
	private function formaterObservations() {
141
		$observations = array_map('array_filter', $this->infosObs);
143
		$observations = array_map('array_filter', $this->infosObs);
142
		$obsFormatees = array_flip($this->idsObsOrdonnees);// Permet de garder l'ordre de sortie !
144
		$obsFormatees = array_flip($this->idsObsOrdonnees);// Permet de garder l'ordre de sortie !
143
		foreach ($observations as $obs) {
145
		foreach ($observations as &$obs) {
144
			$this->nettoyerAuteur($obs);
146
			$this->nettoyerAuteur($obs);
145
 
147
 
146
			$id = $obs['id_observation'];
148
			$id = $obs['id_observation'];
-
 
149
			// ATTENTION : la requête retourne de nombreuses lignes avec les mêmes données (test de l'existence nécessaire)
-
 
150
			if (is_array($obsFormatees[$id]) === false) {
147
			$obsFormatees[$id] = $obs;
151
				$obsFormatees[$id] = $obs;
148
 
152
			}
149
			$image = $this->extraireInfosImage($obs);
153
			$obsFormatees[$id]['images'][] = $this->extraireInfosImage($obs);
150
			$obsFormatees[$id]['images'][] = $image;
-
 
151
		}
154
		}
152
		return $obsFormatees;
155
		return $obsFormatees;
153
	}
156
	}
154
 
157
 
155
	private function nettoyerAuteur(&$obs) {
158
	private function nettoyerAuteur(&$obs) {
156
		// car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID
159
		// car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID
157
		// mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaire
160
		// mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaire
158
		if (!isset($obs['auteur.id']) || !is_numeric($obs['auteur.id'])) {
161
		if (!isset($obs['auteur.id']) || !is_numeric($obs['auteur.id'])) {
159
			$obs['auteur.id'] = "0";
162
			$obs['auteur.id'] = "0";
160
		}
163
		}
161
		if (!isset($obs['auteur.nom'])) {
164
		if (!isset($obs['auteur.nom'])) {
162
			$obs['auteur.nom'] = '[inconnu]';
165
			$obs['auteur.nom'] = '[inconnu]';
163
		}
166
		}
164
	}
167
	}
165
 
168
 
166
	private function extraireInfosImage(&$obs) {
169
	private function extraireInfosImage(&$obs) {
167
		$champsImageAffichables = array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original');
170
		$champsImageAffichables = array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original');
168
		$image = array_intersect_key($obs, array_flip($champsImageAffichables));
171
		$image = array_intersect_key($obs, array_flip($champsImageAffichables));
169
		$urlImgTpl = $this->conteneur->getParametre('cel_img_url_tpl');
172
		$urlImgTpl = $this->conteneur->getParametre('cel_img_url_tpl');
170
		$image['binaire.href'] = sprintf($urlImgTpl, $image['id_image'], 'XL');
173
		$image['binaire.href'] = sprintf($urlImgTpl, $image['id_image'], 'XL');
171
 
174
 
172
		unset($obs['id_image'], $obs['date'], $obs['hauteur'], $obs['largeur'], $obs['nom_original']);
175
		unset($obs['id_image'], $obs['date'], $obs['hauteur'], $obs['largeur'], $obs['nom_original']);
173
		return $image;
176
		return $image;
174
	}
177
	}
175
 
178
 
176
	/**
179
	/**
177
	 * Récupérer toutes les déterminations et le nombre de commentaire au total
180
	 * Récupérer toutes les déterminations et le nombre de commentaire au total
178
	 * @param array $observations la liste des observations à mettre à jour
181
	 * @param array $observations la liste des observations à mettre à jour
179
	 */
182
	 */
180
	private function chargerDeterminations() {
183
	private function chargerDeterminations() {
181
		$idObsConcat = implode(',', $this->idsObsOrdonnees);
184
		$idObsConcat = implode(',', $this->idsObsOrdonnees);
182
		$requete = 'SELECT * '.
185
		$requete = 'SELECT * '.
183
			'FROM del_commentaire AS dc '.
186
			'FROM del_commentaire AS dc '.
184
			'WHERE dc.nom_sel IS NOT NULL '.
187
			'WHERE dc.nom_sel IS NOT NULL '.
185
			"AND ce_observation IN ($idObsConcat) ".
188
			"AND ce_observation IN ($idObsConcat) ".
186
			'-- '.__FILE__.':'.__LINE__;
189
			'-- '.__FILE__.':'.__LINE__;
187
 
190
 
188
		$propositions = $this->bdd->recupererTous($requete);
191
		$propositions = $this->bdd->recupererTous($requete);
189
		if ($propositions) {
192
		if ($propositions) {
190
			foreach ($propositions as $proposition) {
193
			foreach ($propositions as $proposition) {
191
				$idObs = $proposition['ce_observation'];
194
				$idObs = $proposition['ce_observation'];
192
				$idComment = $proposition['id_commentaire'];
195
				$idComment = $proposition['id_commentaire'];
193
				$comment = $this->formaterDetermination($idComment, $proposition);
196
				$comment = $this->formaterDetermination($idComment, $proposition);
194
				if ($comment) {
197
				if ($comment) {
195
					$this->infosObsOrdonnees[$idObs]['commentaires'][$idComment] = $comment;
198
					$this->infosObsOrdonnees[$idObs]['commentaires'][$idComment] = $comment;
196
				}
199
				}
197
			}
200
			}
198
		}
201
		}
199
	}
202
	}
200
 
203
 
201
	private function formaterDetermination($propositionId, $propositionInfos) {
204
	private function formaterDetermination($propositionId, $propositionInfos) {
202
		if (!$propositionInfos) return NULL;
205
		if (!$propositionInfos) return NULL;
203
 
206
 
204
		$propositionFormatee = array();
207
		$propositionFormatee = array();
205
		foreach ($this->mappings['commentaires'] as $nomChamp => $nomAttributJson) {
208
		foreach ($this->mappings['commentaires'] as $nomChamp => $nomAttributJson) {
206
			if (isset($propositionInfos[$nomChamp])) {
209
			if (isset($propositionInfos[$nomChamp])) {
207
				$propositionFormatee[$nomAttributJson] = $propositionInfos[$nomChamp];
210
				$propositionFormatee[$nomAttributJson] = $propositionInfos[$nomChamp];
208
			}
211
			}
209
		}
212
		}
210
 
213
 
211
		// Charger les votes sur les déterminations
214
		// Charger les votes sur les déterminations
212
		$requete = "SELECT * FROM del_commentaire_vote WHERE ce_proposition = $propositionId".
215
		$requete = "SELECT * FROM del_commentaire_vote WHERE ce_proposition = $propositionId".
213
			'-- '.__FILE__.':'.__LINE__;
216
			'-- '.__FILE__.':'.__LINE__;
214
		$resultatsVotes = $this->bdd->recupererTous($requete);
217
		$resultatsVotes = $this->bdd->recupererTous($requete);
215
		foreach ($resultatsVotes as $vote) {
218
		foreach ($resultatsVotes as $vote) {
216
			$propositionFormatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);
219
			$propositionFormatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);
217
		}
220
		}
218
 
221
 
219
		$propositionFormatee['nb_commentaires'] = $this->chargerNombreCommentaire($propositionId);
222
		$propositionFormatee['nb_commentaires'] = $this->chargerNombreCommentaire($propositionId);
220
 
223
 
221
		return $propositionFormatee;
224
		return $propositionFormatee;
222
	}
225
	}
223
 
226
 
224
	/**
227
	/**
225
	 * Formater un vote en fonction du fichier de configuration config_votes.ini
228
	 * Formater un vote en fonction du fichier de configuration config_votes.ini
226
	 * @param $votes array()
229
	 * @param $votes array()
227
	 */
230
	 */
228
	private function formaterVote($vote) {
231
	private function formaterVote($vote) {
229
		$voteFormate = array();
232
		$voteFormate = array();
230
		foreach ($vote as $nomChamp => $valeur) {
233
		foreach ($vote as $nomChamp => $valeur) {
231
			$voteFormate[$this->mappings['votes'][$nomChamp]] = $valeur;
234
			$voteFormate[$this->mappings['votes'][$nomChamp]] = $valeur;
232
		}
235
		}
233
		return $voteFormate;
236
		return $voteFormate;
234
	}
237
	}
235
 
238
 
236
	private function chargerNombreCommentaire($propositionId) {
239
	private function chargerNombreCommentaire($propositionId) {
237
		$requete = 'SELECT COUNT( id_commentaire ) AS nb '.
240
		$requete = 'SELECT COUNT( id_commentaire ) AS nb '.
238
			'FROM del_commentaire '.
241
			'FROM del_commentaire '.
239
			"WHERE ce_proposition = $propositionId ".
242
			"WHERE ce_proposition = $propositionId ".
240
			'GROUP BY ce_proposition '.
243
			'GROUP BY ce_proposition '.
241
			'-- '.__FILE__.':'.__LINE__;
244
			'-- '.__FILE__.':'.__LINE__;
242
		$commentaires = $this->bdd->recuperer($requete);
245
		$commentaires = $this->bdd->recuperer($requete);
243
		return $commentaires ? $commentaires['nb'] : 0;
246
		return $commentaires ? $commentaires['nb'] : 0;
244
	}
247
	}
245
}
248
}