Subversion Repositories eFlore/Applications.moissonnage

Rev

Rev 31 | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php

/**
 * 
 * Classe principale du web service qui peut traiter des requetes provenant d'un navigateur web
 * (stations dans bbox ou observations sur un point), ou d'un client SIG via appel au protocole/service WFS
 * (demande d'observations par stations selon des filtres optionnels). Le web service analyse et verifie
 * les parametres de l'URL de la requete qu'il recoit. S'ils sont tous valides, il va appeler une autre classe
 * pour recuperer les informations demandees dans les differentes sources de donnees.
 * Les donnees recuperees sont ensuite combinees si plusieurs sources sont demandees et mises en forme
 * au format de sortie. Les formats de sortie utilises sont le GeoJSON (extension de JSON pour les donnees
 * geographiques) en destination des navigateurs web et le GML adapte au service WFS pour les clients SIG.
 * Dans le cas ou des erreurs sont levees, le web service renvoie un message d'erreur expliquant le probleme
 * recnontre dans son fonctionnement.
 * 
 * 
 * @package framework-0.4
 * @author Alexandre GALIBERT <alexandre.galibert@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 $Id$
 * @copyright 2013 Tela Botanica (accueil@tela-botanica.org)
 *
 */

class Commun {
        
        
        private $parametres = array();
        private $ressources = array();
        private $nomSource = '';
        private $nomService = '';
        
        private $verificateur = null;
        private $parametresRecherche = null;
        private $retour = array();
        
        const MIME_WFS = 'text/xml';
        
        
        public function consulter($ressources, $parametres) {
                $this->recupererRessourcesEtParametres($ressources, $parametres);
                $retour = null;
                if (in_array("wfs", $ressources)) {
                        $retour = $this->traiterRequeteWfs();
                } else {
                        $retour = $this->traiterRequeteNavigateur();
                }
                return $retour;
        }
        
        
        
        /*********************************************/
        // Verification parametres URL non-WFS
        
        private function traiterRequeteWfs() {
                $retour = null;
                try {
                        $this->parametresRecherche = new StdClass();
                        $this->traiterParametreOperation();
                        if ($this->parametresRecherche->operation != 'GetCapabilities') {
                                $this->traiterParametreSource();
                        }
                        if ($this->parametresRecherche->operation == 'GetFeature') {
                                $retour = $this->getFeature();
                        } else {
                                $formateurWfs = new FormateurWfs();
                                $nomMethode = 'formater'.$this->parametresRecherche->operation;
                                $parametre = isset($this->parametresRecherche->sources)
                                        ? $this->parametresRecherche->sources : null;
                                $retour = new ResultatService();
                                $retour->mime = self::MIME_WFS;
                                $retour->corps = $formateurWfs->$nomMethode($parametre);
                        }
                } catch (Exception $erreur) {
                        $formateurWfs = new FormateurWfs();
                        $retour = new ResultatService();
                        $retour->mime = self::MIME_WFS;
                        $retour->corps = $formateurWfs->formaterException($erreur);
                }
                return $retour;
        }
        
        private function getFeature() {
                if (array_key_exists('bbox', $this->parametres)) {
                        $this->traiterParametreBbox();
                } elseif (array_key_exists('filter', $this->parametres)) {
                        $this->traiterParametreFilter();
                }
                $this->recupererStationsWfs();
                $formateurWfs = new FormateurWfs();
                $retour = new ResultatService();
                $retour->mime = self::MIME_WFS;
                $retour->corps = $formateurWfs->formaterGetFeature($this->retour, $this->parametresRecherche->sources);
                return $retour;
        }
        
        private function traiterParametreOperation() {
                if ($this->verifierExistenceParametre('request')) {
                        if (!$this->estOperationWfsAutorisee()) {
                                $message = "L'opération '".$this->parametres['request']."' n'est pas autorisée.\n".
                                        "Les opérations suivantes sont permises par le service : ".Config::get('operations_wfs');
                                throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                        } else {
                                $this->parametresRecherche->operation = $this->parametres['request'];
                        }
                }
        }
                
