Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

<?php
/**
* Classe Graphiques.php permet d'afficher des graphiques en svg remplis avec des données écologiques
*  fin d'url possibles :
*  graphiques/#typegraphique/#bdnt.nn:#num_nomen --> renvoie une graphique avec les données connues 
*  
* Encodage en entrée : utf8
* Encodage en sortie : utf8
* @package eflore-projets
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Mathilde SALTHUN-LASSALLE <mathilde@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-2011 Tela Botanica (accueil@tela-botanica.org)
*/

class Graphiques extends Commun{

        protected $parametres = array();
        protected $ressources = array();
        private $metadonnees;
        private $version;
        private $Bdd;
        private $nomGraphique = array();
        protected $table = "";
        private $requete_condition = "";
        private $requete_champs;
        private $config;
        private $convertisseur;
        private $cheminGraphBase;
        protected $serviceNom = 'Graphiques';
        private $valeurs_en_pourcentage ;
        private $dom;
        private $largeurSVG="500";
        private $valeurs_champs;
        private $graduations_id = array ("zero" => 0 ,"un"=> 0.1, "deux" => 0.2 , "trois" => 0.3, "quatre" => 0.4,
                                                                        "cinq" => 0.5, "six" => 0.6 ,"sept" => 0.7, "huit" => 0.8, "neuf" => 0.9,
                                                                        "dix" => 1 );
        private $champs_ontologiques =  array ('ve_lumiere' => 'VEL', 've_temperature' => 'VET',
                                                                                                've_continentalite' => 'VEC', 've_humidite_atmos' => 'VEHA',
                                                                                                've_humidite_edaph' => 'VEHE', 've_reaction_sol' => 'VER' ,
                                                                                                've_nutriments_sol' => 'VEN', 've_salinite'=> 'VES' , 
                                                                                                've_texture_sol' => 'VETX', 've_mat_org_sol' => 'VEMO');
        
        public function consulter($ressources, $parametres) {
                $this->ressources = $ressources;
                $this->parametres = $parametres;
                $this->initialiserConfiguration();
                $resultats = '';
                $this->table = Config::get('bdd_table')."_v".$this->version;
                $this->traiterRessources();
                $requete = $this->assemblerLaRequete();
                $resultat = $this->resultat = $this->Bdd->recupererTous($requete);
                $versionResultat = $this->obtenirResultat($resultat);
                return $versionResultat;
        }
        
//+--------------------------initialisation de paramètres  -------------------------------------------+
        
        public function initialiserConfiguration() {
                $conteneur = new Conteneur();
                $this->Bdd = $conteneur->getBdd();
                $this->config = $conteneur->getParametre('Graphiques');
                $this->convertisseur = $this->config['convertisseur'];
                $this->cheminGraphBase = $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']);
                $this->cache = $conteneur->getCacheSimple($cacheOptions);
                $this->chargerVersions();
                $this->definirVersion();
                $this->definirFormat();
        }
        
        //on n'affiche qu'une version de graphique à la fois ( la dernière ou celle demandée )
        private function definirVersion() {
                if( (!isset($this->parametres['version.projet']) ) || ((isset($this->parametres['version.projet']) )&&
                (($this->parametres['version.projet'] == '+') || ($this->parametres['version.projet'] == '')))){
                        $this->version = $this->metadonnees[0]['version'];
                } else {
                        $this->version = $this->parametres['version.projet'];
                }
        }
        
        private function definirFormat() {
                if (isset($this->parametres['retour.format']) ){
                        if (preg_match("/^[0-9]+$/", $this->parametres['retour.format'])){
                                $this->largeurSVG= $this->parametres['retour.format'];
                        }else {
                                $erreur = "Erreur : Entrez la largeur voulue (en pixels) pour le paramètre retour.format.";
                                $code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
                                throw new Exception($erreur, $code);
                        }
                }
                if (!isset($this->parametres['retour']) ){
                        $this->parametres['retour'] = 'image/svg+xml';  
                }else {
                        if (( $this->parametres['retour'] != 'image/svg+xml')&& ( $this->parametres['retour'] != 'image/png')){
                                $erreur = "Erreur : choisissez le format de retour pour le paramètre retour : image/svg%2Bxml ou image/png.";
                                $code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
                                throw new Exception($erreur, $code);
                        }
                }
        }
        

        
        private function chargerVersions() {
                $requete = "SELECT version ".
                                "FROM ".Config::get('bdd_table_meta')." ".
                                "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;
        }
        
        //+--------------------------traitement ressources ou paramètres  -------------------------------------------+ 
        
