* @author Jean-Pascal MILCENT * @author Aurelien PERONNET * @license GPL v3 * @license CECILL v2 * @copyright 1999-2015 Tela Botanica */ class Saisie extends WidgetCommun { const DS = DIRECTORY_SEPARATOR; const PROJET_DEFAUT = 'defaut'; const WS_SAISIE = 'CelWidgetSaisie'; const WS_UPLOAD = 'CelWidgetUploadImageTemp'; const WS_OBS = 'CelObs'; const WS_NOM = 'noms'; const EFLORE_API_VERSION = '0.1'; const REFERENTIEL_DEFAUT = 'bdtfxr'; /** référentiel utilisé pour la complétion des noms scientifiques */ protected $ns_referentiel; /** mot-clé associé aux saisies, et template personnalisé si appliquable */ protected $projet = null; protected $configProjet = null; protected $configMission = null; protected $mission = null; /** langue (traduction), charge un template de la forme "defaut_en.tpl.html" */ protected $langue = null; /** * Amorçage du widget */ public function executer() { // paramètres par défaut $this->ns_referentiel = self::REFERENTIEL_DEFAUT; $this->projet = self::PROJET_DEFAUT; // définition du projet / mission if (isset($this->parametres['projet']) && trim($this->parametres['projet']) != "") { $projets = explode(',', $this->parametres['projet']); $this->projet = strtolower($projets[0]); } $this->chargerConfigProjet(); // définition de la langue, en mode souple if (isset($this->parametres['lang'])) { $this->langue = $this->parametres['lang']; } // exécution du service (le widget entier ou une sous-partie, par ex "Taxons") $retour = null; $service = isset($this->parametres['service']) ? $this->parametres['service'] : 'widget'; $methode = $this->traiterNomMethodeExecuter($service); if (method_exists($this, $methode)) { $retour = $this->$methode(); } else { $this->messages[] = "Le service '$methode' n'est pas disponible."; } // injection des données dans le squelette $contenu = null; $mime = null; if (is_array($retour) && array_key_exists('squelette', $retour)) { $ext = (isset($retour['squelette_ext'])) ? $retour['squelette_ext'] : '.tpl.html'; // Suffixe de template pour la langue - fr par défaut @TODO configurer ça un jour $suffixeLangue = ""; // Si "nolang" n'est pas vide, on ne cherchera pas de squelette spécifique à la langue en cours if ($this->langue != null && $this->langue != "fr" && empty($retour['nolang'])) { $suffixeLangue = "_" . $this->langue; } // Template par défaut ou spécifique if ($this->projetASquelette()) { $squelette = dirname(__FILE__).self::DS.'squelettes'.self::DS.$this->projet.self::DS.$retour['squelette'].$suffixeLangue.$ext; } else { $squelette = dirname(__FILE__).self::DS.'squelettes'.self::DS.'defaut'.self::DS.'defaut'.$suffixeLangue.$ext; } $contenu = $this->traiterSquelettePhp($squelette, $retour['donnees']); $mime = isset($retour['mime']) ? $retour['mime'] : null; } else { if (count($this->messages) == 0) { $this->messages[] = "La méthode du sous-service ne renvoie pas les données dans le bon format"; } $contenu = 'Un problème est survenu : ' . print_r($this->messages, true); } // envoi de la page $this->envoyer($contenu, $mime); } /** * Charge le fichier de configuration associé au projet : configurations/nomduprojet.ini * Si une mission est définie, charge séparément la section de la configuration concernant * cette mission : [nommission] */ protected function chargerConfigProjet() { $fichier_config = dirname(__FILE__).self::DS.'configurations'.self::DS.$this->projet.'.ini'; if (file_exists($fichier_config)) { if ($this->configProjet = parse_ini_file($fichier_config, true)) { if (isset($_GET['mission'])) { $this->mission = strtolower(trim($_GET['mission'])); if (isset($this->configProjet[$this->mission])) { $this->configMission = $this->configProjet[$this->mission]; } } } else { $this->messages[] = "Le fichier de configuration '$fichier_config' n'a pu être chargé."; } } else { $this->debug[] = "Le fichier de configuration '$fichier_config' n'existe pas."; } } /** * Retourne true si le dossier du projet courant existe, false sinon * @return boolean */ protected function projetASquelette() { return file_exists(dirname(__FILE__).self::DS.'squelettes'.self::DS.$this->projet); } /** * Exécution du widget complet * @return Ambigous */ public function executerWidget() { $widget['squelette'] = $this->projet; $widget['donnees'] = array(); $widget['donnees']['url_base'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], ''); $widget['donnees']['url_ws_saisie'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_SAISIE); $widget['donnees']['url_ws_obs'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_OBS); $widget['donnees']['url_ws_upload'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_UPLOAD); $widget['donnees']['url_ws_annuaire'] = sprintf($this->config['chemins']['baseURLServicesAnnuaireTpl'], 'utilisateur/identite-par-courriel/'); $widget['donnees']['url_remarques'] = $this->config['chemins']['widgetRemarquesUrl']; $widget['donnees']['logo'] = $this->getLogoPage(); $widget['donnees']['titre'] = $this->getTitrePage(); $widget['donnees']['nom_mission'] = $this->getNomMissionFlore(); $widget['donnees']['zone_geo'] = $this->getZoneGeo(); $widget['donnees']['groupe_zones_geo'] = $this->getGroupeZonesGeo(); $widget['donnees']['referentiel_impose'] = $this->getReferentielImpose(); $widget['donnees']['espece_imposee'] = false; $widget['donnees']['nn_espece_defaut'] = ''; $widget['donnees']['nom_sci_espece_defaut'] = ''; $widget['donnees']['infos_espece'] = '{}'; $widget['donnees']['prod'] = ($this->config['parametres']['modeServeur'] == "prod"); $widget['donnees']['cleGoogleMaps'] = $this->config['api']['cleGoogleMapsSaisie']; $projetsAutorises = $this->transformerEnTableau($this->config['projets']['autorises']); $urlWsNsTpl = $this->config['chemins']['baseURLServicesEfloreTpl']; $urlWsNs = sprintf($urlWsNsTpl, self::EFLORE_API_VERSION, $this->ns_referentiel, self::WS_NOM); $urlWsNsSansRef = sprintf($urlWsNsTpl, self::EFLORE_API_VERSION, '{referentiel}', self::WS_NOM); $widget['donnees']['url_ws_autocompletion_ns'] = $urlWsNs; $widget['donnees']['url_ws_autocompletion_ns_tpl'] = $urlWsNsSansRef; $widget['donnees']['ns_referentiel'] = $this->ns_referentiel; $widget['donnees']['url_ws_coord_search_tpl'] = $this->config['chemins']['serviceCoordSearchUrl']; $widget['donnees']['url_ws_trace_rue_tpl'] = $this->config['chemins']['serviceTraceRueUrl']; if ($this->especeEstImposee()) { $nnEspeceImposee = $this->getNnEspeceImposee(); $nom = $this->chargerInfosTaxon($nnEspeceImposee); $widget['donnees']['espece_imposee'] = true; $widget['donnees']['nn_espece_defaut'] = $nnEspeceImposee; $widget['donnees']['nom_sci_espece_defaut'] = $nom['nom_complet']; $widget['donnees']['infos_espece'] = $this->array2js($nom, true); } $projetsAListeDeNoms = $this->transformerEnTableau($this->config['projets']['liste_noms']); if (in_array($this->projet, $projetsAListeDeNoms) && !$this->especeEstImposee()) { $projetsAListeDeNomsSciEtVerna = $this->transformerEnTableau($this->config['projets']['liste_noms_sci_et_verna']); if (in_array($this->projet, $projetsAListeDeNomsSciEtVerna)) { $widget['donnees']['taxons'] = $this->recupererListeNoms(); } else { $widget['donnees']['taxons'] = $this->recupererListeNomsSci(); } } // Chargement de la liste des milieux issues du fichier .ini du projet $projetsAListeDeMilieux = $this->transformerEnTableau($this->config['projets']['liste_milieux']); if (in_array($this->projet, $projetsAListeDeMilieux)) { $widget['donnees']['milieux'] = $this->parserMilieux(); } return $widget; } protected function getTitrePage() { $titre = 'defaut'; if (isset($this->configProjet['titre_page'])) { $titre = $this->configProjet['titre_page']; } if (isset($this->configMission['titre_page'])) { $titre = $this->configMission['titre_page']; } if (isset($_GET['titre'])) { $titre = $_GET['titre']; } if ($titre === 0) { // wtf ? $titre = ''; } return $titre; } protected function getLogoPage() { $logo = 'defaut'; if (isset($this->configProjet['logo_page'])) { $logo = $this->configProjet['logo_page']; } if (isset($this->configMission['logo_page'])) { $logo = $this->configMission['logo_page']; } if (isset($_GET['logo'])) { $logo = $_GET['logo']; } return $logo; } protected function getGroupeZonesGeo() { $groupe = null; if (isset($_GET['groupe_zones_geo'])) { $groupe = $_GET['groupe_zones_geo']; } return $groupe; } protected function getZoneGeo() { $zone_geo = null; if (isset($_GET['zone_geo'])) { $zone_geo = $_GET['zone_geo']; } return $zone_geo; } protected function getReferentielImpose() { $referentiel_impose = true; if (!empty($_GET['referentiel']) && $_GET['referentiel'] != "autre") { $this->ns_referentiel = $_GET['referentiel']; } else if (isset($this->configProjet['referentiel'])) { $this->ns_referentiel = $this->configProjet['referentiel']; } else if (isset($this->configMission['referentiel'])) { $this->ns_referentiel = $this->configMission['referentiel']; } else { $referentiel_impose = false; } return $referentiel_impose; } /** * Un nom un peu plus sympatoche à afficher que juste le mot-clef associé; s'il * n'est pas défini dans la config, on prend le mot-clef tout de même */ protected function getNomMissionFlore() { $nom = $this->mission; if (isset($this->configMission['nom_mission'])) { $nom = $this->configMission['nom_mission']; } return $nom; } /** * Remplit un fichier JS avec une variable contenant une liste restreinte de taxons, * pour certains projets * @return string */ public function executerTaxons() { $widget['squelette'] = $this->projet.'_taxons'; $widget['squelette_ext'] = '.tpl.js'; $widget['donnees'] = array(); $nomsAAfficher = $this->recupererListeNomsSci(); $taxons_tries = array(); foreach ($nomsAAfficher as $taxon) { $taxons_tries[$taxon['num_nom_sel']] = $taxon; } $widget['donnees']['taxons'] = json_encode($taxons_tries); //echo "
"; var_dump($widget); echo "
"; // Le squelette n'est pas traduit, seules les données de taxons le sont $widget['nolang'] = true; return $widget; } /** * Trie par nom français les taxons lus dans le fichier tsv */ protected function recupererListeNomsSci() { $taxons = $this->recupererListeTaxon(); if (is_array($taxons)) { $taxons = self::trierTableauMd($taxons, array('nom_fr' => SORT_ASC)); } return $taxons; } /** * @TODO documenter * @return array */ protected function recupererListeNoms() { $taxons = $this->recupererListeTaxon(); $nomsAAfficher = array(); $nomsSpeciaux = array(); if (is_array($taxons)) { foreach ($taxons as $taxon) { $nomSciTitle = $taxon['nom_ret']. ($taxon['nom_fr'] != '' ? ' - '.$taxon['nom_fr'] : '' ). ($taxon['nom_fr_autre'] != '' ? ' - '.$taxon['nom_fr_autre'] : '' ); $nomFrTitle = $taxon['nom_sel']. ($taxon['nom_ret'] != $taxon['nom_sel']? ' - '.$taxon['nom_ret'] : '' ). ($taxon['nom_fr_autre'] != '' ? ' - '.$taxon['nom_fr_autre'] : '' ); if ($taxon['groupe'] == 'special') { $nomsSpeciaux[] = array( 'num_nom' => $taxon['num_nom_sel'], 'nom_a_afficher' => $taxon['nom_fr'], 'nom_a_sauver' => $taxon['nom_sel'], 'nom_title' => $nomSciTitle, 'nom_type' => 'nom-special'); } else { $nomsAAfficher[] = array( 'num_nom' => $taxon['num_nom_sel'], 'nom_a_afficher' => $taxon['nom_sel'], 'nom_a_sauver' => $taxon['nom_sel'], 'nom_title' => $nomSciTitle, 'nom_type' => 'nom-sci'); $nomsAAfficher[] = array( 'num_nom' => $taxon['num_nom_sel'], 'nom_a_afficher' => $taxon['nom_fr'], 'nom_a_sauver' => $taxon['nom_fr'], 'nom_title' => $nomFrTitle, 'nom_type' => 'nom-fr'); } } $nomsAAfficher = self::trierTableauMd($nomsAAfficher, array('nom_a_afficher' => SORT_ASC)); $nomsSpeciaux = self::trierTableauMd($nomsSpeciaux, array('nom_a_afficher' => SORT_ASC)); } return array('speciaux' => $nomsSpeciaux, 'sci-et-fr' => $nomsAAfficher); } /** * Lit une liste de taxons depuis un fichier tsv fourni */ protected function recupererListeTaxon() { $taxons = array(); $fichier_tsv = null; if ($this->projet == 'missions-flore') { $fichier_tsv = dirname(__FILE__).self::DS.'configurations'.self::DS.$this->projet.'_'.$this->mission.'_taxons.tsv'; } else { // recherche d'un fichier traduit (pour les noms vernaculaires) $suffixeLangue = ""; if ($this->langue != null && $this->langue != "fr") { $suffixeLangue = "_" . $this->langue; $fichier_tsv = dirname(__FILE__).self::DS.'configurations'.self::DS.$this->projet.'_taxons'.$suffixeLangue.'.tsv'; } // si le fichier de taxons traduit n'est pas disponible ou qu'on n'a // pas demandé de langue particulière, on se rabat sur celui par défaut if (! file_exists($fichier_tsv)) { $fichier_tsv = dirname(__FILE__).self::DS.'configurations'.self::DS.$this->projet.'_taxons.tsv'; } } if (file_exists($fichier_tsv) && is_readable($fichier_tsv)) { $taxons = $this->decomposerFichierTsv($fichier_tsv); } else { $this->debug[] = "Impossible d'ouvrir le fichier '$fichier_tsv'."; } return $taxons; } /** * Découpe un fihcier tsv */ protected function decomposerFichierTsv($fichier, $delimiter = "\t"){ $header = null; $data = array(); if (($handle = fopen($fichier, 'r')) !== FALSE) { while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) { if (!$header) { $header = $row; } else { $data[] = array_combine($header, $row); } } fclose($handle); } return $data; } /** * Récupère la liste des milieux depuis la section [milieux] de la configuration * du projet, si elle existe * @return array */ protected function parserMilieux() { $infosMilieux = array(); if (isset($this->configProjet['milieux'])) { $milieux = explode('|', $this->configProjet['milieux']); foreach ($milieux as $milieu) { $milieu = trim($milieu); $details = explode(';', $milieu); if (isset($details[1])) { $infosMilieux[$details[0]] = $details[1]; } else { $infosMilieux[$details[0]] = ''; } } ksort($infosMilieux); } return $infosMilieux; } /** * Retourne true si le widget est restreint à une espèce, false sinon * @return boolean */ protected function especeEstImposee() { return ((isset($_GET['num_nom']) && $_GET['num_nom'] != '') || isset($this->configProjet['sp_imposee']) || isset($this->configMission['sp_imposee'])); } /** * Retourne le numéro nomenclatural (nn) de l'espèce imposée si tel est * le cas, null sinon * @return string */ protected function getNnEspeceImposee() { $nn = null; if (isset($_GET['num_nom']) && is_numeric($_GET['num_nom'])) { $nn = $_GET['num_nom']; } else if (isset($this->configProjet['sp_imposee'])) { $nn = $this->configProjet['sp_imposee']; } else if (isset($this->configMission['sp_imposee'])) { $nn = $this->configMission['sp_imposee']; } return $nn; } /** * Consulte un webservice pour obtenir des informations sur le taxon dont le * numéro nomenclatural est $num_nom (ce sont donc plutôt des infos sur le nom * et non le taxon?) * @param string|int $num_nom * @return array */ protected function chargerInfosTaxon($num_nom) { $url_service_infos = sprintf($this->config['chemins']['infosTaxonUrl'], $this->ns_referentiel, $num_nom); $infos = json_decode(file_get_contents($url_service_infos)); // trop de champs injectés dans les infos espèces peuvent // faire planter javascript $champs_a_garder = array('id', 'nom_sci','nom_sci_complet', 'nom_complet', 'famille','nom_retenu.id', 'nom_retenu_complet', 'num_taxonomique'); $resultat = array(); if (isset($infos) && !empty($infos)) { $infos = (array)$infos; if (isset($infos['nom_sci']) && $infos['nom_sci'] != '') { $resultat = array_intersect_key($infos, array_flip($champs_a_garder)); $resultat['retenu'] = ($infos['id'] == $infos['nom_retenu.id']) ? "true" : "false"; } } return $resultat; } /** * Convertit un tableau PHP en Javascript - @WTF pourquoi ne pas faire un json_encode ? * @param array $array * @param boolean $show_keys * @return une portion de JSON représentant le tableau */ protected function array2js($array,$show_keys) { $tableauJs = '{}'; if (!empty($array)) { $total = count($array) - 1; $i = 0; $dimensions = array(); foreach ($array as $key => $value) { if (is_array($value)) { $dimensions[$i] = array2js($value,$show_keys); if ($show_keys) { $dimensions[$i] = '"'.$key.'":'.$dimensions[$i]; } } else { $dimensions[$i] = '"'.addslashes($value).'"'; if ($show_keys) { $dimensions[$i] = '"'.$key.'":'.$dimensions[$i]; } } if ($i == 0) { $dimensions[$i] = '{'.$dimensions[$i]; } if ($i == $total) { $dimensions[$i].= '}'; } $i++; } $tableauJs = implode(',', $dimensions); } return $tableauJs; } }