        private function verifierExistenceParametre($nomParametre) {
                $estParametreExistant = false;
                if (!array_key_exists($nomParametre, $this->parametres)) {
                        $message = "Le paramètre nom de l'opération '{$nomParametre}' ".
                                "n'a pas été trouvé dans la liste des paramètres.";
                        throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                } else {
                        $estParametreExistant = true;
                }
                return $estParametreExistant;
        }
        
        private function estOperationWfsAutorisee() {
                $operationsWfsService = explode(',' , Config::get('operations_wfs'));
                return (in_array($this->parametres['request'], $operationsWfsService));
        }
        
        private function traiterParametreSource() {
                // le parametre source (typename) est optionnel par defaut
                if (array_key_exists('typename', $this->parametres)) {
                        $sources = explode(',', $this->parametres['typename']);
                        $estSourceValide = true;
                        foreach ($sources as $source) {
                                if (!$this->verifierExistenceSourcesDonnees($source)) {
                                        $message = "Source de donnees '{$source}' indisponible. Les sources disponibles sont : ".
                                                Config::get('sources_dispo');
                                        $estSourceValide = false;
                                        throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                                }
                        }
                        if ($estSourceValide) {
                                $this->parametresRecherche->sources = $sources;
                        }
                }
        }
        
        private function traiterParametreBbox() {
                $bboxVerifiee = $this->verifierCoordonneesBbox($this->parametres['bbox']);
                if (is_array($bboxVerifiee) && count($bboxVerifiee) == 4) {
                        $this->parametresRecherche->bbox = array($bboxVerifiee);
                }
        }
        
        private function verifierCoordonneesBbox($bbox) {
                $bboxVerifiee = null;
                // verifier que la chaine de caracteres $bbox est une serie de chaque nombre decimaux
                // separes entre eux par une virgule
                if (preg_match('/^(-?\d{1,3}(.\d+)?,){3}(-?\d{1,3}(.\d+)?)$/', $bbox) == 0) {
                        $message = "Format de saisie des coordonnees de la bounding box non valide.  Le service ".
                                        "n'accepte seulement qu'une serie de 4 nombre décimaux séparés par des virgules.";
                        throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                } else {
                        $coordonnees = explode(',', $bbox);
                        $nomsIndexBbox = array("ouest", "sud", "est", "nord");
                        $bbox = array();
                        for ($i = 0; $i < count($coordonnees); $i ++) {
                                $bbox[$nomsIndexBbox[$i]] = $coordonnees[$i];
                        }
                        // verifier que les coordonnees de chaque bord de la bbox sont valides
                        if ($this->estUneBboxValide($bbox)) {
                                $bboxVerifiee = $bbox;
                        } else {
                                $message = "Certaines coordonnées de la bounding box sont situés en dehors des limites ".
                                                "de notre monde";
                                throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                        }
                }
                return $bboxVerifiee;
        }
        
        private function estUneBboxValide($bbox) {
                $monde = array(
                        'ouest' => floatval(Config::get('carte.limite_ouest')),
                        'est'   => floatval(Config::get('carte.limite_est')),
                        'sud'   => floatval(Config::get('carte.limite_sud')),
                        'nord'  => floatval(Config::get('carte.limite_nord'))
                );
                return (floatval($bbox['ouest']) >= $monde['ouest']  && floatval($bbox['ouest']) <= $monde['est']
                        && floatval($bbox['est'])   >= $monde['ouest']  && floatval($bbox['est'])   <= $monde['est']
                        && floatval($bbox['nord'])  >= $monde['sud']    && floatval($bbox['nord'])  <= $monde['nord']
                        && floatval($bbox['sud'])   >= $monde['sud']    && floatval($bbox['sud'])   <= $monde['nord']);
        }
        
