Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

Rev Author Line No. Line
6 jpm 1
<?php
2
/**
3
* Description :
4
* Classe ZoneGeo.php fournit des informations sur un ensemble de lieux à une échelle donnée.
5
* Le but étant de fournir un ensemble minimal d'information comprenant :
6
* un identifiant (numérique ou alphanumérique sous forme de ChatMot si possible), un nom, une region et
7
* éventuellement une relation hiérarchique avec un autre terme (=classe).
8
* Si l'url finit par /zone-geo on retourne une liste de zones (seulement les 100 premières par défaut).
9
* L'url peut contenir des paramètres optionnels passés après le ? : /zone-geo?param1=val1&param2=val2&...
10
*
11
* Les paramètres de requête disponibles sont : masque, masque.code, masque.nom, masque.region , recherche,
12
* distinct, retour.format, navigation.depart et navigation.limite.
13
*
14
* Encodage en entrée : utf8
15
* Encodage en sortie : utf8
16
* @package framework-v3
17
* @author Delphine Cauquil <delphine@tela-botanica.org>
18
* @author Jennifer Dhé <jennifer.dhe@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 1.0
22
* @copyright 1999-${year} Tela Botanica (accueil@tela-botanica.org)
23
*/
24
 
25
class ZoneGeo extends Commun {
26
 
27
	protected $service = 'zone-geo';
28
 
29
	/**
30
	 * Permet de stocker la requete formulée : /zone-geo | /zone-geo/#id | /zone-geo/#id/champ | /zone-geo/#id/relations
31
	 * Est remplit au cours de l'analyse des ressources (traiterRessources()), par défaut, a la valeur du service.
32
	 * Est utilisée principalement pr déterminer le format du tableau à retourner.	 */
33
	protected $format_reponse = 'zone-geo';
34
 
35
	/** Variables constituant les parametres de la requete SQL (champ, condition, group by, limit) remplie
36
	 * selon ressources et paramètres	 */
37
	protected $requete_champ = ' * ';
38
	protected $requete_condition = '';
39
	protected $limite_requete 	 = array(
40
		'depart' => 0,
41
		'limite' => 100
42
	);
43
 
44
	/** Stockage des ressources et paramétres */
45
	protected $table_ressources = array();
46
	protected $table_param = array();
47
	/**
48
	 * Precise la contenance plus ou moins précise du tableau à retourner :
49
	 *  - min = les données présentes dans la table
50
	 *  - max = les données de la table + les informations complémentaires (pour les identifiants et les codes)
51
	 *  - oss = la liste des nom_sci (uniquement pour noms et taxons)
52
	 */
53
	protected $retour_format = 'max';
54
	/** Valeur du paramètre de requete recherche :
55
	 *  - stricte : le masque est passé tel quel à l'opérateur LIKE.
56
	 *  - etendue : ajout automatique du signe % à la place des espaces et en fin de masque avec utilisation de LIKE.
57
	 *  - floue : recherche tolérante vis-à-vis d'approximations ou d'erreurs (fautes d'orthographe par exemple) */
58
	protected $recherche;
59
 
60
	/** Permet de stocker le tableau de résultat (non encodé en json) */
61
	protected $table_retour = array();
62
	/** Stocke le nombre total de résultats de la requete principale. Est calculée lors de l'assemblage de la requete */
63
	protected $total_resultat;
64
 
65
// +-------------------------------------------------------------------------------------------------------------------+
66
	public function consulter($ressources, $parametres) {
67
		$this->traiterParametres($parametres);
68
		$this->traiterVersionProjet($ressources);
69
		$this->traiterRessources($ressources);
70
		$resultat_formate = '';
71
 
72
		if ($this->corps_http == '' && $this->entete_http == '') {
73
		foreach ($this->table_version as $version) {
74
				$this->table = $version; //on stocke le nom de la table correspondant à la version du projet en cours
75
				$requete = $this->assemblerLaRequete(); //print_r($requete);
76
				$resultat = $this->getBdd()->recupererTous($requete);
77
				$res_version = $this->testerResultat($resultat, $requete);
78
			}
79
			if ($this->corps_http == '' && $this->entete_http == '') {
80
				if (isset($res_version)) {
81
					$resultat_formate = json_encode($res_version);
82
				}
83
			}
84
		}
85
		return $this->formerReponseHTTP($resultat_formate);
86
	}
87
 
88
	public function testerResultat($resultat, $requete) {
89
		if ($resultat == '') { //cas ou la requete comporte des erreurs
90
			$s = 'La requête SQL formée comporte une erreur !!';
91
			Debug::printr($requete);
92
			$this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $s);
93
		} elseif ($resultat) {
94
			if (count($this->table_version) > 1) {
95
				$res_version[$version] = $this->retournerResultatFormate($resultat);
96
			} else {
97
				$res_version = $this->retournerResultatFormate($resultat);
98
			}
99
		} else {
100
			$d = 'Données recherchées introuvables dans la base';
101
			$this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $d);
102
			Debug::printr($requete);
103
		}