        public function traiterRessources() {
                $this->traiterRessources_NomService();
                $this->traiterRessources_TypeGraphique();
        }
        
        public function traiterRessources_TypeGraphique(){
                if (isset($this->ressources) && !empty($this->ressources[1])) {
                        if(preg_match('/^(.+)\.nn:([0-9]+)$/', $this->ressources[1], $retour)==1){
                                switch ($retour[1]) {
                                        case 'bdtfx' :
                                                $this->requete_condition[]= "num_nomen = ".$retour[2]." AND BDNT = 'BDTFX' ";
                                                break;
                                        case  'bdafx' :
                                                $this->requete_condition[] = "num_nomen = ".$retour[2]." AND BDNT = 'BDAFX' ";
                                                break;
                                        case  'bdbfx' :
                                                $this->requete_condition[] = "num_nomen = ".$retour[2]." AND BDNT = 'BDBFX' ";
                                                break;
                                        default :
                                                $e = 'Erreur dans l\'url de votre requête : </br> La ressource " '
                                        .$retour[1].' " n\'existe pas.';
                                        throw new Exception( $e, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
                                        break;
                                }
                
                        }else {
                                $e = 'Erreur dans l\'url de votre requête : </br> La ressource  n\'existe pas.';
                                throw new Exception( $e, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
                        }
                } else {
                        throw new Exception( "Erreur dans l\'url de votre requête :".
                                        "preciser le référentiel et le numéro nomenclatural sous la forme {bdnt}.nn:{nn}.",
                        RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
                }
                
        }
        
        public function traiterRessources_NomService(){
                if (isset($this->ressources) && !empty($this->ressources[0])) {
                        switch ($this->ressources[0]) {
                                case  'climat' :
                                        $this->requete_champs = ' ve_lumiere , ve_temperature, ve_continentalite, ve_humidite_atmos' ;
                                        $this->nomGraphique= 'climat';
                                        break;
                                case 'sol' :
                                        $this->requete_champs = ' ve_humidite_edaph , ve_reaction_sol, ve_nutriments_sol, ve_salinite,'
                                        .'ve_texture_sol, ve_mat_org_sol' ;
                                        $this->nomGraphique = 'sol';
                                        break;
                                default :
                                        $e = 'Erreur dans l\'url de votre requête : </br> La ressource " '
                                .$retour[1].' " n\'existe pas.';
                                throw new Exception($e, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
                                break;
                        }
                }else {
                        throw new Exception("Erreur dans l\'url de votre requête :".
                        "</br> precisez le graphique -> \"sol\" ou \"climat\".", RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
                }
        }
        

        

        //+-------------------------- formatage du résultat  -------------------------------------------+

        
        public function obtenirResultat($resultat) {
                if ($resultat == ""){
                        $message = 'La requête SQL formée comporte une erreur!';
                        $code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
                        throw new Exception($message, $code);
                }elseif ($resultat) {
                        if ((count($this->ressources)) != 0) {
                                $this->traiterValeursEcologiques($resultat[0]);
                                $svg = $this->genererSVG();
                                $resultat = new ResultatService();
                                $resultat->corps = ($this->parametres['retour'] == 'image/png') ? $this->convertirEnPNG($svg) : $svg;
                                $resultat->mime = $this->parametres['retour'];
                                }
                } else {
                        $message = 'Les données recherchées sont introuvables.';
                        $code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
                        throw new Exception($message, $code);
                }
                return $resultat;
        }
        

        public function traiterValeursEcologiques($valeur){
                $this->valeurs_champs = $valeur; 
                //humidite edaphique sur echelle de 12
                foreach($this->valeurs_champs as $cle => $val){
                        if ($cle == 've_humidite_edaph'){
                                $this->valeurs_en_pourcentage[$cle] = round($val/12,1);
                        }else{
                                //salinite commence à 0
                                if($val == 0){
                                        $this->valeurs_en_pourcentage[$cle] = 0;
                                }else{
                                        $this->valeurs_en_pourcentage[$cle] = round($val/9,1);
                                }
                        }
                }
        }
        
        public function genererSVG(){
                $this->dom = new DOMDocument('1.0', 'UTF-8');
                //verifie que le xml est bien formé
                $this->dom->validateOnParse = true;
                $fichierSvg = $this->cheminGraphBase."".$this->nomGraphique.".svg";
                $this->dom->load($fichierSvg);
                $this->changerValeursSVG();
                $svg = $this->dom->saveXML();
                return $svg;
        }
        

        
        public function changerValeursSVG(){
                foreach ($this->valeurs_en_pourcentage as $cle => $val){
                        $grad_id = array_search($val,$this->graduations_id);
                        $Dompath = new DOMXPath($this->dom);
                        $element = $Dompath->query("//*[@id='".$grad_id."']")->item(0);
                        $pos_x = $element->getAttribute('x1');
                        $curseur = $Dompath->query("//*[@id='".$cle."']")->item(0);
                        $curseur->setAttribute('cx', $pos_x);
                        $this->ajouterInfoAuSurvol($curseur);
                        $svg = $this->dom->getElementsByTagName("svg")->item(0);
                        $svg->setAttribute('width',$this->largeurSVG);
                }
        }
        
        public function ajouterInfoAuSurvol($curseur){
                $champs = $curseur->getAttribute('id');
                $valeurTexte = $this->recupererOntologies($this->valeurs_champs[$champs], $champs );
                $curseur->setAttribute('title',$this->valeurs_champs[$champs].":".$valeurTexte->nom );
        }
        
        public function recupererOntologies($valeur, $champs){
                $url = $this->ajouterHref('ontologies',$this->champs_ontologiques[$champs].':'.urlencode(urlencode($valeur)));
                $val = $this->consulterHref($url);
                return $val;
        }
        
        public function convertirEnPNG($svg) {
                $png = null;
                
                if (isset($this->convertisseur)) {
                        if ($this->convertisseur == 'imagick') {
                                if (extension_loaded('imagick')) {
                                        $png = $this->convertirEnPNGAvecImageMagick($svg);
                                } else {
                                        $message = "Impossible de générer l'image sur le serveur. Extension ImageMagick absente.";
                                        $code = RestServeur::HTTP_CODE_ERREUR;
                                        throw new Exception($message, $code);
                                }
                        } else if ($this->convertisseur == 'rsvg') {
                        $png = $this->convertirEnPNGAvecRsvg($svg);
                        } else {
                                $message = "Le convertisseur indiqué '{$this->convertisseur}' ne fait pas partie de la liste ".
                                                "des convertisseurs disponibles : imagick, rsvg.";
                                $code = RestServeur::HTTP_CODE_ERREUR;
                                throw new Exception($message, $code);
                        }
                } else {
                        $message = "Veuillez indiquer le convertisseur de svg à utiliser pour le service.";
                        $code = RestServeur::HTTP_CODE_ERREUR;
                        throw new Exception($message, $code);
                }
                return $png;
        }
        
        public function convertirEnPNGAvecImageMagick($svg) { 
                $convertisseur = new Imagick();
                $convertisseur->setBackgroundColor(new ImagickPixel('#F8F8F8'));
                $convertisseur->readImageBlob($svg);
                $convertisseur->setImageFormat('png32');
                $convertisseur->resizeImage($this->largeurSVG, 0 , imagick::FILTER_LANCZOS, 0, true);
                $png = $convertisseur->getImageBlob();
                $convertisseur->clear();
                $convertisseur->destroy();
                return $png;
        }
        
        public function convertirEnPNGAvecRsvg($svg) { 
                $idFichier = $this->getIdFichier(); 
                $fichierPng = $this->config['cache']['stockageChemin']."".$idFichier.'.png';
                $fichierSvg = $this->config['cache']['stockageChemin']."".$idFichier.'.svg';
                file_put_contents($fichierSvg, $svg);
                $commande = "rsvg-convert  $fichierSvg -b #F8F8F8 -w $this->largeurSVG -a -o $fichierPng";
                $rsvg = exec($commande);
                $this->indexerFichierPng($fichierPng);
                $png = file_get_contents($fichierPng);
                return $png;
        }
        
        public function indexerFichierPng($fichierPng) {
                $img = imagecreatefrompng($fichierPng);
                imagetruecolortopalette($img, false, 32);
                imagepng($img, $fichierPng, 9, PNG_ALL_FILTERS);
        }
        
        public function getIdFichier(){
                $idfichier = str_replace(".","-",$this->ressources[1]);
                $idfichier = str_replace(':','-',$idfichier);
                $idfichier .= "-".$this->ressources[0];
                return $idfichier;
        }
        //+--------------------------FONCTIONS D'ASSEMBLAGE DE LA REQUETE-------------------------------------------+
        
        public function assemblerLaRequete() {
                $requete =      ' SELECT '.$this->requete_champs.'  FROM '.$this->table.' '.$this->retournerRequeteCondition();
                return $requete;
        }

        public  function retournerRequeteCondition() {
                $condition = '';
                if ($this->requete_condition !== "") {
                        $condition = ' WHERE '.implode(' AND ', $this->requete_condition);
                }
                return $condition;
        }
        
        

}
?>