Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

Rev Author Line No. Line
237 jpm 1
<?php
2
// declare(encoding='UTF-8');
3
/**
4
* Classe implémentant l'API d'eFlore Cartes pour le projet CHORODEP.
5
*
6
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=EfloreApi01Cartes
7
*
8
* @package eFlore/services
9
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
10
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
11
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
12
* @version 1.0
13
* @copyright 1999-2012 Tela Botanica (accueil@tela-botanica.org)
14
*/
15
// TODO : Config et Outils sont des classes statiques qui doivent poser des pb pour les tests...
16
class Cartes {
17
 
18
	private $parametres = array();
19
	private $ressources = array();
20
	private $Bdd;
21
 
22
	const CODE_REFTAX_DEFAUT = 'bdtfx';
23
	const TYPE_ID_DEFAUT = 'nn';
24
	const CARTE_DEFAUT = 'france_02';
25
	const FORMAT_DEFAUT = '550';
26
	const MIME_SVG = 'image/svg+xml';
27
	const MIME_PNG = 'image/png';
28
 
29
	private $config = array();
30
	private $cheminCartesBase = '';
31
	private $formats_supportes = array(self::MIME_SVG, self::MIME_PNG);
32
	private $UrlNavigation = null;
33
	private $taxonsDemandes = array();
34
	private $imgLargeur = 0;
35
	private $imgHauteur = 0;
248 jpm 36
	private $legende = array();
37
	private $donnees = array();
237 jpm 38
 
39
	public function __construct(Bdd $bdd = null, Array $config = null, CacheSimple $cache = null) {
40
		$this->Bdd = is_null($bdd) ? new Bdd() : $bdd;
41
		$this->config = is_null($config) ? Config::get('Cartes') : $config;
248 jpm 42
 
43
		$this->chargerLegende();
44
 
237 jpm 45
		$this->cheminCartesBase = $this->config['chemin'];
248 jpm 46
 
237 jpm 47
		$cacheOptions = array('mise_en_cache' => $this->config['cache']['miseEnCache'],
48
			'stockage_chemin' => $this->config['cache']['stockageChemin'],
49
			'duree_de_vie' => $this->config['cache']['dureeDeVie']);
50
		//die(print_r($this->config, true));
51
		$this->cache = is_null($cache) ? new CacheSimple($cacheOptions) : $cache;
52
	}
53
 
248 jpm 54
	private function chargerLegende() {
55
		$requete = 'SELECT * '.
56
				'FROM chorodep_ontologies '.
57
				"WHERE classe_id = 1 ";
58
		$resultats = $this->Bdd->recupererTous($requete);
59
 
60
		if (!is_array($resultats) || count($resultats) <= 0) {
61
			$message = "La légende n'a pu être chargée pour la ressource demandée";
62
			$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
63
			throw new Exception($message, $code);
64
		}
65
 
66
		foreach ($resultats as $ontologie) {
67
			$ontologie = $this->extraireComplementsOntologies($ontologie);
68
			$this->legende[$ontologie['code']] = $ontologie['legende'];
69
		}
70
	}
71
 
72
	private function extraireComplementsOntologies($ontologie) {
73
		$complements = explode(',', trim($ontologie['complements']));
74
		foreach ($complements as $complement) {
75
			list($cle, $val) = explode('=', trim($complement));
76
			$ontologie[trim($cle)] = trim($val);
77
		}
78
		return $ontologie;
79
	}
80
 
237 jpm 81
	public function consulter($ressources, $parametres) {
82
		//$tpsDebut = microtime(true);
83
		$this->parametres = $parametres;
84
		$this->ressources = $ressources;
85
 
86
		$this->definirValeurParDefautDesParametres();
87
		$this->verifierParametres();
88
		$this->analyserIdentifiant();
89
 
90
		$resultat = new ResultatService();
248 jpm 91
		$this->chargerDonnees();
237 jpm 92
		if ($this->parametres['retour'] == self::MIME_SVG) {
93
			$svg = $this->genererSVG();
94
			$resultat->corps = $svg;
95
		} else if ($this->parametres['retour'] == self::MIME_PNG) {
96
			$svg = $this->genererSVG();
97
			$png = $this->convertirEnPNG($svg);
98
			$resultat->corps = $png;
99
		}
100
		$resultat->mime = $this->parametres['retour'];
101
 
102
		return $resultat;
103
	}
104
 
105
	private function definirValeurParDefautDesParametres() {
106
		if (isset($this->parametres['retour']) == false) {
107
			$this->parametres['retour'] = self::MIME_SVG;
108
		}
109
		if (isset($this->parametres['retour.format']) == false) {
110
			$this->parametres['retour.format'] = self::FORMAT_DEFAUT;
111
		}
112
	}
113
 
114
	private function verifierParametres() {
115
		$erreurs = array();
116
 
117
		if ($this->verifierIdentifiants() == false) {
118
			$erreurs[] = "L'identifiant de ressource indiqué ne respecte pas le format attendu.";
119
		}
120
		if (isset($this->parametres['retour']) == false) {
121
			$erreurs[] = "Le paramètre type de retour 'retour' est obligatoire.";
122
		}
123
		if ($this->verifierValeurParametreRetour() == false) {
124
			$erreurs[] = "Le type de retour '{$this->parametres['retour']}' n'est pas supporté.";
125
		}
126
		if (isset($this->parametres['retour.format']) == false) {
127
			$erreurs[] = "Le paramètre de format de retour 'retour.format' est obligatoire.";
128
		}
129
		if ($this->verifierValeurParametreFormat() == false) {
130
			$erreurs[] = "Le type de format '{$this->parametres['retour.format']}' n'est pas supporté.".
131
				"Veuillez indiquer un nombre entier correspondant à la largeur désirée pour la carte.";
132
		}
133
 
134
		if (count($erreurs) > 0) {
135
			$message = implode('<br />', $erreurs);
136
			$code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
137
			throw new Exception($message, $code);
138
		}
139
	}
140
 
141
	private function verifierIdentifiants() {
142
		$ok = true;
143
		if (isset($this->ressources[0])) {
144
			$ids = $this->ressources[0];
145
			$projetPattern = '(?:(?:[A-Z0-9]+(\.(?:nn|nt)?):)?(?:[0-9]+,)*[0-9]+)';
146
			$patternComplet = "/^$projetPattern(?:;$projetPattern)*$/i";
147
			$ok = preg_match($patternComplet, $ids) ? true : false;
148
		}
149
		return $ok;
150
	}
151
 
152
	private function verifierValeurParametreRetour() {
153
		return in_array($this->parametres['retour'], $this->formats_supportes);
154
	}
155
 
156
	private function verifierValeurParametreFormat() {
157
		if ($ok = preg_match('/^([0-9]+)$/', $this->parametres['retour.format'], $match)) {
158
			$this->imgLargeur = $match[1];
159
		} else if ($ok = preg_match('/^([0-9]+)x([0-9]+)$/', $this->parametres['retour.format'], $match)) {
160
			$this->imgLargeur = $match[1];
161
			$this->imgHauteur = $match[2];
162
		}
163
		return $ok;
164
	}
165
 
166
	private function analyserIdentifiant() {
167
		if (isset($this->ressources[0])) {
168
			$ids = $this->ressources[0];
169
			if (preg_match('/^[0-9]+$/', $ids)) {
170
				$this->taxonsDemandes[self::CODE_REFTAX_DEFAUT]['nn'][] = $ids;
171
			} else {
172
				// ceci contient potentiellement des formes ref_tax1.nn:1,2;ref_tax2.nt:3,4
173
				throw new Exception("A implémenter : ressource id multiples");
174
				$projetsListeEtNumNoms = explode(';', $nn);
175
				if (count($projetsListeEtNumNoms) > 0) {
176
					foreach ($projetsListeEtNumNoms as $projetEtNumNoms) {
177
						$projetEtNumNoms = (strpos($projetEtNumNoms, ':')) ? $projetEtNumNoms : self::CODE_REFTAX_DEFAUT.':'.$projetEtNumNoms;
178
						list($projet, $numNoms) = explode(':', $projetEtNumNoms);
179
						$this->ref_tax_demande[$projet] = explode(',', $numNoms);
180
					}
181
				}
182
			}
183
		} else {
184
			throw new Exception("A implémenter : carte proportionnelle ensemble des infos");
185
		}
186
	}
187
 
248 jpm 188
	private function chargerDonnees() {
189
		$refTax = self::CODE_REFTAX_DEFAUT;
190
		$numNom = $this->Bdd->proteger($this->taxonsDemandes[$refTax]['nn'][0]);
237 jpm 191
 
248 jpm 192
		$requete = 'SELECT * '.
193
				'FROM chorodep_v2012_01 '.
194
				"WHERE num_nom IN ($numNom) ";
195
		$resultat = $this->Bdd->recupererTous($requete);
237 jpm 196
 
248 jpm 197
		if (!is_array($resultat) || count($resultat) <= 0) {
198
			$message = "Aucune donnée ne correspond à la ressource demandée";
199
			$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
200
			throw new Exception($message, $code);
201
		}
202
		$this->donnees = $resultat;
203
	}
237 jpm 204
 
248 jpm 205
	private function genererSVG() {
237 jpm 206
		$dom = new DOMDocument('1.0', 'UTF-8');
248 jpm 207
		$dom->validateOnParse = true;
208
 
209
		$fichierCarteSvg = $this->cheminCartesBase.self::CARTE_DEFAUT.'.svg';
237 jpm 210
		$dom->load($fichierCarteSvg);
248 jpm 211
 
237 jpm 212
		$racineElement = $dom->documentElement;
213
		$racineElement->setAttribute('width', $this->imgLargeur);
248 jpm 214
 
215
		$css = $this->creerCssCarte();
216
		$txtCss = $dom->createCDATASection($css);
217
		$dom->getElementsByTagName('style')->item(0)->appendChild($txtCss);
218
 
219
		$titre = $this->creerTitre();
220
		$titreCdata = $dom->createCDATASection($titre);
221
		$titreElement = $dom->getElementsByTagName('title')->item(0);
222
		$titreElement->nodeValue = '';
223
		$titreElement->appendChild($titreCdata);
224
 
225
		$taxonTitre = $this->creerTitreTaxon();
226
		$taxonCdata = $dom->createCDATASection($taxonTitre);
227
		$xpath = new DOMXPath($dom);
228
		$taxonTitreEl = $xpath->query("//*[@id='titre-taxon']")->item(0);
229
		$taxonTitreEl->nodeValue = '';
230
		$taxonTitreEl->appendChild($taxonCdata);
231
 
237 jpm 232
		$svg = $dom->saveXML();
233
		return $svg;
234
	}
235
 
248 jpm 236
	private function creerCssCarte() {
237
		$fichierCssBase = $this->cheminCartesBase.self::CARTE_DEFAUT.'.css';
238
		$css = file_get_contents($fichierCssBase);
237 jpm 239
 
248 jpm 240
		$zonesCouleurs = $this->getZonesCouleurs();
241
		foreach ($zonesCouleurs as $couleur => $zonesClasses) {
242
			$classes = implode(', ', $zonesClasses);
243
			$css .= "$classes{\nfill:$couleur;\n}\n";
244
		}
245
		return $css;
246
	}
237 jpm 247
 
248 jpm 248
	private function getZonesCouleurs() {
249
		$zones = array();
250
		foreach ($this->donnees as $donnee) {
251
			foreach ($donnee as $champ => $valeur) {
252
				if (preg_match('/^[0-9][0-9ab]$/i', $champ)) {
253
					if (array_key_exists($valeur, $this->legende)) {
254
						$couleur = $this->legende[$valeur];
255
						$zones[$couleur][] = strtolower(".departement$champ");
256
					}
257
				}
258
			}
237 jpm 259
		}
248 jpm 260
		return $zones;
261
	}
237 jpm 262
 
248 jpm 263
	private function creerTitre() {
264
		$titre = "Carte en cours d'élaboration pour ".$this->creerTitreTaxon();
265
		return $titre;
237 jpm 266
	}
267
 
248 jpm 268
	private function creerTitreTaxon() {
269
		$noms = array();
270
		foreach ($this->donnees as $donnee) {
271
			$noms[] = $donnee['nom_sci'];
272
		}
273
		$titre = implode(', ', $noms);
274
		return $titre;
237 jpm 275
	}
276
 
277
	private function convertirEnPNG($svg) {
278
		$png = null;
279
		if (extension_loaded('imagick')) {
280
			$png = $this->convertirEnPNGAvecImageMagick($svg);
281
		} else {
282
			$message = "Impossible de générer l'image sur le serveur. Extenssion ImageMagick abscente.";
283
			$code = RestServeur::HTTP_CODE_ERREUR;
284
			throw new Exception($message, $code);
285
		}
286
		return $svg;
287
	}
288
 
289
	private function convertirEnPNGAvecImageMagick($svg) {
290
		$convertisseur = new Imagick();
291
		$convertisseur->readImageBlob($svg);
292
		$convertisseur->setImageFormat("png24");
293
		$convertisseur->resizeImage($this->imgLargeur, $this->imgHauteur, imagick::FILTER_LANCZOS, 0);
294
		$png = $convertisseur->getImageBlob();
295
		$convertisseur->clear();
296
		$convertisseur->destroy();
297
		return $png;
298
	}
248 jpm 299
 
300
	public function getParametreTableau($cle) {
301
		$tableau = array();
302
		$parametre = $this->config[$cle];
303
		if (empty($parametre) === false) {
304
			$tableauPartiel = explode(',', $parametre);
305
			$tableauPartiel = array_map('trim', $tableauPartiel);
306
			foreach ($tableauPartiel as $champ) {
307
				if (strpos($champ, '=') === false) {
308
					$tableau[] = trim($champ);
309
				} else {
310
					list($cle, $val) = explode('=', $champ);
311
					$tableau[trim($cle)] = trim($val);
312
				}
313
			}
314
		}
315
		return $tableau;
316
	}
237 jpm 317
}
318
?>