Subversion Repositories eFlore/Applications.moissonnage

Rev

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

Rev Author Line No. Line
26 alex 1
<?php
2
 
34 alex 3
/**
4
 *
5
 * Classe principale du web service qui peut traiter des requetes provenant d'un navigateur web
6
 * (stations dans bbox ou observations sur un point), ou d'un client SIG via appel au protocole/service WFS
7
 * (demande d'observations par stations selon des filtres optionnels). Le web service analyse et verifie
8
 * les parametres de l'URL de la requete qu'il recoit. S'ils sont tous valides, il va appeler une autre classe
9
 * pour recuperer les informations demandees dans les differentes sources de donnees.
10
 * Les donnees recuperees sont ensuite combinees si plusieurs sources sont demandees et mises en forme
11
 * au format de sortie. Les formats de sortie utilises sont le GeoJSON (extension de JSON pour les donnees
12
 * geographiques) en destination des navigateurs web et le GML adapte au service WFS pour les clients SIG.
13
 * Dans le cas ou des erreurs sont levees, le web service renvoie un message d'erreur expliquant le probleme
14
 * recnontre dans son fonctionnement.
15
 *
16
 *
17
 * @package framework-0.4
18
 * @author Alexandre GALIBERT <alexandre.galibert@tela-botanica.org>
19
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
20
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
21
 * @version $Id$
22
 * @copyright 2013 Tela Botanica (accueil@tela-botanica.org)
23
 *
24
 */
25
 
