Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 1064 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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