Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

Rev Author Line No. Line
1110 aurelien 1
<?php
2
// declare(encoding='UTF-8');
3
/**
4
* Gère le sous-service Taxons de Cartes.
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 FranceCartes {
17
 
18
	private $parametres = array();
19
	private $ressources = array();
20
 
21
	protected $largeurOrig = 600;
22
	protected $longeurOrig = 545;
23
 
24
	protected $largeurDefaut = 600;
25
	protected $largeurDemandee = 600;
26
 
27
	protected $prefixe_id_zone = 'INSEE-D';
28
 
29
	protected $options_cache = array();
30
 
31
	const PRESENCE_CHOROLOGIE = '1';
32
 
33
	public function __construct(Conteneur $conteneur) {
34
		$this->Bdd = $conteneur->getBdd();
35
		$this->tableOntologie = $conteneur->getParametre('bdd_table_ontologies');
36
		$this->config = $conteneur->getParametre('Cartes');
37
		$this->convertisseur = $this->config['convertisseur'];
38
		$this->tableMeta = $conteneur->getParametre('bdd_table_meta');
39
		$this->cheminCartesBase = $this->config['chemin'];
40
 
41
		$this->options_cache = array('mise_en_cache' => $this->config['cache_miseEnCache'],
42
				'stockage_chemin' => $this->config['cache_stockageChemin'],
43
				'duree_de_vie' => $this->config['cache_dureeDeVie']);
44
	}
45
 
46
	public function consulter($ressources, $parametres) {
47
		$this->parametres = $parametres;
48
		$this->ressources = $ressources;
49
 
50
		$this->chargerMetadonnees();
51
		$this->definirVersion();
52
		$this->tableChorodep = 'chorodep_v'.str_replace('.', '_', $this->version);
53
 
54
		if(isset($parametres['retour.format']) && is_numeric($parametres['retour.format'])) {
55
			$this->largeurDemandee = intval($parametres['retour.format']);
56
		}
57
 
58
		if(count($ressources) == 0) {
59
			$resultat = $this->getCarteTaxonsParZones();
60
		} else if($ressources[0] == "legende") {
61
			$cache = $this->getCache('global');
62
			if($cache != null) {
63
				$max = $cache['nb_taxons_max'];
64
			} else {
65
				$max = $this->getNbMaxTaxonsParZones();
66
			}
67
			$resultat = $this->getLegendeCarteTaxonsParZones($max);
68
		}
69
 
70
		return $resultat;
71
	}
72
 
73
	private function chargerMetadonnees() {
74
		$requete = 'SELECT * '.
75
				"FROM {$this->tableMeta} ".
76
				"ORDER BY date_creation DESC ";
77
		$resultats = $this->Bdd->recupererTous($requete);
78
 
79
		if (!is_array($resultats) || count($resultats) <= 0) {
80
			$message = "Les méta-données n'ont pu être chargée pour la ressource demandée";
81
			$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
82
			throw new Exception($message, $code);
83
		}
84
 
85
		$this->metadonnees = $resultats;
86
	}
87
 
88
	private function definirVersion() {
89
		$this->version = $this->metadonnees[0]['version'];
90
	}
91
 
92
	public function getLegendeCarteTaxonsParZones($nb_max) {
93
		// TODO : mettre en config ou en ontologie ?
94
		// mais ça fait encore un appel de plus aux ontologies
95
		// qui sont déjà bien bien bien bien chargées
96
		$this->couleurs_legende_globale = array("#808080", "#EFF8E1", "#F2E2C0", "#C9CC8D", "#C1E587", "#A0FF7D");
97
		$couleurs = $this->couleurs_legende_globale;
98
		$legende = array(
99
				"seuil0" => array(
100
					"code" => "",
101
					"couleur" => $couleurs[0],
102
					"css" => "",
103
					"nom" => "Non renseignée",
104
					"description" => "Zone géographique non renseignée."
105
				)
106
		);
107
		array_shift($couleurs);
108
		$borne_min = 0;
109
		$borne_max = 500;
110
 
111
		for($i = 1; $i <= 5; $i++) {
112
			$borne_max = ($i == 5) ? $nb_max : $borne_max;
113
			$legende["seuil".$i] = array(
114
					"code" => "",
115
					"couleur" => $couleurs[$i-1],
116
					"css" => "",
117
					"nom" => "de ".$borne_min." à ".$borne_max." taxons",
118
					"description" => "de ".$borne_min." à ".$borne_max." taxons."
119
				);
120
			$borne_min = $borne_max + 1;
121
			$borne_max = ($i == 5) ? $nb_max : ($i * 1200);
122
		}
123
 
124
		return $legende;
125
	}
126
 
127
	private function convertirLegendeVersCss($legende) {
128
		$css = "";
129
		foreach($legende as $cle => $item) {
130
			if($item['css'] != '') {
131
				$css .=
132
				$item['css']." {"."\n".
133
				"	fill:".$item['couleur'].";"."\n".
134
				"}"."\n\n";
135
			}
136
		}
137
 
138
		return $css;
139
	}
140
 
141
	public function getCarteTaxonsParZones() {
142
		$this->envoyerCacheSiExiste('global');
143
 
144
		$taxonsParZones = $this->compterTaxonsParZones();
145
		$legende = $this->getLegendeCarteTaxonsParZones($taxonsParZones['max']);
146
 
147
		$infos_zones = array();
148
		$max = 0;
149
 
150
		foreach($taxonsParZones['nb_taxons_par_zones'] as $id_zone => $nb) {
151
			$infos_zones[$id_zone] = "- ".$nb." taxons présents";
152
			$legende[$this->getSeuil($nb)]['css'] .= $legende[$this->getSeuil($nb)]['css'] != "" ? ', ' : '' ;
153
			$legende[$this->getSeuil($nb)]['css'] .= "#".$this->prefixe_id_zone.$id_zone;
154
			$max = $max < $nb ? $nb : $max;
155
		}
156
 
157
		$this->style = $this->convertirLegendeVersCss($legende);
158
		$svg = $this->assemblerSvg(
159
				$this->calculerHauteur($this->largeurDemandee),
160
				$this->largeurDemandee,
161
				$this->style,
162
				$infos_zones);
163
 
164
		$this->sauverCache(array('style' => $this->style, 'infos_zones' => $infos_zones, 'nb_taxons_max' => $max), 'global');
165
		$this->envoyerSvg($svg);
166
	}
167
 
168
	// Fonction bien pourrie pour renvoyer juste un max
169
	// mais son résultat est mis en cache donc elle sera appelée environ
170
	// une fois par an (et encore si on appelle la légende avant la carte)
171
	public function getNbMaxTaxonsParZones() {
172
		$taxonsParZones = $this->compterTaxonsParZones();
173
		$max = 0;
174
 
175
		foreach($taxonsParZones as $id_zone => $nb) {
176
			$max = $max < $nb ? $nb : $max;
177
		}
178
		return $max;
179
	}
180
 
181
	public function getSeuil($nb_taxons) {
182
		// TODO: factoriser les bornes avec la fonction qui gère la légende
183
		$seuil = "";
184
		if($nb_taxons <= 1) {
185
			$seuil = "1";
186
		} elseif (2 <= $nb_taxons && $nb_taxons <= 1200) {
187
			$seuil = "2";
188
		} elseif (1201 <= $nb_taxons && $nb_taxons <= 2400) {
189
			$seuil = "3";
190
		} elseif (2401 <= $nb_taxons && $nb_taxons <= 3600) {
191
			$seuil = "4";
192
		} elseif (3601 <= $nb_taxons) {
193
			$seuil = "5";
194
		}
195
		return "seuil".$seuil;
196
	}
197
 
198
	public function compterTaxonsParZones() {
199
		$req = "SELECT * FROM ".$this->tableChorodep;
200
		$resultat = $this->Bdd->recupererTous($req);
201
 
202
		$max = 0;
203
		$nb_taxons_par_zones = array();
204
 
205
		foreach($resultat as $ligne) {
206
			$i = 0;
207
			for($i < 0; $i <= 100; $i++) {
208
				$index = $i < 10 ? "0".$i : $i;
209
				if(isset($ligne[$index]) && $ligne[$index] != "" && $ligne[$index] == self::PRESENCE_CHOROLOGIE) {
210
					// seules les présences certaines sont prises en compte
211
					$nb_taxons_par_zones[$index] = isset($nb_taxons_par_zones[$index]) ? $nb_taxons_par_zones[$index] : 0;
212
					$nb_taxons_par_zones[$index] += 1;
213
					// calcul du max qui sert à générer la légende
214
					$max = $nb_taxons_par_zones[$index] > $max ? $nb_taxons_par_zones[$index] : $max;
215
				}
216
			}
217
		}
218
 
219
		return array('nb_taxons_par_zones' => $nb_taxons_par_zones, 'max' => $max);
220
	}
221
 
222
	public function sauverCache($a_cacher, $cache_id) {
223
		$cache = new CacheSimple($this->options_cache);
224
		return $cache->sauver(serialize($a_cacher), $cache_id);
225
	}
226
 
227
	public function getCache($id) {
228
		$cache = new CacheSimple($this->options_cache);
229
		if(($contenu_cache = $cache->charger($id)) !== false) {
230
			$contenu_cache = unserialize($contenu_cache);
231
		}
232
		return $contenu_cache;
233
	}
234
 
235
	private function calculerHauteur($largeur) {
236
		$rapport = $this->longeurOrig/$this->largeurOrig;
237
		$hauteur = $rapport * $largeur;
238
		return intval($hauteur);
239
	}
240
 
241
	private function envoyerCacheSiExiste($id) {
242
		if(($cache = $this->getCache($id))) {
243
			$style = $cache['style'];
244
			$infos_zones = $cache['infos_zones'];
245
			$cache = $this->assemblerSvg($this->calculerHauteur($this->largeurDemandee), $this->largeurDemandee, $style, $infos_zones);
246
			$this->envoyerSvg($cache);
247
		}
248
	}
249
 
250
	private function assemblerSvg($hauteur, $largeur, $style, $infos_zones) {
251
		$tpl_svg = $this->cheminCartesBase.'/france_02.tpl.svg';
252
		$donnees = array(
253
						'hauteur'	=> $hauteur,
254
						'largeur'	=> $largeur,
255
						'css'		=> $style,
256
						'infos_zones' => $infos_zones
257
					);
258
		$svg = SquelettePhp::analyser($tpl_svg, $donnees);
259
		return $svg;
260
	}
261
 
262
	private function envoyerLegende($legende) {
263
		header("Content-type: application/json");
264
		echo json_encode($legende);
265
		exit;
266
	}
267
 
268
	private function envoyerSvg($svg) {
269
		header("Content-type: image/svg+xml");
270
		echo $svg;
271
		exit;
272
	}
273
}