26 alex 26
class Commun {
27
 
28
 
34 alex 29
	private $parametres = array();
30
	private $ressources = array();
31
	private $nomSource = '';
32
	private $nomService = '';
26 alex 33
 
34 alex 34
	private $verificateur = null;
35
	private $parametresRecherche = null;
36
	private $retour = array();
26 alex 37
 
34 alex 38
	const MIME_WFS = 'text/xml';
26 alex 39
 
34 alex 40
 
26 alex 41
	public function consulter($ressources, $parametres) {
42
		$this->recupererRessourcesEtParametres($ressources, $parametres);
43
		$retour = null;
34 alex 44
		if (in_array("wfs", $ressources)) {
45
			$retour = $this->traiterRequeteWfs();
46
		} else {
47
			$retour = $this->traiterRequeteNavigateur();
48
		}
49
		return $retour;
50
	}
51
 
52
 
53
 
54
	/*********************************************/
55
	// Verification parametres URL non-WFS
56
 
57
	private function traiterRequeteWfs() {
58
		$retour = null;
26 alex 59
		try {
34 alex 60
			$this->parametresRecherche = new StdClass();
61
			$this->traiterParametreOperation();
62
			if ($this->parametresRecherche->operation != 'GetCapabilities') {
63
				$this->traiterParametreSource();
64
			}
65
			if ($this->parametresRecherche->operation == 'GetFeature') {
66
				$retour = $this->getFeature();
67
			} else {
68
				$formateurWfs = new FormateurWfs();
69
				$nomMethode = 'formater'.$this->parametresRecherche->operation;
70
				$parametre = isset($this->parametresRecherche->sources)
71
					? $this->parametresRecherche->sources : null;
72
				$retour = new ResultatService();
73
				$retour->mime = self::MIME_WFS;
74
				$retour->corps = $formateurWfs->$nomMethode($parametre);
75
			}
76
		} catch (Exception $erreur) {
77
			$formateurWfs = new FormateurWfs();
78
			$retour = new ResultatService();
79
			$retour->mime = self::MIME_WFS;
80
			$retour->corps = $formateurWfs->formaterException($erreur);
81
		}
82
		return $retour;
83
	}
84
 
85
	private function getFeature() {
86
		if (array_key_exists('bbox', $this->parametres)) {
87
			$this->traiterParametreBbox();
88
		} elseif (array_key_exists('filter', $this->parametres)) {
89
			$this->traiterParametreFilter();
90
		}
91
		$this->recupererStationsWfs();
92
		$formateurWfs = new FormateurWfs();
93
		$retour = new ResultatService();
94
		$retour->mime = self::MIME_WFS;
95
		$retour->corps = $formateurWfs->formaterGetFeature($this->retour, $this->parametresRecherche->sources);
96
		return $retour;
97
	}
98
 
99
	private function traiterParametreOperation() {
100
		if ($this->verifierExistenceParametre('request')) {
101
			if (!$this->estOperationWfsAutorisee()) {
102
				$message = "L'opération '".$this->parametres['request']."' n'est pas autorisée.\n".
103
					"Les opérations suivantes sont permises par le service : ".Config::get('operations_wfs');
26 alex 104
				throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
105
			} else {
34 alex 106
				$this->parametresRecherche->operation = $this->parametres['request'];
107
			}
108
		}
109
	}
110
 
111
	private function verifierExistenceParametre($nomParametre) {
112
		$estParametreExistant = false;
113
		if (!array_key_exists($nomParametre, $this->parametres)) {
114
			$message = "Le paramètre nom de l'opération '{$nomParametre}' ".
115
				"n'a pas été trouvé dans la liste des paramètres.";
116
			throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
117
		} else {
118
			$estParametreExistant = true;
119
		}
120
		return $estParametreExistant;
121
	}
122
 
123
	private function estOperationWfsAutorisee() {
124
		$operationsWfsService = explode(',' , Config::get('operations_wfs'));
125
		return (in_array($this->parametres['request'], $operationsWfsService));
126
	}
127
 
128
	private function traiterParametreSource() {
129
		// le parametre source (typename) est optionnel par defaut
130
		if (array_key_exists('typename', $this->parametres)) {
131
			$sources = explode(',', $this->parametres['typename']);
132
			$estSourceValide = true;
133
			foreach ($sources as $source) {
134
				if (!$this->verifierExistenceSourcesDonnees($source)) {
135
					$message = "Source de donnees '{$source}' indisponible. Les sources disponibles sont : ".
136
						Config::get('sources_dispo');
137
					$estSourceValide = false;
138
					throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
139
				}
140
			}
141
			if ($estSourceValide) {
142
				$this->parametresRecherche->sources = $sources;
143
			}
144
		}
145
	}
146
 
147
	private function traiterParametreBbox() {
148
		$bboxVerifiee = $this->verifierCoordonneesBbox($this->parametres['bbox']);
149
		if (is_array($bboxVerifiee) && count($bboxVerifiee) == 4) {
150
			$this->parametresRecherche->bbox = array($bboxVerifiee);
151
		}
152
	}
153
 
154
	private function verifierCoordonneesBbox($bbox) {
155
		$bboxVerifiee = null;
156
		// verifier que la chaine de caracteres $bbox est une serie de chaque nombre decimaux
157
		// separes entre eux par une virgule
158
		if (preg_match('/^(-?\d{1,3}(.\d+)?,){3}(-?\d{1,3}(.\d+)?)$/', $bbox) == 0) {
159
			$message = "Format de saisie des coordonnees de la bounding box non valide.  Le service ".
160
					"n'accepte seulement qu'une serie de 4 nombre décimaux séparés par des virgules.";
161
			throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
162
		} else {
163
			$coordonnees = explode(',', $bbox);
164
			$nomsIndexBbox = array("ouest", "sud", "est", "nord");
165
			$bbox = array();
166
			for ($i = 0; $i < count($coordonnees); $i ++) {
167
				$bbox[$nomsIndexBbox[$i]] = $coordonnees[$i];
168
			}
169
			// verifier que les coordonnees de chaque bord de la bbox sont valides
170
			if ($this->estUneBboxValide($bbox)) {
171
				$bboxVerifiee = $bbox;
172
			} else {
173
				$message = "Certaines coordonnées de la bounding box sont situés en dehors des limites ".
174
						"de notre monde";
175
				throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
176
			}
177
		}
178
		return $bboxVerifiee;
179
	}
180
 
181
	private function estUneBboxValide($bbox) {
182
		$monde = array(
183
			'ouest' => floatval(Config::get('carte.limite_ouest')),
184
			'est'   => floatval(Config::get('carte.limite_est')),
185
			'sud'   => floatval(Config::get('carte.limite_sud')),
186
			'nord'  => floatval(Config::get('carte.limite_nord'))
187
		);
188
		return (floatval($bbox['ouest']) >= $monde['ouest']  && floatval($bbox['ouest']) <= $monde['est']
189
			&& floatval($bbox['est'])   >= $monde['ouest']  && floatval($bbox['est'])   <= $monde['est']
190
			&& floatval($bbox['nord'])  >= $monde['sud']    && floatval($bbox['nord'])  <= $monde['nord']
191
			&& floatval($bbox['sud'])   >= $monde['sud']    && floatval($bbox['sud'])   <= $monde['nord']);
192
	}
193
 
194
	private function traiterParametreFilter() {
195
		// la valeur du parametre filter est une chaine de texte qui compose en realite un document XML
196
		// plus d'infos a l'URL suivante : http://mapserver.org/fr/ogc/filter_encoding.html
197
		$filtreTexte = $this->recupererTexteParametreFilter();
198
		$documentXML = new DomDocument();
199
		$documentXML->loadXML($filtreTexte);
200
		$filtres = $documentXML->documentElement->childNodes;
201
		for ($index = 0; $index < $filtres->length; $index ++) {
202
			$this->verifierFiltre($filtres->item($index));
203
		}
204
	}
205
 
206
	private function recupererTexteParametreFilter() {
207
		$parametresUrl = explode("&", $_SERVER['QUERY_STRING']);
208
		$filtreTexte = '';
209
		foreach ($parametresUrl as $parametre) {
210
			list($cle, $valeur) = explode("=", $parametre);
211
			if ($cle == 'filter') {
212
				$filtreTexte = rawurldecode($valeur);
213
			}
214
		}
215
		return $filtreTexte;
216
	}
217
 
218
	private function verifierFiltre($filtre) {
219
		$operateursAcceptes = explode(',', Config::get('operateurs_wfs'));
220
		$nomOperateur = $filtre->tagName;
221
		if (!in_array($nomOperateur, $operateursAcceptes)) {
222
			$message = "Le filtre '$nomOperateur' n'est pas pris en compte par le serrvice. ".
223
			"Les opérateurs acceptés sont :".implode(', ', $operateursAcceptes);
224
			throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
225
		} else {
226
			if ($nomOperateur == 'BBOX') {
227
				$bboxUrl = $filtre->lastChild->nodeValue;
228
				$bboxVerifiee = $this->verifierCoordonneesBbox($bboxUrl);
229
				$this->parametresRecherche->bbox = array($bboxVerifiee);
230
			} else {
231
				$this->traiterOperateurScalaire($filtre);
232
			}
233
		}
234
	}
235
 
236
	private function traiterOperateurScalaire($filtre) {
237
		$nomOperateur = $filtre->tagName;
238
		$champ  = $filtre->childNodes->item(0)->nodeValue;
239
		if ($champ != Config::get('champ_filtrage_wfs')) {
240
			$message = "Le filtre ne peut pas être appliqué sur le champ '$champ'. ".
241
					"Il est seulement accepté sur le champ '".Config::get('champ_filtrage_wfs')."'";
242
			throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
243
		} else {
244
			$valeur = $filtre->childNodes->item(1)->nodeValue;
245
			$operateur =  $nomOperateur == 'PropertyIsEqualTo' ? "=" : "LIKE";
246
			$this->parametresRecherche->filtre = array("champ" => $champ, "operateur" => $operateur,
247
					"valeur" => $valeur);
248
		}
249
	}
250
 
251
	private function recupererStationsWfs() {
252
		$this->nomMethode = $this->ressources[0];
253
		foreach ($this->parametresRecherche->sources as $source) {
254
			$source = trim($source);
255
			$resultat = $this->traiterSource($source);
256
			$this->ajouterResultat($resultat, $source);
257
		}
258
	}
259
 
260
 
261
 
262
	/*********************************************/
263
	// Verification parametres URL non-WFS
264
 
265
	private function traiterRequeteNavigateur() {
266
		$retour = null;
267
		try {
268
			if (!$this->estParametreSourceExistant()) {
269
				$message = "Le paramètre source de données n'a pas été indiqué.";
270
				throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
271
			} else {
26 alex 272
				$this->verifierParametres();
34 alex 273
				$listeSources = explode(',', $this->parametres['source']);
274
				foreach ($listeSources as $source) {
275
					$source = trim($source);
276
					$resultat = $this->traiterSource($source);
277
					$this->ajouterResultat($resultat, $source);
31 alex 278
				}
26 alex 279
			}
34 alex 280
			$formateur = new FormateurJson();
281
			$nomMethode = 'formater'.ucfirst($this->ressources[0]);
282
			$retour = new ResultatService();
283
			$retour->corps = $formateur->$nomMethode($this->retour);
26 alex 284
		} catch (Exception $erreur) {
34 alex 285
			$retour = $erreur;
26 alex 286
		}
287
		return $retour;
288
	}
289
 
290
	private function recupererRessourcesEtParametres($ressources, $parametres) {
291
		$this->ressources = $ressources;
34 alex 292
		$this->parametres = array();
293
		foreach ($parametres as $nomParametre => $valeur) {
294
			$this->parametres[strtolower($nomParametre)] = $valeur;
295
		}
26 alex 296
	}
297
 
34 alex 298
	private function estParametreSourceExistant() {
299
		$parametreExiste = false;
300
		if (isset($this->parametres['source'])) {
301
			$parametreExiste = true;
302
		}
303
		return $parametreExiste;
304
	}
305
 
306
	private function verifierExistenceSourcesDonnees($source) {
26 alex 307
		$sourcesDisponibles = explode(',', Config::get('sources_dispo'));
308
		$estDisponible = false;
34 alex 309
		if (in_array($source, $sourcesDisponibles)) {
26 alex 310
			$estDisponible = true;
311
		}
312
		return $estDisponible;
313
	}
314
 
315
	private function verifierParametres() {
316
		$this->verificateur = new VerificateurParametres($this->parametres);
317
		$this->verificateur->verifierParametres();
318
		if ($this->verificateur->contientErreurs()) {
319
			$this->verificateur->leverException();
320
		} else {
321
			$this->recupererParametresRecherche();
322
		}
323
	}
324
 
34 alex 325
	private function traiterSource($source) {
326
		$retour = array();
327
		if (!$this->verifierExistenceSourcesDonnees($source)) {
328
			$message = "Source de donnees indisponible";
329
			throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
330
		} else {
331
			$this->chargerNomService($source);
332
			$retour = $this->executerServicePourSource($source);
333
		}
334
		return $retour;
335
	}
336
 
26 alex 337
	private function recupererParametresRecherche() {
338
		$this->parametresRecherche = $this->verificateur->renvoyerResultatVerification();
339
	}
340
 
34 alex 341
	private function chargerNomSource($source) {
31 alex 342
		if (isset($this->parametres['source'])) {
343
			$this->nomSource = $this->parametres['source'];
344
		} else {
345
			$this->nomSource = Config::get('source_defaut');
346
		}
347
	}
26 alex 348
 
34 alex 349
	private function chargerNomService($source) {
350
		$this->nomService = ($source == 'floradata' ? 'Floradata' : 'Moissonnage').'Formateur';
351
		Projets::chargerConfigurationSource($source);
31 alex 352
	}
34 alex 353
 
354
	private function executerServicePourSource($source) {
355
		$objetTraitement = new $this->nomService($this->parametresRecherche, $source);
31 alex 356
		$methode = $this->genererNomMethodeAExecuter();
357
		return $objetTraitement->$methode();
358
	}
359
 
360
	private function genererNomMethodeAExecuter() {
361
		return 'recuperer' . ucfirst($this->ressources[0]);
362
	}
363
 
34 alex 364
 
365
	private function ajouterResultat(& $resultat, $source) {
366
		if (count($this->retour) > 0) {
367
			if ($this->ressources[0] == 'stations' && count($resultat) > 0
368
				&& $this->doitTransformerTypeDonnees($resultat)) {
369
				$this->combinerResultats($resultat, $source);
370
			} else {
371
				$this->retour = array_merge($this->retour, $resultat);
372
			}
373
		} else {
374
			$this->retour = array_merge($this->retour, $resultat);
375
		}
376
	}
377
 
378
	private function doitTransformerTypeDonnees(& $resultat) {
379
		return ($this->parametresRecherche->zoom <= Config::get('zoom_maximal_maillage') &&
380
			(($resultat[0]['type_site'] == 'MAILLE' || $this->retour[0]['type_site'] == 'MAILLE')
381
			|| ($resultat[0]['type_site'] != 'MAILLE' && $this->retour[0]['type_site'] != 'MAILLE'
382
				&& count($resultat) + count($this->retour) > Config::get('seuil_maillage')))
383
		);
384
	}
385
 
386
	private function combinerResultats(& $resultat, $source) {
387
		$maillage = new Maillage($this->parametresRecherche->bbox, $this->parametresRecherche->zoom, $source);
388
		$maillage->genererMaillesVides();
389
		if ($resultat[0]['type_site'] == 'MAILLE') {
390
			$maillage->ajouterMailles($resultat);
391
		} else {
392
			$maillage->ajouterStations($resultat);
393
		}
394
		if ($this->retour[0]['type_site'] == 'MAILLE') {
395
			$maillage->ajouterMailles($this->retour);
396
		} else {
397
			$maillage->ajouterStations($this->retour);
398
		}
399
		$this->retour = $maillage->formaterSortie();
400
	}
401
 
26 alex 402
}
403
 
404
?>