        private function traiterParametreFilter() {
                // la valeur du parametre filter est une chaine de texte qui compose en realite un document XML
                // plus d'infos a l'URL suivante : http://mapserver.org/fr/ogc/filter_encoding.html 
                $filtreTexte = $this->recupererTexteParametreFilter();
                $documentXML = new DomDocument();
                $documentXML->loadXML($filtreTexte);
                $filtres = $documentXML->documentElement->childNodes;
                for ($index = 0; $index < $filtres->length; $index ++) {
                        $this->verifierFiltre($filtres->item($index));
                }
        }
        
        private function recupererTexteParametreFilter() {
                $parametresUrl = explode("&", $_SERVER['QUERY_STRING']);
                $filtreTexte = '';
                foreach ($parametresUrl as $parametre) {
                        list($cle, $valeur) = explode("=", $parametre);
                        if ($cle == 'filter') {
                                $filtreTexte = rawurldecode($valeur);
                        }
                }
                return $filtreTexte;
        }
        
        private function verifierFiltre($filtre) {
                $operateursAcceptes = explode(',', Config::get('operateurs_wfs'));
                $nomOperateur = $filtre->tagName;
                if (!in_array($nomOperateur, $operateursAcceptes)) {
                        $message = "Le filtre '$nomOperateur' n'est pas pris en compte par le serrvice. ".
                        "Les opérateurs acceptés sont :".implode(', ', $operateursAcceptes);
                        throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                } else {
                        if ($nomOperateur == 'BBOX') {
                                $bboxUrl = $filtre->lastChild->nodeValue;
                                $bboxVerifiee = $this->verifierCoordonneesBbox($bboxUrl);
                                $this->parametresRecherche->bbox = array($bboxVerifiee);
                        } else {
                                $this->traiterOperateurScalaire($filtre);
                        }
                }
        }
        
        private function traiterOperateurScalaire($filtre) {
                $nomOperateur = $filtre->tagName;
                $champ  = $filtre->childNodes->item(0)->nodeValue;
                if ($champ != Config::get('champ_filtrage_wfs')) {
                        $message = "Le filtre ne peut pas être appliqué sur le champ '$champ'. ".
                                        "Il est seulement accepté sur le champ '".Config::get('champ_filtrage_wfs')."'";
                        throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                } else {
                        $valeur = $filtre->childNodes->item(1)->nodeValue;
                        $operateur =  $nomOperateur == 'PropertyIsEqualTo' ? "=" : "LIKE";
                        $this->parametresRecherche->filtre = array("champ" => $champ, "operateur" => $operateur,
                                        "valeur" => $valeur);
                }
        }
        
        private function recupererStationsWfs() {
                $this->nomMethode = $this->ressources[0];
                foreach ($this->parametresRecherche->sources as $source) {
                        $source = trim($source);
                        $resultat = $this->traiterSource($source);
                        $this->ajouterResultat($resultat, $source);
                }
        }
        
        
                
        /*********************************************/
        // Verification parametres URL non-WFS
        
        private function traiterRequeteNavigateur() {
                $retour = null;
                try {
                        if (!$this->estParametreSourceExistant()) {
                                $message = "Le paramètre source de données n'a pas été indiqué.";
                                throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                        } else {
                                $this->verifierParametres();
                                $listeSources = explode(',', $this->parametres['source']);
                                foreach ($listeSources as $source) {
                                        $source = trim($source);
                                        $resultat = $this->traiterSource($source);
                                        $this->ajouterResultat($resultat, $source);
                                }
                        }
                        $formateur = new FormateurJson();
                        $nomMethode = 'formater'.ucfirst($this->ressources[0]);
                        $retour = new ResultatService();
                        $retour->corps = $formateur->$nomMethode($this->retour);
                } catch (Exception $erreur) {
                        $retour = $erreur;
                }
                return $retour;
        }
        
