Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 837 | Blame | Last modification | View Log | RSS feed

<?php
/**
* Description :
* Classe MetaDonnees.php fournit des informations sur le projet.
* Le but étant de fournir un ensemble minimal d'information comprenant :
* la version, la langue, le nom, le créateur et l'éditeur du projet.
* Si l'url finit par /meta-donnees on retourne une liste de termes (seulement les 100 premières par défaut).
* L'url peut contenir des paramètres optionnels passés après le ? : /meta-donnees?param1=val1&param2=val2&...
*
* Les paramètres de requête disponibles sont : masque, , recherche,
* distinct, retour.format, navigation.depart et navigation.limite.
*
* Encodage en entrée : utf8
* Encodage en sortie : utf8
* @package framework-v3
* @author Jennifer Dhé <jennifer.dhe@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-${year} Tela Botanica (accueil@tela-botanica.org)
*/

class MetaDonnees extends Commun {

        protected $requete_champ = '*';
        protected $requete_condition = null;
        protected $retour_format = 'max';
        protected $table_retour = array();
        protected $format_reponse = 'metaDonnees';
        protected $table_ressources;
        static $cache_ontologies = array();


        public function consulter($ressources, $parametres) {
                $this->ressources = $ressources;
                $this->parametres = $parametres;
                $this->service = 'meta-donnees';

                $resultats = '';
                // on traite en premier la version dans le cas ou un langage est demandé pr une version
                $this->traiterVersionProjet();
                $this->traiterParametres($parametres);
                $this->traiterRessources($ressources);
                if ($this->corps_http == '' && $this->entete_http == '') {
                        $requete_meta  = $this->assemblerLaRequete();
                        $resultat_meta = $this->getBdd()->recupererTous($requete_meta);
                        $resultats = $this->formerResultat($resultat_meta, $requete_meta);
                }
                return $resultats;
        }

        public function formerResultat($resultat_meta, $requete_meta) {
                if ($resultat_meta == '') {
                        $e = 'La requête formée comporte une erreur!';
                        $this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE,$e);
                        Debug::printr($requete);
                } elseif ($resultat_meta) {
                        $resultat_formate = $this->retournerResultatFormate($resultat_meta);
                } else {
                        $m = "Données introuvables dans la base $this->table";
                        $this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $m);
                        Debug::printr($requete_meta);
                }
                return $resultat_formate;
        }

//--------------------FONCTIONS TRAITEMENT DES PARAMETRES---------------------------------------------------------------

        public function traiterParametres($parametres) {
                if (isset($parametres) && !empty($parametres)) {
                        foreach ($parametres as $param => $val) {
                                switch ($param) {
                                        case 'version.projet' : $this->ajouterFiltreVersion($val);      break;
                                        case 'retour.langue' : $this->rechercherLangueDispo($val);      break;
                                        case 'retour.format' : $this->retour_format = $val;                     break;
                                        default                          :
                                                $e = 'Erreur dans les paramètres de recherche de votre requête : </br> Le paramètre " '
                                                        .$param.' " n\'existe pas.';
                                                $this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $e);
                                                break;
                                }
                        }
                }
        }

        /** Détermine quelles métadonnées doivent etre retournées :
        *  - "*" : (/#projet/* /meta-donnees) Renvoi les meta-données de toutes les versions du projet
        *  - "numero de la version" : (/#projet/2.00/meta-donnees) Renvoi les meta-données de la version 2.00 du projet
        *  - non renseignée : (/#projet/meta-donnees) Renvoi les meta-données de la dernière version du projet
        *  Cette info est stockée dans par la classe RestServeur dans la variable $ressources ($ressources[0])
        */
        public function ajouterFiltreVersion($val) {
                if (preg_match('/(?:[0-9]+(?:_|[.])[0-9]+|[*]| )/', $val)) {
                        $this->version_projet = ($val == ' ') ? '+' : $val;
                }
                switch ($this->version_projet) {
                        case '+' :
                                $this->requete_condition[] = 'version = (SELECT MAX(version) FROM '.Config::get('bdd_table_meta').')';
                                break;
                        case '*' :
                                break;
                        default :
                                if (is_numeric($this->version_projet)) {
                                        $versions_dispo = $this->rechercherVersionsDispos();
                                        if (in_array($val, $versions_dispo)) {
                                                $this->requete_condition[] = 'version = '.$this->getBdd()->proteger($val);
                                        } else {
                                                $e = 'La version demandée n\'existe pas actuellement. </br>Les versions disponibles sont : '
                                                .implode(', ', $versions_dispo);
                                                $this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $e);
                                        }
                                }
                                break;
                }
        }

        /**
        * Vérifie que le numéro de la version passée en paramètre correspond à une version existante.
        * Si oui remplit la condition de la requete SQL
        */
        public function rechercherVersionsDispos() {
                $val = str_replace('_', '.', $this->version_projet);
                $req_version = 'SELECT version FROM '.Config::get('bdd_table_meta');
                $res_version = $this->getBdd()->recupererTous($req_version);
                foreach ($res_version as $version) {
                        $versions_dispo[] = $version['version'];
                }
                return $versions_dispo;
        }

        /** Vérifie que les meta-donnees existe dans la langue passée en paramètre, Si oui remplit la condition de la requete SQL */
        public function rechercherLangueDispo($val) {
                //on recherche les langues_meta disponibles pour la version demandée : (d'ou ajout de la condition)
                $req_langue = 'SELECT langue_meta FROM '
                .Config::get('bdd_table_meta')
                .$this->formerRequeteCondition();
                $res_langue = $this->getBdd()->recupererTous($req_langue);
                foreach ($res_langue as $langue) {
                        $langue_dispo[] = $langue['langue_meta'];
                }
                if (in_array($val, $langue_dispo)) {
                        $this->requete_condition[] = 'langue_meta = '.$this->getBdd()->proteger($val);
                } else {
                        $e = 'La langue demandée n\'existe pas actuellement. </br>Les langues disponibles sont : '
                        .implode($langue_dispo);
                        $this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $e);
                }
        }
