Subversion Repositories eFlore/Projets.eflore-projets

Rev

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;
        }
}