        private function recupererRessourcesEtParametres($ressources, $parametres) {
                $this->ressources = $ressources;
                $this->parametres = array();
                foreach ($parametres as $nomParametre => $valeur) {
                        $this->parametres[strtolower($nomParametre)] = $valeur;
                }
        }
        
        private function estParametreSourceExistant() {
                $parametreExiste = false;
                if (isset($this->parametres['source'])) {
                        $parametreExiste = true;
                }
                return $parametreExiste;
        }
        
        private function verifierExistenceSourcesDonnees($source) {
                $sourcesDisponibles = explode(',', Config::get('sources_dispo'));
                $estDisponible = false;
                if (in_array($source, $sourcesDisponibles)) {
                        $estDisponible = true;
                }
                return $estDisponible;
        }
        
        private function verifierParametres() {
                $this->verificateur = new VerificateurParametres($this->parametres);
                $this->verificateur->verifierParametres();
                if ($this->verificateur->contientErreurs()) {
                        $this->verificateur->leverException();
                } else {
                        $this->recupererParametresRecherche();
                }
        }
        
        private function traiterSource($source) {
                $retour = array();
                if (!$this->verifierExistenceSourcesDonnees($source)) {
                        $message = "Source de donnees indisponible";
                        throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
                } else {
                        $this->chargerNomService($source);
                        $retour = $this->executerServicePourSource($source);
                }
                return $retour;
        }
        
        private function recupererParametresRecherche() {
                $this->parametresRecherche = $this->verificateur->renvoyerResultatVerification();
        }
        
        private function chargerNomSource($source) {
                if (isset($this->parametres['source'])) {
                        $this->nomSource = $this->parametres['source'];
                } else {
                        $this->nomSource = Config::get('source_defaut');
                }
        }
        
        private function chargerNomService($source) {
                $this->nomService = ($source == 'floradata' ? 'Floradata' : 'Moissonnage').'Formateur';
                Projets::chargerConfigurationSource($source);
        }
                
        private function executerServicePourSource($source) {
                $objetTraitement = new $this->nomService($this->parametresRecherche, $source);
                $methode = $this->genererNomMethodeAExecuter();
                return $objetTraitement->$methode();
        }
        
        private function genererNomMethodeAExecuter() {
                return 'recuperer' . ucfirst($this->ressources[0]);
        }
        
        
        private function ajouterResultat(& $resultat, $source) {
                if (count($this->retour) > 0) {
                        if ($this->ressources[0] == 'stations' && count($resultat) > 0
                                && $this->doitTransformerTypeDonnees($resultat)) {
                                $this->combinerResultats($resultat, $source);
                        } else {
                                $this->retour = array_merge($this->retour, $resultat);
                        }
                } else {
                        $this->retour = array_merge($this->retour, $resultat);
                }
        }
        
        private function doitTransformerTypeDonnees(& $resultat) {
                return ($this->parametresRecherche->zoom <= Config::get('zoom_maximal_maillage') && 
                        (($resultat[0]['type_site'] == 'MAILLE' || $this->retour[0]['type_site'] == 'MAILLE')
                        || ($resultat[0]['type_site'] != 'MAILLE' && $this->retour[0]['type_site'] != 'MAILLE'
                                && count($resultat) + count($this->retour) > Config::get('seuil_maillage')))
                );
        }
        
        private function combinerResultats(& $resultat, $source) {
                $maillage = new Maillage($this->parametresRecherche->bbox, $this->parametresRecherche->zoom, $source);
                $maillage->genererMaillesVides();
                if ($resultat[0]['type_site'] == 'MAILLE') {
                        $maillage->ajouterMailles($resultat);
                } else {
                        $maillage->ajouterStations($resultat);
                }
                if ($this->retour[0]['type_site'] == 'MAILLE') {
                        $maillage->ajouterMailles($this->retour);
                } else {
                        $maillage->ajouterStations($this->retour);
                }
                $this->retour = $maillage->formaterSortie();
        }

}

?>