104
		return $res_version;
105
	}
106
 
107
// +-------------------------------------------------------------------------------------------------------------------+
108
	public function traiterParametres($parametres) {
109
		if (isset($parametres) && !empty($parametres)) {
110
			$this->table_param = $parametres;
111
 
112
		//	masque : filtre la liste en fonction d'un masque de recherche portant sur le code, le nom ou la region.
113
		//	masque.code : filtre uniquement sur le code. masque.nom : filtre uniquement sur le nom.
114
		//	masque.region : filtre uniquement sur la region.
115
			if (isset($parametres['recherche']) && $parametres['recherche'] != '') {
116
				$this->recherche = $parametres['recherche'];
117
			}
118
 
119
			foreach ($parametres as $param => $valeur) {
120
				switch ($param) {
121
					case 'masque'				: $this->ajouterLeFiltreMasque('masque', $valeur);				break;
122
					case 'masque_code'			: $this->ajouterLeFiltreMasque('codet', $valeur);				break;
123
					case 'masque_nom'			: $this->ajouterLeFiltreMasque('nom', $valeur);					break;
124
					case 'masque_statut'		: $this->ajouterLeFiltreMasque('codet_statut', $valeur);		break;
125
					case 'retour_format'		: $this->retour_format = $valeur;								break;
126
					case 'navigation_depart'	: $this->limite_requete['depart'] = $valeur;					break;
127
					case 'navigation_limite'	: $this->limite_requete['limite'] = $valeur;					break;
128
					case 'recherche'			:																break;
129
					default						:  $p = 'Erreur dans les paramètres de recherche de votre requête : '.
130
													'</br> Le paramètre " '.$param.' " n\'existe pas.';
131
												$this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $p);	break;
132
				}
133
			}
134
		}
135
	}
136
 
