Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 1072 | Rev 1143 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1056 jpm 1
<?php
2
// declare(encoding='UTF-8');
3
/**
4
 * Classe permettant d'obtenir le nom et les codes d'une zone administrative à partir de ces coordonnées (latitude et longitude).
5
 * La latitude et longitude doivent être exprimée par un nombre décimal.
6
 * Ce service fonctionne uniquement pour les zones administratives dont les contours ont été tracés dans OpenStreetMap.
7
 * Source des données : OpenStreetMap <http://wiki.openstreetmap.org>
8
 * Tag:boundary=administrative : <http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative>
9
 * Paramètres du service :
10
 *  - lat : latitude
11
 *  - lon : longitude
12
 * Exemple :
13
 * http://localhost/service-test:eflore:0.1/osm/nom-commune?lon=3.83619&lat=44.74231
14
 *
15
 * @category	php 5.2
16
 * @package		eFlore
17
 * @subpackage	Services
18
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
19
 * @author		Mohcen BENMOUNAH <mohcen@tela-botanica.org>
20
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
21
 * @license		CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt>
22
 * @license		GNU-GPL <http://www.gnu.org/licenses/gpl.html>
23
 */
24
class ZoneADmin {
25
 
1141 aurelien 26
	const PATTERN_LAT = '/^[-]?[0-9]+(?:[.][0-9]+|)$/';
1056 jpm 27
	const PATTERN_LON = '/^[-]?[0-9]+(?:[.][0-9]+|)$/';
28
	const MIME_JSON = 'application/json';
29
 
30
	private $parametres = array();
31
	private $bdd = null;
32
 
33
	private $lat = null;
34
	private $lon = null;
1072 jpm 35
	private $zone = null;
1141 aurelien 36
	private $niveaux = null;
1056 jpm 37
 
38
	public function __construct(Bdd $bdd) {
39
		$this->bdd = $bdd;
40
	}
41
 
42
	public function consulter($ressources, $parametres) {
43
		$this->parametres = $parametres;
44
		$this->verifierParametres();
45
		$this->lat = $this->parametres['lat'];
46
		$this->lon = $this->parametres['lon'];
1072 jpm 47
		$this->zone = isset($this->parametres['zone']) ? $this->parametres['zone'] : null;
1141 aurelien 48
		$this->niveaux = isset($this->parametres['niveau']) ? explode(',', $this->parametres['niveau']) : null;
1056 jpm 49
 
50
		$zoneTrouveeInfos = $this->localiserPointLatLon();
51
		$corps = $this->formaterResultats($zoneTrouveeInfos);
52
 
53
		$resultat = new ResultatService();
54
		$resultat->mime = self::MIME_JSON;
55
		$resultat->corps = $corps;
56
		return $resultat;
57
	}
58
 
59
	private function verifierParametres() {
60
		extract($this->parametres);
61
		$messages = array();
62
		if (! array_key_exists('lat', $this->parametres)) {
63
			$messages[] = "Vous devez indiquer une latitude en degré décimal à l'aide du paramètres d'url : lat";
64
		} else if (!preg_match(self::PATTERN_LAT, $lat)) {
1141 aurelien 65
			$messages[] = "La valeur de latitude doit être un nombre décimal dont le séparateur décimal est un point. Ex. : 44 ou 43.03";
1056 jpm 66
		}
67
		if (! array_key_exists('lon', $this->parametres)) {
68
			$messages[] = "Vous devez indiquer une longitude en degré décimal à l'aide du paramètres d'url : lon";
69
		} else if (!preg_match(self::PATTERN_LON, $lon)) {
70
			$messages[] = "La valeur de longitude doit être un nombre décimal dont le séparateur décimal est un point. Ex. : -4.03 ou 3.256";
71
		}
72
		if (count($messages) != 0) {
73
			$message = implode('<br />', $messages);
74
			$code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
75
			throw new Exception($message, $code);
76
		}
77
	}
78
 
79
	private function formaterResultats($zonesTrouveesInfos) {
80
		$retour = array();
81
		foreach ($zonesTrouveesInfos as $infos) {
82
			$donnees = array();
83
			foreach ($infos as $champ => $valeur) {
84
				if ($valeur != '' && $champ != 'niveau') {
85
					if ($champ == 'wikipedia') {
86
						$valeur = $this->formaterUrlWikipedia($valeur);
87
					}
88
					$donnees[$champ] = $valeur;
89
				}
90
			}
91
			$retour[$infos['niveau']] = $donnees;
92
		}
93
		ksort($retour);
94
		return $retour;
95
	}
96
 
97
	private function localiserPointLatLon() {
98
		$osmIdsInClause = $this->getOsmIdsDesCentresAProximites();
1072 jpm 99
		$zone = isset($this->zone) ? $this->bdd->proteger($this->zone) : null;
1056 jpm 100
 
101
		$requete = 'SELECT id_zone_geo AS codeZoneGeo, intitule, code_iso_3166_1 AS codeIso31661, '.
102
			'code_iso_3166_2 AS codeIso31662, code_insee AS codeInsee, code_nuts as codeNuts, '.
103
			'nom_en AS nomEn, nom_es AS nomEs, wikipedia, niveau '.
104
			'FROM osm_zones_admin '.
105
			"WHERE st_within(GEOMFROMTEXT('POINT($this->lon $this->lat)'), polygone) = 1 ".
1072 jpm 106
			(isset($zone) ? "AND zone = $zone " : '').
1056 jpm 107
			"AND osm_id IN ($osmIdsInClause) ".
108
			' -- '.__FILE__.' : '.__LINE__;
109
		$resultat = $this->bdd->recupererTous($requete);
110
		if ($resultat === false) {
111
			$msgTpl = "Service '%s' : aucune zone correspondant aux coordonnées : %s, %s.";
112
			$msg = sprintf($msgTpl, get_class($this), $this->lat, $this->lon);
113
			throw new Exception($msg, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
114
		}
115
		return $resultat;
116
	}
117
 
118
	private function getOsmIdsDesCentresAProximites() {
119
		$requete = $this->construireRequeteUnion();
120
		$resultats = $this->bdd->recupererTous($requete);
121
		if ($resultats === false) {
122
			$msgTpl = "Service '%s' : aucun centroïde correspondant aux coordonnées : %s, %s.";
123
			$msg = sprintf($msgTpl, get_class($this), $this->lat, $this->lon);
124
			throw new Exception($msg, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
125
		}
126
		$osmIds = array();
127
		foreach ($resultats as $info) {
128
			$osmIds[] = $info['osm_id'];
129
		}
130
		$osmIdsInClause = implode(',', $this->bdd->proteger($osmIds));
131
		return $osmIdsInClause;
132
	}
133
 
134
	private function construireRequeteUnion() {
1072 jpm 135
		$zone = isset($this->zone) ? $this->bdd->proteger($this->zone) : null;
1141 aurelien 136
		$niveaux = isset($this->niveaux) ? $this->niveaux : null;
137
 
1056 jpm 138
		$requeteTpl = 'SELECT osm_id, '.
1065 jpm 139
			"(($this->lon - centre_lng) * ($this->lon -centre_lng) + ($this->lat - centre_lat) * ($this->lat - centre_lat)) AS distance ".
1056 jpm 140
			'FROM osm_zones_admin '.
141
			'WHERE niveau = %s '.
1072 jpm 142
			(isset($zone) ? "AND zone = $zone " : '').
1056 jpm 143
			'ORDER BY distance ASC '.
144
			"LIMIT %s ";
1141 aurelien 145
		$niveaux = isset($niveaux) ? $niveaux : array(2,3,4,5,6,7,8);
1056 jpm 146
		$requetesAUnir = array();
147
		foreach ($niveaux as $niveau) {
1141 aurelien 148
			$requetesAUnir[] = sprintf($requeteTpl, $this->bdd->proteger($niveau), ($niveau * 2));
1056 jpm 149
		}
150
		$requete = '('.implode(') UNION (', $requetesAUnir).') -- '.__FILE__.' : '.__LINE__;
151
		return $requete;
152
	}
153
 
154
	private function formaterUrlWikipedia($infoWikipedia) {
155
		list($lang, $page) = explode(':', $infoWikipedia);
156
		$pageEncode = rawurlencode($page);
157
		$urlTpl = 'https://%s.wikipedia.org/wiki/%s';
158
		return sprintf($urlTpl, $lang, $pageEncode);
159
	}
160
}