//----------------------FONCTIONS TRAITEMENT DES RESSOURCES-------------------------------------------------------------

        public function traiterRessources($ressources) {
                // /meta-donnees (liste des meta-données. Toutes les info de la table sont affichées) ou /meta-donnees/#champ
                if (isset($ressources) && !empty($ressources)) {
                        $this->table_ressources = $ressources;
                        if (isset($ressources) && !empty($ressources)) {
                                $this->format_reponse = 'metaDonnees/champ';
                        }
                }
        }

//------------------------------Fonction d'assemblage de la requete------------------------------------------------------

        public function assemblerLaRequete() {
                $req = 'SELECT '.$this->requete_champ.' FROM '.Config::get('bdd_table_meta').$this->formerRequeteCondition();
                return $req;
        }

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

//--------------------------------------Fonction de formatage des resultats ---------------------------------------------

        public function retournerResultatFormate($resultat) {
                switch ($this->format_reponse) {
                        case 'metaDonnees/champ' : $reponse = $this->formaterMetaDonneesChamp($resultat);       break;
                        case 'metaDonnees'               : $reponse = $this->formaterMetaDonnees($resultat);            break;
                        default                                  :                                                                                                                      break;
                }
                return $reponse;
        }

//--------------------------------------Fonction de formatage des resultats de /metaDonnees/----------------------------

        public function formaterMetaDonnees($resultat) {
                foreach ($resultat as $version) {
                        foreach ($version as $key => $val) {
                                if ($val != '') {
                                        $this->afficherDonnees($key, $val);
                                }
                        }
                        if ($this->retour_format == 'max' && $this->version_projet == '*') {
                                $this->table_retour['href'] = Config::get('url_service_base').Config::get('nom_projet')
                                                                                         .'/'.$version['version'].'/'.$this->serviceNom;
                        }
                        $table[] = $this->table_retour;
                        $this->table_retour = array();
                }
                return $table;
        }


        public function afficherDonnees($key, $valeur) {
                if ($valeur != '') {
                        $tab = array();
                        if ($this->retour_format == 'min') {
                                if (in_array($key, array('editeur','createurs', 'contributeurs','couverture_spatiale','couverture_temporelle'))) {
                                        //Pour les données comprenant plusieurs infos (...=...,...=...;...)
                                        $tab = $this->recupererTableauResultat($valeur);
                                        $this->afficherConcatenationValeur($key, $tab);
                                } else {
                                        $this->table_retour[$key] = trim($valeur);
                                }
                        } else {
                                if (in_array($key, array('editeur','createurs', 'contributeurs','couverture_spatiale','couverture_temporelle','langue','langue_meta'))) {
                                        $tab = $this->recupererTableauResultat($valeur);
                                        $this->afficherConcatenationValeur($key, $tab);
                                        $this->afficherDonneesMax($key,$valeur,$tab);
                                } else {
                                        $this->table_retour[$key] = trim($valeur);
                                }
                        }
                }
        }

        /**
         * Recupère à partir de la valeur du champ les différentes informations séparées par ';' (stocke ds un tableau)
         * pour éditeurs, créateurs, contributeurs,...
         * (ex : nom=Tela Botanica,guid=urn:lsid:tela-botanica.org,courriel=accueil@tela-botanica.org,...
         */
        public function recupererTableauResultat($val) {
                $tab = array();
                $num_entite = 0;
                // découpe chaque participant
                $tab_entites = explode(';', $val);
                foreach ($tab_entites as $entite) {
                        $tab[$num_entite] = array();
                        if ($entite != '') { // découpe les informations du participant
                                $entite_detail = explode(',', $entite);
                                foreach ($entite_detail as $detail) {
                                        if ($detail != '') {
                                                if (preg_match('/^([^=]+)=([^=]*)$/', $detail, $match)) {
                                                        $tab[$num_entite][$match[1]] = $match[2];
                                                } else {
                                                        $tab[$num_entite][] = $detail;
                                                }
                                        }
                                }
                        }
                        $num_entite++;
                }
                return $tab;
        }


        /** Retourne :
         *  - le nom de l'editeur
         *  - les coordonnées de l'éditeur sous la forme [latitude]N,[longitude]S [datum]
         *  - la couverture temporelle sous la forme xxxx à xxxx
         *  - la concaténation des noms pour les contributeurs et les créateurs (machin chouette, truc bidule...)
         *  - la liste des liste des couvertures spatiales (le nom et pas le code) (France, allemagne..) */
        public function afficherConcatenationValeur($champ, $tab) {
                if (strrpos($champ, '.coordonnees') !== false) {
                        if (isset($tab[0]['latitude']) && isset($tab[0]['longitude']) && isset($tab[0]['datum'])) {
                                $this->table_retour[$champ] = $tab[0]['latitude'].' N, '.$tab[0]['longitude'].' S ['.$tab[0]['datum'].']';
                        }
                } else {
                        $concat = '';
                        foreach ($tab as $entite) {
                                foreach ($entite as $key => $val) {
                                        if ($champ == 'couverture_spatiale') {
                                                        $concat .= ', '.$this->ajouterSignification($champ, $val);
                                        } else {
                                                if (strrpos($key, '.prenom') !== false) {
                                                        $concat .= ', '.$val;
                                                } elseif (strrpos($key, 'nom') !== false) {

                                                        $concat .= ' '.$val;
                                                        break;
                                                }
                                        }
                                }
                        }
                        $res = trim($concat, ',');
                        $res = trim($res);
                        if ($champ == 'couverture_temporelle') $res = str_replace(' ', ' à ',$res);
                        $this->table_retour[$champ] = $res;
                }
        }


        public function afficherDonneesMax($champ,$valeur,$tab) {
                switch ($champ) {
                        case 'couverture_temporelle' : $this->afficherInfosPrecises($champ, 'start,end', $valeur, $tab);                break;
                        case 'langue'                            : $this->afficherInfosPrecises($champ,'signification,code,href', $valeur); break;
                        case 'langue_meta'                       : $this->afficherInfosPrecises($champ,'signification,code,href', $valeur); break;
                        case 'couverture_spatiale'       : $this->afficherInfosPrecises($champ, 'details', $valeur, $tab);                      break;
                        case 'createurs'                         : $this->afficherInfosPrecises($champ, 'details', $valeur, $tab);                      break;
                        case 'contributeurs'             : $this->afficherInfosPrecises($champ, 'details', $valeur, $tab);                      break;
                        case 'editeur'                           : $this->afficherEditeur($champ, $tab);                                                                        break;
                        default                                          : $this->table_retour[$champ] = $valeur;                                                                       break;
                }
        }


        public function afficherEditeur($key, $tab) {
                // infos générales sur l'éditeur
                foreach ($tab[0] as $k => $val) {
                        if ((strrpos($k, 'contact.') === false) && (strrpos($k, '.wgs84') === false)) {
                                $this->table_retour[$key.'.'.$k] = $val;
                        }
                }
                //on récupère dans un premier temps les tableaux des coordonnées.
                $table_coordonnees = $this->recupererTableCoordonnees($tab);
                //on affiche les informations sur les coordonnees : concaténation + détails
                if ($table_coordonnees[0] != array()) {
                        $this->afficherConcatenationValeur($key.'.coordonnees', $table_coordonnees);
                        if (isset($table_coordonnees[0]['datum'])) {
                                $this->afficherInfosPrecises($key.'.coordonnees.datum',
                                        'signification,code,href',$table_coordonnees[0]['datum'],
                                        $table_coordonnees);
                        }
                }
                $table_contact = $this->recupererTableContact($tab);
                //on affiche le premier contact en dehors de la table de détail:
                if ($table_contact[0] != array()) {
                        $this->table_retour[$key.'.contact'] = '';
                        foreach ($table_contact as $info => $valeur) {
                                $this->table_retour[$key.'.contact'] .= $valeur['contact.prenom']." ".$valeur['contact.nom'];
                        }
                        //on affiche les détails des autres contacts :
                        $this->afficherTableDetails($key.'.contact', $table_contact);
                }
        }



        public function afficherInfosPrecises($champ, $pts, $val, $tab = null) {
                //permet d'afficher les informations précises telles que les .details, .start, .end...
                $pts = explode(',', $pts);
                foreach ($pts as $pt) {
                        switch ($pt) {
                                case 'start' :
                                        if (isset($this->table_retour[$champ.'.start'])) {
                                                $this->table_retour[$champ.'.start'] = $tab['start'];
                                        }
                                        break;
                                case 'end' :
                                        if (isset($this->table_retour[$champ.'.end'])) {
                                                $this->table_retour[$champ.'.end'] = $tab['end'];
                                        }
                                        break;
                                case 'code' :
                                        $this->table_retour[$champ.'.code'] = $val;
                                        break;
                                case 'href' :
                                        $this->table_retour[$champ.'.href'] = $this->ajouterHrefAutreProjet($champ, '', $val);
                                        break;
                                case 'signification' :
                                        $this->table_retour[$champ] = $this->ajouterSignification($champ, $val);
                                        break;
                                case 'details' :
                                        if ($champ == 'couverture_spatiale') {
                                                $this->afficherCouvertureSpatiale($champ, $tab);
                                        } else {
                                                $this->afficherTableDetails($champ, $tab);
                                        }
                                        break;
                                default :
                                        $this->table_retour[$champ.'.'.$pt] = $tab[$pt];
                        }
                }
        }



        public function afficherCouvertureSpatiale($key, $tab) {
                $res = $this->table_retour;
                $this->table_retour = array();
                foreach ($tab as $iso) {
                        foreach ($iso as $val) {
                                $this->afficherInfosPrecises($key, 'signification,code,href',$val);
                                $res[$key.'.detail'][] = $this->table_retour;
                                $this->table_retour = array();
                        }
                }
                $this->table_retour = $res;
        }

        public function afficherTableDetails($champ, $tab) {
                $res = $this->table_retour;
                $this->table_retour = array();
                foreach ($tab as $num_entite => $entite) { // $t et $type valent p ou o
                        $t = '';
                        $type = '.';
                        foreach ($entite as $key => $infos) {
                                list($type, $info) = explode('.', trim($key));
                                if ($type == 'contact') $type = 'p';
                                if ($type != $t) { // cherche et ajoute la signification du type
                                        $this->afficherInfosPrecises('type', 'signification,code,href', trim($type));
                                        foreach ($this->table_retour as $k => $val) {
                                                $res[$champ.'.details'][$num_entite][$type.'.'.$k] = $val;
                                        }
                                        $table_retour = array();
                                        $this->table_retour = array(); // rempli par afficherInfosPrecises
                                        $t = $type;
                                }
                                $res[$champ.'.details'][$num_entite][$key] = $infos;
                        }
                }
                $this->table_retour = $res;
        }

        public function ajouterSignification($champ, $val, $nom = 'nom') {
                $url = $this->ajouterHrefAutreProjet($champ, '', $val);
                if (in_array($champ, array('langue', 'langue_meta', 'couverture_spatiale'))) {
                        $url .= '/'.$nom;
                }
                if(array_key_exists($url, self::$cache_ontologies)) {
                        return self::$cache_ontologies[$url];
                }
                $signification = $this->consulterHref($url);
                if (isset($signification->$nom)) {
                        $res = $signification->$nom;
                } else {
                        $nom = 'nom.fr';
                        $res = $signification->$nom;
                }
                self::$cache_ontologies[$url] = $res;
                return $res ;
        }


        public function recupererTableContact(&$tab) {
                $res = array();
                foreach ($tab[0] as $key => $val) {
                        if (strrpos($key, 'contact.') !== false) {
                                while (array_key_exists($key, $res)) { $key = ' '.$key; }
                                $res[$key] = $val;
                                unset($tab[0][$key]); //suppression des premiers contacts qui seront affichés après
                        }
                }
                $resultat[0] = $res;
                return $resultat;
        }


        public function recupererTableCoordonnees(&$tab) {
                $res = array();
                foreach ($tab[0] as $key => $val) {
                        if (strrpos($key, 'latitude') !== false || strrpos($key, 'longitude') !== false) {
                                list ($coord, $datum) = explode('.', $key);
                                $res[$coord]  = $val;
                                $res['datum'] = $datum;
                        }
                }
                $resultat[0] = $res;
                return $resultat;
        }