137
	public function ajouterLeFiltreMasque($nom_champ, $valeur) {
138
		if ($nom_champ == 'codet') {
139
			$this->requete_condition[] .= $nom_champ.' = '.$this->getBdd()->proteger($valeur);
140
		} else {
141
			if ($this->recherche == 'floue') {
142
				if ($nom_champ == 'masque') {
143
					$this->requete_condition[] = ' ( codet = '.$this->getBdd()->proteger($valeur)
144
						.' OR (SOUNDEX(nom_francais) = SOUNDEX(\''.$valeur.'\')'
145
						.' OR SOUNDEX(REVERSE(nom_francais)) = SOUNDEX(REVERSE(\''.$valeur.'\')) OR '
146
							.'SOUNDEX(nom_anglais) = SOUNDEX(\''.$valeur.'\')'
147
						.' OR SOUNDEX(REVERSE(nom_anglais)) = SOUNDEX(REVERSE(\''.$valeur.'\'))) '
148
						.' OR ( SOUNDEX(codet_statut) = SOUNDEX(\''.$valeur.'\')'
149
						.' OR SOUNDEX(REVERSE(codet_statut)) = SOUNDEX(REVERSE(\''.$valeur.'\')) '
150
						.')) ';
151
				} elseif ($nom_champ == 'nom') {
152
					$this->requete_condition[] = '(SOUNDEX(nom_francais) = SOUNDEX(\''.$valeur.'\')'
153
						.' OR SOUNDEX(REVERSE(nom_francais)) = SOUNDEX(REVERSE(\''.$valeur.'\'))) OR
154
						(SOUNDEX(nom_anglais) = SOUNDEX(\''.$valeur.'\')'
155
						.' OR SOUNDEX(REVERSE(nom_anglais)) = SOUNDEX(REVERSE(\''.$valeur.'\'))) ';
156
				} else {
157
					$this->requete_condition[] = '(SOUNDEX('.$nom_champ.') = SOUNDEX(\''.$valeur.'\')'
158
						.' OR SOUNDEX(REVERSE('.$nom_champ.')) = SOUNDEX(REVERSE(\''.$valeur.'\'))) ';
159
				}
160
			} else {
161
				if ($this->recherche == 'etendue') {
162
					$valeur = str_replace(' ','%', $valeur);
163
					$valeur .= '%';
164
				}
165
 
166
				if ($nom_champ == 'masque') {
167
					$this->requete_condition[] = '(codet = '.$this->getBdd()->proteger($valeur)
168
						.' OR nom_francais LIKE '.$this->getBdd()->proteger($valeur)
169
						.' OR nom_anglais LIKE '.$this->getBdd()->proteger($valeur)
170
						.' OR codet_statut LIKE '.$this->getBdd()->proteger($valeur).')';
171
				} elseif ($nom_champ == 'nom') {
172
					$this->requete_condition[] = '(nom_francais LIKE '.$this->getBdd()->proteger($valeur).' OR '
173
						.'nom_anglais LIKE '.$this->getBdd()->proteger($valeur).') ';
174
				} else {
175
					$this->requete_condition[] = $nom_champ.' LIKE '.$this->getBdd()->proteger($valeur);
176
				}
177
			}
178
		}
179
	}
180
 
181
// +-------------------------------------------------------------------------------------------------------------------+
182
	public function traiterRessources(&$ressources) {
183
		if (isset($ressources) && !empty($ressources)) {
184
			$this->table_ressources = $ressources;
185
			if (isset($this->table_ressources[0]) && !empty($this->table_ressources[0])) {
186
				//requete = /zone-geo/#id
187
				$this->traiterRessourceId();
188
				if (isset($this->table_ressources[1]) && !empty($this->table_ressources[1])) {
189
					//requete = /zone-geo/#id/#champ ou /zone-geo/#id/relations
190
					$this->traiterRessourceChampOuRelations();
191
				}
192
			}
193
		}
194
	}
195
 
196
	public function traiterRessourceId() {
197
		//requete : /zone-geo/#id (ex : /zone-geo/7)
198
		if ($this->table_ressources[0]) {
199
			$this->requete_condition[] = ' codet = '.$this->getBdd()->proteger($this->table_ressources[0]);
200
			$this->format_reponse .= '/id';
201
		} else {
202
			$r = 'Erreur dans les ressources de votre requête : </br> La ressource " '.$this->table_ressources[0].
203
				' " n\'existe pas.';
204
			$this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $r);
205
		}
206
	}
207
 
208
 
209
	public function traiterRessourceChampOuRelations() {
210
		if ($this->table_ressources[1] == 'relations') {
211
			$r = 'Erreur dans les ressources de votre requête : </br> La ressource " '.$this->table_ressources[1].
212
				' " n\'existe pas.';
213
			$this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $r);
214
		} else {
215
			$this->format_reponse .= '/champ';
216
		}
217
	}
218
 
219
// +-------------------------------------------------------------------------------------------------------------------+
220
	public function assemblerLaRequete() {
221
		//assemblage de la requete :
222
		$requete = 	' SELECT '.$this->requete_champ.
223
			' FROM '.$this->table
224
			.$this->formerRequeteCondition()
225
			.$this->formerRequeteLimite();
226
		return $requete;
227
	}
228
 
229
	//ajout d'une limite seulement pour les listes (pas plus de 100 resultats retournés pr les requetes
230
	// suivantes : /zone-geo et /zone-geo/#id/relations)
231
	public function formerRequeteLimite() {
232
		if ($this->format_reponse != 'zone-geo') {
233
			$this->requete_limite = '';
234
		} elseif (($depart = $this->limite_requete['depart']) > ($this->total_resultat = $this->recupererTotalResultat())) {
235
			//cas ou la requete presente un navigation.depart supérieur au nb total de resultats.
236
			$this->limite_requete['depart'] =
237
				(($nb - $this->limite_requete['limite']) < 0) ? 0 : ($nb - $this->limite_requete['limite']);
238
			$this->requete_limite = ' LIMIT '.$this->limite_requete['depart'].', '.$this->limite_requete['limite'];
239
		} else {
240
			$this->requete_limite = ' LIMIT '.$this->limite_requete['depart'].', '.$this->limite_requete['limite'];
241
		}
242
		return $this->requete_limite;
243
	}
