Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
// declare(encoding='UTF-8');
/**
* Gère le sous-service Taxons de Cartes.
*
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=EfloreApi01Cartes
*
* @package eFlore/services
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @version 1.0
* @copyright 1999-2012 Tela Botanica (accueil@tela-botanica.org)
*/
// TODO : Config et Outils sont des classes statiques qui doivent poser des pb pour les tests...
class FranceCartes {
private $parametres = array();
private $ressources = array();
protected $largeurOrig = 600;
protected $longeurOrig = 545;
protected $largeurDefaut = 600;
protected $largeurDemandee = 600;
protected $prefixe_id_zone = 'INSEE-D';
protected $options_cache = array();
const PRESENCE_CHOROLOGIE = '1';
public function __construct(Conteneur $conteneur) {
$this->Bdd = $conteneur->getBdd();
$this->tableOntologie = $conteneur->getParametre('bdd_table_ontologies');
$this->config = $conteneur->getParametre('Cartes');
$this->convertisseur = $this->config['convertisseur'];
$this->tableMeta = $conteneur->getParametre('bdd_table_meta');
$this->cheminCartesBase = $this->config['chemin'];
$this->options_cache = array('mise_en_cache' => $this->config['cache_miseEnCache'],
'stockage_chemin' => $this->config['cache_stockageChemin'],
'duree_de_vie' => $this->config['cache_dureeDeVie']);
}
public function consulter($ressources, $parametres) {
$this->parametres = $parametres;
$this->ressources = $ressources;
$this->chargerMetadonnees();
$this->definirVersion();
$this->tableChorodep = 'chorodep_v'.str_replace('.', '_', $this->version);
if(isset($parametres['retour.format']) && is_numeric($parametres['retour.format'])) {
$this->largeurDemandee = intval($parametres['retour.format']);
}
if(count($ressources) == 0) {
$resultat = $this->getCarteTaxonsParZones();
} else if($ressources[0] == "legende") {
$cache = $this->getCache('global');
if($cache != null) {
$max = $cache['nb_taxons_max'];
} else {
$max = $this->getNbMaxTaxonsParZones();
}
$resultat = $this->getLegendeCarteTaxonsParZones($max);
}
return $resultat;
}
private function chargerMetadonnees() {
$requete = 'SELECT * '.
"FROM {$this->tableMeta} ".
"ORDER BY date_creation DESC ";
$resultats = $this->Bdd->recupererTous($requete);
if (!is_array($resultats) || count($resultats) <= 0) {
$message = "Les méta-données n'ont pu être chargée pour la ressource demandée";
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
throw new Exception($message, $code);
}
$this->metadonnees = $resultats;
}
private function definirVersion() {
$this->version = $this->metadonnees[0]['version'];
}
public function getLegendeCarteTaxonsParZones($nb_max) {
// TODO : mettre en config ou en ontologie ?
// mais ça fait encore un appel de plus aux ontologies
// qui sont déjà bien bien bien bien chargées
$this->couleurs_legende_globale = array("#808080", "#EFF8E1", "#F2E2C0", "#C9CC8D", "#C1E587", "#A0FF7D");
$couleurs = $this->couleurs_legende_globale;
$legende = array(
"seuil0" => array(
"code" => "",
"couleur" => $couleurs[0],
"css" => "",
"nom" => "Non renseignée",
"description" => "Zone géographique non renseignée."
)
);
array_shift($couleurs);
$borne_min = 0;
$borne_max = 500;
for($i = 1; $i <= 5; $i++) {
$borne_max = ($i == 5) ? $nb_max : $borne_max;
$legende["seuil".$i] = array(
"code" => "",
"couleur" => $couleurs[$i-1],
"css" => "",
"nom" => "de ".$borne_min." à ".$borne_max." taxons",
"description" => "de ".$borne_min." à ".$borne_max." taxons."
);
$borne_min = $borne_max + 1;
$borne_max = ($i == 5) ? $nb_max : ($i * 1200);
}
return $legende;
}
private function convertirLegendeVersCss($legende) {
$css = "";
foreach($legende as $cle => $item) {
if($item['css'] != '') {
$css .=
$item['css']." {"."\n".
" fill:".$item['couleur'].";"."\n".
"}"."\n\n";
}
}
return $css;
}
public function getCarteTaxonsParZones() {
$this->envoyerCacheSiExiste('global');
$taxonsParZones = $this->compterTaxonsParZones();
$legende = $this->getLegendeCarteTaxonsParZones($taxonsParZones['max']);
$infos_zones = array();
$max = 0;
foreach($taxonsParZones['nb_taxons_par_zones'] as $id_zone => $nb) {
$infos_zones[$id_zone] = "- ".$nb." taxons présents";
$legende[$this->getSeuil($nb)]['css'] .= $legende[$this->getSeuil($nb)]['css'] != "" ? ', ' : '' ;
$legende[$this->getSeuil($nb)]['css'] .= "#".$this->prefixe_id_zone.$id_zone;
$max = $max < $nb ? $nb : $max;
}
$this->style = $this->convertirLegendeVersCss($legende);
$svg = $this->assemblerSvg(
$this->calculerHauteur($this->largeurDemandee),
$this->largeurDemandee,
$this->style,
$infos_zones);
$this->sauverCache(array('style' => $this->style, 'infos_zones' => $infos_zones, 'nb_taxons_max' => $max), 'global');
$this->envoyerSvg($svg);
}
// Fonction bien pourrie pour renvoyer juste un max
// mais son résultat est mis en cache donc elle sera appelée environ
// une fois par an (et encore si on appelle la légende avant la carte)
public function getNbMaxTaxonsParZones() {
$taxonsParZones = $this->compterTaxonsParZones();
$max = 0;
foreach($taxonsParZones as $id_zone => $nb) {
$max = $max < $nb ? $nb : $max;
}
return $max;
}
public function getSeuil($nb_taxons) {
// TODO: factoriser les bornes avec la fonction qui gère la légende
$seuil = "";
if($nb_taxons <= 1) {
$seuil = "1";
} elseif (2 <= $nb_taxons && $nb_taxons <= 1200) {
$seuil = "2";
} elseif (1201 <= $nb_taxons && $nb_taxons <= 2400) {
$seuil = "3";
} elseif (2401 <= $nb_taxons && $nb_taxons <= 3600) {
$seuil = "4";
} elseif (3601 <= $nb_taxons) {
$seuil = "5";
}
return "seuil".$seuil;
}
public function compterTaxonsParZones() {
$req = "SELECT * FROM ".$this->tableChorodep;
$resultat = $this->Bdd->recupererTous($req);
$max = 0;
$nb_taxons_par_zones = array();
foreach($resultat as $ligne) {
$i = 0;
for($i < 0; $i <= 100; $i++) {
$index = $i < 10 ? "0".$i : $i;
if(isset($ligne[$index]) && $ligne[$index] != "" && $ligne[$index] == self::PRESENCE_CHOROLOGIE) {
// seules les présences certaines sont prises en compte
$nb_taxons_par_zones[$index] = isset($nb_taxons_par_zones[$index]) ? $nb_taxons_par_zones[$index] : 0;
$nb_taxons_par_zones[$index] += 1;
// calcul du max qui sert à générer la légende
$max = $nb_taxons_par_zones[$index] > $max ? $nb_taxons_par_zones[$index] : $max;
}
}
}
return array('nb_taxons_par_zones' => $nb_taxons_par_zones, 'max' => $max);
}
public function sauverCache($a_cacher, $cache_id) {
$cache = new CacheSimple($this->options_cache);
return $cache->sauver(serialize($a_cacher), $cache_id);
}
public function getCache($id) {
$cache = new CacheSimple($this->options_cache);
if(($contenu_cache = $cache->charger($id)) !== false) {
$contenu_cache = unserialize($contenu_cache);
}
return $contenu_cache;
}
private function calculerHauteur($largeur) {
$rapport = $this->longeurOrig/$this->largeurOrig;
$hauteur = $rapport * $largeur;
return intval($hauteur);
}
private function envoyerCacheSiExiste($id) {
if(($cache = $this->getCache($id))) {
$style = $cache['style'];
$infos_zones = $cache['infos_zones'];
$cache = $this->assemblerSvg($this->calculerHauteur($this->largeurDemandee), $this->largeurDemandee, $style, $infos_zones);
$this->envoyerSvg($cache);
}
}
private function assemblerSvg($hauteur, $largeur, $style, $infos_zones) {
$tpl_svg = $this->cheminCartesBase.'/france_02.tpl.svg';
$donnees = array(
'hauteur' => $hauteur,
'largeur' => $largeur,
'css' => $style,
'infos_zones' => $infos_zones
);
$svg = SquelettePhp::analyser($tpl_svg, $donnees);
return $svg;
}
private function envoyerLegende($legende) {
header("Content-type: application/json");
echo json_encode($legende);
exit;
}
private function envoyerSvg($svg) {
header("Content-type: image/svg+xml");
echo $svg;
exit;
}
}