Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

<?php
// declare(encoding='UTF-8');
/**
* Classe implémentant l'API d'eFlore Cartes pour le projet CHORODEP.
*
* @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 Cartes {

        private $parametres = array();
        private $ressources = array();
        private $Bdd;

        const CODE_REFTAX_DEFAUT = 'bdtfx';
        const TYPE_ID_DEFAUT = 'nn';
        const CARTE_DEFAUT = 'france_02';
        const FORMAT_DEFAUT = '550';
        const MIME_SVG = 'image/svg+xml';
        const MIME_PNG = 'image/png';

        private $config = array();
        private $cheminCartesBase = '';
        private $formats_supportes = array(self::MIME_SVG, self::MIME_PNG);
        private $UrlNavigation = null;
        private $taxonsDemandes = array();
        private $imgLargeur = 0;
        private $imgHauteur = 0;
        private $legende = array();
        private $donnees = array();

        public function __construct(Bdd $bdd = null, Array $config = null, CacheSimple $cache = null) {
                $this->Bdd = is_null($bdd) ? new Bdd() : $bdd;
                $this->config = is_null($config) ? Config::get('Cartes') : $config;

                $this->chargerLegende();

                $this->cheminCartesBase = $this->config['chemin'];

                $cacheOptions = array('mise_en_cache' => $this->config['cache']['miseEnCache'],
                        'stockage_chemin' => $this->config['cache']['stockageChemin'],
                        'duree_de_vie' => $this->config['cache']['dureeDeVie']);
                //die(print_r($this->config, true));
                $this->cache = is_null($cache) ? new CacheSimple($cacheOptions) : $cache;
        }

        private function chargerLegende() {
                $requete = 'SELECT * '.
                                'FROM chorodep_ontologies '.
                                "WHERE classe_id = 1 ";
                $resultats = $this->Bdd->recupererTous($requete);

                if (!is_array($resultats) || count($resultats) <= 0) {
                        $message = "La légende n'a pu être chargée pour la ressource demandée";
                        $code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
                        throw new Exception($message, $code);
                }

                foreach ($resultats as $ontologie) {
                        $ontologie = $this->extraireComplementsOntologies($ontologie);
                        $this->legende[$ontologie['code']] = $ontologie['legende'];
                }
        }

        private function extraireComplementsOntologies($ontologie) {
                $complements = explode(',', trim($ontologie['complements']));
                foreach ($complements as $complement) {
                        list($cle, $val) = explode('=', trim($complement));
                        $ontologie[trim($cle)] = trim($val);
                }
                return $ontologie;
        }

        public function consulter($ressources, $parametres) {
                //$tpsDebut = microtime(true);
                $this->parametres = $parametres;
                $this->ressources = $ressources;

                $this->definirValeurParDefautDesParametres();
                $this->verifierParametres();
                $this->analyserIdentifiant();

                $resultat = new ResultatService();
                $this->chargerDonnees();
                if ($this->parametres['retour'] == self::MIME_SVG) {
                        $svg = $this->genererSVG();
                        $resultat->corps = $svg;
                } else if ($this->parametres['retour'] == self::MIME_PNG) {
                        $svg = $this->genererSVG();
                        $png = $this->convertirEnPNG($svg);
                        $resultat->corps = $png;
                }
                $resultat->mime = $this->parametres['retour'];

                return $resultat;
        }

        private function definirValeurParDefautDesParametres() {
                if (isset($this->parametres['retour']) == false) {
                        $this->parametres['retour'] = self::MIME_SVG;
                }
                if (isset($this->parametres['retour.format']) == false) {
                        $this->parametres['retour.format'] = self::FORMAT_DEFAUT;
                }
        }

        private function verifierParametres() {
                $erreurs = array();

                if ($this->verifierIdentifiants() == false) {
                        $erreurs[] = "L'identifiant de ressource indiqué ne respecte pas le format attendu.";
                }
                if (isset($this->parametres['retour']) == false) {
                        $erreurs[] = "Le paramètre type de retour 'retour' est obligatoire.";
                }
                if ($this->verifierValeurParametreRetour() == false) {
                        $erreurs[] = "Le type de retour '{$this->parametres['retour']}' n'est pas supporté.";
                }
                if (isset($this->parametres['retour.format']) == false) {
                        $erreurs[] = "Le paramètre de format de retour 'retour.format' est obligatoire.";
                }
                if ($this->verifierValeurParametreFormat() == false) {
                        $erreurs[] = "Le type de format '{$this->parametres['retour.format']}' n'est pas supporté.".
                                "Veuillez indiquer un nombre entier correspondant à la largeur désirée pour la carte.";
                }

                if (count($erreurs) > 0) {
                        $message = implode('<br />', $erreurs);
                        $code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
                        throw new Exception($message, $code);
                }
        }

        private function verifierIdentifiants() {
                $ok = true;
                if (isset($this->ressources[0])) {
                        $ids = $this->ressources[0];
                        $projetPattern = '(?:(?:[A-Z0-9]+(\.(?:nn|nt)?):)?(?:[0-9]+,)*[0-9]+)';
                        $patternComplet = "/^$projetPattern(?:;$projetPattern)*$/i";
                        $ok = preg_match($patternComplet, $ids) ? true : false;
                }
                return $ok;
        }

        private function verifierValeurParametreRetour() {
                return in_array($this->parametres['retour'], $this->formats_supportes);
        }

        private function verifierValeurParametreFormat() {
                if ($ok = preg_match('/^([0-9]+)$/', $this->parametres['retour.format'], $match)) {
                        $this->imgLargeur = $match[1];
                } else if ($ok = preg_match('/^([0-9]+)x([0-9]+)$/', $this->parametres['retour.format'], $match)) {
                        $this->imgLargeur = $match[1];
                        $this->imgHauteur = $match[2];
                }
                return $ok;
        }

        private function analyserIdentifiant() {
                if (isset($this->ressources[0])) {
                        $ids = $this->ressources[0];
                        if (preg_match('/^[0-9]+$/', $ids)) {
                                $this->taxonsDemandes[self::CODE_REFTAX_DEFAUT]['nn'][] = $ids;
                        } else {
                                // ceci contient potentiellement des formes ref_tax1.nn:1,2;ref_tax2.nt:3,4
                                throw new Exception("A implémenter : ressource id multiples");
                                $projetsListeEtNumNoms = explode(';', $nn);
                                if (count($projetsListeEtNumNoms) > 0) {
                                        foreach ($projetsListeEtNumNoms as $projetEtNumNoms) {
                                                $projetEtNumNoms = (strpos($projetEtNumNoms, ':')) ? $projetEtNumNoms : self::CODE_REFTAX_DEFAUT.':'.$projetEtNumNoms;
                                                list($projet, $numNoms) = explode(':', $projetEtNumNoms);
                                                $this->ref_tax_demande[$projet] = explode(',', $numNoms);
                                        }
                                }
                        }
                } else {
                        throw new Exception("A implémenter : carte proportionnelle ensemble des infos");
                }
        }

        private function chargerDonnees() {
                $refTax = self::CODE_REFTAX_DEFAUT;
                $numNom = $this->Bdd->proteger($this->taxonsDemandes[$refTax]['nn'][0]);

                $requete = 'SELECT * '.
                                'FROM chorodep_v2012_01 '.
                                "WHERE num_nom IN ($numNom) ";
                $resultat = $this->Bdd->recupererTous($requete);

                if (!is_array($resultat) || count($resultat) <= 0) {
                        $message = "Aucune donnée ne correspond à la ressource demandée";
                        $code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
                        throw new Exception($message, $code);
                }
                $this->donnees = $resultat;
        }

        private function genererSVG() {
                $dom = new DOMDocument('1.0', 'UTF-8');
                $dom->validateOnParse = true;

                $fichierCarteSvg = $this->cheminCartesBase.self::CARTE_DEFAUT.'.svg';
                $dom->load($fichierCarteSvg);

                $racineElement = $dom->documentElement;
                $racineElement->setAttribute('width', $this->imgLargeur);

                $css = $this->creerCssCarte();
                $txtCss = $dom->createCDATASection($css);
                $dom->getElementsByTagName('style')->item(0)->appendChild($txtCss);

                $titre = $this->creerTitre();
                $titreCdata = $dom->createCDATASection($titre);
                $titreElement = $dom->getElementsByTagName('title')->item(0);
                $titreElement->nodeValue = '';
                $titreElement->appendChild($titreCdata);

                $taxonTitre = $this->creerTitreTaxon();
                $taxonCdata = $dom->createCDATASection($taxonTitre);
                $xpath = new DOMXPath($dom);
                $taxonTitreEl = $xpath->query("//*[@id='titre-taxon']")->item(0);
                $taxonTitreEl->nodeValue = '';
                $taxonTitreEl->appendChild($taxonCdata);

                $svg = $dom->saveXML();
                return $svg;
        }

        private function creerCssCarte() {
                $fichierCssBase = $this->cheminCartesBase.self::CARTE_DEFAUT.'.css';
                $css = file_get_contents($fichierCssBase);

                $zonesCouleurs = $this->getZonesCouleurs();
                foreach ($zonesCouleurs as $couleur => $zonesClasses) {
                        $classes = implode(', ', $zonesClasses);
                        $css .= "$classes{\nfill:$couleur;\n}\n";
                }
                return $css;
        }

        private function getZonesCouleurs() {
                $zones = array();
                foreach ($this->donnees as $donnee) {
                        foreach ($donnee as $champ => $valeur) {
                                if (preg_match('/^[0-9][0-9ab]$/i', $champ)) {
                                        if (array_key_exists($valeur, $this->legende)) {
                                                $couleur = $this->legende[$valeur];
                                                $zones[$couleur][] = strtolower(".departement$champ");
                                        }
                                }
                        }
                }
                return $zones;
        }

        private function creerTitre() {
                $titre = "Carte en cours d'élaboration pour ".$this->creerTitreTaxon();
                return $titre;
        }

        private function creerTitreTaxon() {
                $noms = array();
                foreach ($this->donnees as $donnee) {
                        $noms[] = $donnee['nom_sci'];
                }
                $titre = implode(', ', $noms);
                return $titre;
        }

        private function convertirEnPNG($svg) {
                $png = null;
                if (extension_loaded('imagick')) {
                        $png = $this->convertirEnPNGAvecImageMagick($svg);
                } else {
                        $message = "Impossible de générer l'image sur le serveur. Extenssion ImageMagick abscente.";
                        $code = RestServeur::HTTP_CODE_ERREUR;
                        throw new Exception($message, $code);
                }
                return $svg;
        }

        private function convertirEnPNGAvecImageMagick($svg) {
                $convertisseur = new Imagick();
                $convertisseur->readImageBlob($svg);
                $convertisseur->setImageFormat("png24");
                $convertisseur->resizeImage($this->imgLargeur, $this->imgHauteur, imagick::FILTER_LANCZOS, 0);
                $png = $convertisseur->getImageBlob();
                $convertisseur->clear();
                $convertisseur->destroy();
                return $png;
        }

        public function getParametreTableau($cle) {
                $tableau = array();
                $parametre = $this->config[$cle];
                if (empty($parametre) === false) {
                        $tableauPartiel = explode(',', $parametre);
                        $tableauPartiel = array_map('trim', $tableauPartiel);
                        foreach ($tableauPartiel as $champ) {
                                if (strpos($champ, '=') === false) {
                                        $tableau[] = trim($champ);
                                } else {
                                        list($cle, $val) = explode('=', $champ);
                                        $tableau[trim($cle)] = trim($val);
                                }
                        }
                }
                return $tableau;
        }
}
?>