244
 
245
	public  function formerRequeteCondition() {
246
		$condition = '';
247
		if ($this->requete_condition != null) {
248
			$condition = ' WHERE '.implode(' AND ', $this->requete_condition);
249
		}
250
		return $condition;
251
	}
252
 
253
	public function recupererTotalResultat() {
254
		//on récupère le nombre total de résultats de la requete (ex : le nombre d'id contenu dans la liste /zone-geo)
255
		$requete = 'SELECT count(*) as nombre FROM '
256
			.$this->table
257
			.$this->formerRequeteCondition();
258
		$res = $this->getBdd()->recuperer($requete);
259
 
260
		if ($res) {
261
			$total = $res['nombre'];
262
		} else {
263
			$t = 'Fonction recupererTotalResultat() : <br/>Données introuvables dans la base';
264
			$this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $t);
265
		}
266
		return $total;
267
	}
268
 
269
// +-------------------------------------------------------------------------------------------------------------------+
270
	// determine en fct du service appelé (/zone-geo | /zone-geo/#id | /zone-geo/#id/champ |
271
	// /zone-geo/#id/relations) le format du tableau à retourner. Encode en json
272
	public function retournerResultatFormate($resultat) {
273
		$this->recupererTableConfig('correspondance_champs');
274
		switch ($this->format_reponse) {
275
			case 'zone-geo'				: $reponse = $this->formaterZoneGeo($resultat);				break;
276
			case 'zone-geo/id'			: $reponse = $this->formaterZoneGeoId($resultat[0]);		break;
277
			case 'zone-geo/id/champ'	: $reponse = $this->formaterZoneGeoIdChamp($resultat[0]);	break;
278
			default						:															break;
279
		}
280
		return $reponse;
281
	}
282
 
283
	public function formaterZoneGeo($resultat) {
284
		//on remplit la table $table_retour_json['entete']
285
		$this->table_retour['depart'] = $this->limite_requete['depart'];
286
		$this->table_retour['limite'] = $this->limite_requete['limite'];
287
		$this->table_retour['total']  = $this->total_resultat;
288
		$url = $this->formulerUrl($this->total_resultat, '/zone-geo');
289
		if ($url['precedent'] != '')	{ $this->table_retour['href.precedent'] = $url['precedent'];	}
290
		if ($url['suivant'] != '')		{ $this->table_retour['href.suivant'] = $url['suivant'];		}
291
		$table_retour_json['entete'] = $this->table_retour;
292
 
293
		//on remplit la table $table_retour_json['resultat']
294
		$this->table_retour = array();
295
		if (isset($this->table_param['masque_nom'])) $resultat = $this->trierRechercheFloue($this->table_param['masque_nom'], $resultat, 'nom_francais');
296
		foreach ($resultat as $tab) {
297
			foreach ($tab as $key => $valeur) {
298
				$valeur = rtrim($valeur);
299
				if ($valeur != '') {
300
					switch ($key) {
301
						case 'codet'		: $num = $valeur; $this->table_retour['code'] = $valeur;				break;
302
						case 'nom_francais' : $this->table_retour['nom'] = $valeur;									break;
303
						case 'nom_anglais'	: if ($tab['nom_francais'] == '') $this->table_retour['nom'] = $valeur;	break;
304
						case 'codet_statut' : $this->table_retour['statut'] = $valeur;								break;
305
						default				:																		break;
306
					}
307
				}
308
			}
309
			if ($this->retour_format == 'max') {
310
				$this->table_retour['href'] = $this->ajouterHref('zone-geo', $num);
311
			}
312
			$resultat_json[$num] = $this->table_retour;
313
			$this->table_retour = array();
314
		}
315
		$table_retour_json['resultat'] = $resultat_json;
316
		return $table_retour_json;
317
	}
318
 
319
	public function formaterZoneGeoId($resultat) {
320
		foreach ($resultat as $key => $valeur) {
321
			if ($valeur != '') {
322
				$this->afficherDonnees($key, $valeur);
323
			}
324
		}
325
		unset($this->table_retour['href']);
326
		return $this->table_retour;
327
	}
328
 