//-------------------------------------Fonction de formatage des resultats de /metaDonnees/#champs+champs----------------

        public function formaterMetaDonneesChamp($resultat) {
                $this->recupererNomChamp(Config::get('bdd_table_meta'));
                //On récupère dans un premier temps toutes les données existantes puis on pioche les champs recherchés
                $table_Meta = $this->formaterMetaDonnees($resultat);
                foreach ($table_Meta as $version) {
                        //on affiche les informations par defaut : la version, la langue_meta et le guid :
                        $this->afficherVersionLangueMetaGuid($version);
                        $tab_ress = explode(' ', $this->table_ressources[0]);
                        foreach ($tab_ress as $champ) {//on recupere le radical pour comparaison avec les nom des champs de la bdd :
                                $this->afficherChampRecherche($champ, $version);
                        }
                        $table[] = $this->table_retour;
                        $this->table_retour = array();
                }
                return $table;
        }

        public function afficherChampRecherche(&$champ, &$version) {
                preg_match('/^([^.]+)(?:[.][^.]+)?$/', $champ, $match);
                if (preg_match('/(.+)[.][*]$/', $champ, $match_2)) {
                        $this->afficherPointEtoile($match_2, $version, $champ);
                } elseif (array_key_exists($champ, $version)) {
                        $this->table_retour[$champ] = $version[$champ];
                } elseif (in_array($match[1], $this->champs_table)) {
                        //si le champ est vide dans cette version on retourne null (comparaison avec les champs existants)
                        $this->table_retour[$champ] = null;
                } else {
                        $champs = implode('</li><li>', array_keys($version));
                        $e = 'Erreur dans votre requête : </br> Le champ "'.$champ.'" n\'existe pas'.
                                '. Les champs disponibles sont : <li>'.$champs.'</li>';
                        $this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $e);
                }
        }

        public function afficherPointEtoile($match, $version, $ressource) {
                $existe = false;
                foreach ($version as $key => $valeur) {
                        if (strrpos($key, $match[1].'.') !== false) {
                                $this->table_retour[$key] = $valeur;
                                $existe = true;
                        }
                }
                if (!$existe) {
                        $champs = implode('</li><li>', array_keys($version));
                        $e = 'Erreur dans votre requête : </br> Le champ " '.$ressource.' " n\'existe pas dans la version '
                                .$version['version'].'. Les champs disponibles sont : <li>'.$champs.'</li>';
                        $this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $e);
                }
        }

        public function afficherVersionLangueMetaGuid(&$version) {
                $this->table_retour['version'] = $version['version'];
                $this->table_retour['langue_meta'] = $version['langue_meta'];
                $this->table_retour['guid'] = $version['guid'];
        }
}