329
	public function formaterZoneGeoIdChamp($resultat) {
330
		//on recupère tous les resultats possibles
331
		$reponse = $this->formaterZoneGeoId($resultat);
332
		$this->table_retour = array();
333
		//on recupère les résultats demandés à partir du tableau de résultat complet
334
		$this->table_retour['id'] = $reponse['code'];
335
 
336
		$champs = explode(' ', $this->table_ressources[1]);
337
		foreach ($champs as $champ) {
338
			if ($champ == 'nom') $champ = 'nom.fr';
339
			if ($this->verifierValiditeChamp($champ)) {
340
				if (strrpos($champ, '.*') !== false) {
341
					$this->afficherPointEtoile($champ, $reponse);
342
				} else {
343
					if (isset($reponse[$champ])) {
344
						$this->table_retour[$champ] = $reponse[$champ];
345
					} else {
346
						$this->table_retour[$champ] = null;
347
					}
348
				}
349
			}
350
		}
351
		return $this->table_retour;
352
	}
353
 
354
	public function verifierValiditeChamp($champ) {
355
		preg_match('/^([^.]+)(\.([^.]+))?$/', $champ, $match);
356
		$champs_possibles = $this->correspondance_champs;
357
		$champs_possibles[] = 'nom.*';
358
 
359
		if (in_array($match[1], $champs_possibles)) {
360
			$validite = true;
361
		} elseif (in_array($match[0], $champs_possibles)) {
362
			$validite = true;
363
		} else {
364
			$champs_possibles = implode('</li><li>', $champs_possibles);
365
			$c = 'Erreur dans votre requête : </br> Le champ "'.$champ_possibles.'" n\'existe pas. '.
366
				'Les champs disponibles sont : <li>'.$champs_possibles.'</li>';
367
			$this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $c);
368
		}
369
		return $validite;
370
	}
371
 
372
	public function afficherPointEtoile($champ, $reponse) {
373
		preg_match('/^([^.]+\.)\*$/', $champ, $match);
374
		foreach ($reponse as $chp => $valeur) {
375
			if (strrpos($chp, $match[1]) !== false) {
376
				if ($valeur != '') {
377
					$this->table_retour[$chp] = $valeur;
378
				} else {
379
					$this->table_retour[$chp] = null;
380
				}
381
			}
382
		}
383
	}
384
 
385
	public function afficherDonnees($champ, $valeur) {
386
		if ($this->retour_format == 'max') {
387
			if ($champ == 'codet_statut') {
388
				$this->table_retour[$this->correspondance_champs[$champ]] = $valeur;
389
				$this->table_retour[$this->correspondance_champs[$champ].'.href'] =
390
					$this->ajouterHref('ontologies', 'masque.nom=Codet '.$valeur, '?');
391
			} else {
392
				$this->table_retour[$this->correspondance_champs[$champ]] = $valeur;
393
			}
394
		} else {
395
			$this->table_retour[$this->correspondance_champs[$champ]] = $valeur;
396
		}
397
	}
398
 
399
// +-------------------------------------------------------------------------------------------------------------------+
400
	/** Permet de retourner l'url http://tela-botanica.org/service:eflore:0.1/[projet]/[version_projet]/[service]/[ressource]:[valeur]
401
	 * @param $service : correspond au nom de la ressource à laquelle on souhaite acceder
402
	 * @param $val : correspond au paramètre de la ressource (ex :
403
	 * @param $projet : est remplit dans les cas suivants :
404
	 * 	- si le projet dans lequel se trouve l'information est différent de celui du service appelé
405
	 *  - si on souhaite rappeler le meme projet avec la meme ressource mais un parametre de ressource différent
406
	 */
407
	public function ajouterHref($service, $val, $separation = '/') {
408
		$val = $this->encoderUrl($val);
409
		if ($this->version_projet == '+') {
410
			$url = Config::get('url_service_base').Config::get('nom_projet').'/'.$service.$separation.$val;
411
		} else {
412
			$url = Config::get('url_service_base').Config::get('nom_projet').'/'.$this->version_projet.'/'.$service.$separation.$val;
413
		}
414
		return $url;
415
	}
416
 
417
	public function encoderUrl($url) {
418
		$url = str_replace(' ', '%20', $url);
419
		$url = str_replace('?', urlencode('?'), $url);
420
		return $url;
421
	}
422
}
423
?>