Rev 1977 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php// declare(encoding='UTF-8');/*** Permet d'ajouter un commentaire.** @category DEL* @package Services* @subpackage Commentaires* @version 0.1* @author Mathias CHOUET <mathias@tela-botanica.org>* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>* @author Aurelien PERONNET <aurelien@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>* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>*/class AjouterCommentaire {private $conteneur;private $navigation;private $bdd;private $parametres = array();private $mapping = array();private $erreurs = array();public function __construct(Conteneur $conteneur) {$this->conteneur = $conteneur;$this->navigation = $this->conteneur->getNavigation();$this->bdd = $this->conteneur->getBdd();$this->mapping = $this->conteneur->getParametreTableau('commentaires.mapping');}public function ajouter($parametres) {$this->parametres = $parametres;$this->verifierParametres();$this->completerParametresUtilisateur();$this->gererPropositionInitiale();// Dernière chance de rattachement au référentiel d'un nom// sans nn (cas du copier-coller ou bien de l'appli tierce// qui envoie des infos incomplètes)$this->tenterEnrichissementTaxonomique();$idCommentaireAjoute = $this->insererCommentaire();// Mettre en forme le résultat et l'envoyer pour affichage$resultat = new ResultatService();$resultat->corps = array('id_commentaire' => $idCommentaireAjoute);return $resultat;}/*** Vérifie notamment que l'auteur du vote est désigné soit par un ID, soit* par un triplet (nom, prénom, adresse courriel)*/private function verifierParametres() {if (!isset($this->parametres['observation'])) {$this->erreurs[] = "Impossible d'ajouter un commentaire sans identifiant d'observation (paramètre 'observation').";}if (!isset($this->parametres['auteur.id'])) {$this->verifierParamsAuteurAnonyme();}$this->verifierParamsNonVide();if (isset($this->parametres['nom_sel_nn']) && !isset($this->parametres['nom_referentiel'])) {$this->erreurs[] = "Si le paramètre «nom_sel_nn» est présent, le paramètre «nom_referentiel» doit l'être aussi.";}if (!empty($this->erreurs)) {$msg = "Erreur de configuration :\n".implode("\n\n", $this->erreurs);throw new Exception($msg, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);}}private function verifierParamsAuteurAnonyme() {$paramsAuteur = array('auteur.nom', 'auteur.prenom', 'auteur.courriel');$paramsAuteurManquant = array();foreach ($paramsAuteur as $param) {if (!isset($this->parametres[$param])) {$paramsAuteurManquant[] = $param;}}if (!empty($paramsAuteurManquant)) {$msgAuteurTpl = "Si le parametre 'auteur.id' n'est pas utilisé, il est nécessaire d'indiquer les "."nom (paramètre 'auteur.nom'), prénom (paramètre 'auteur.prenom') et courriel "."(paramètre 'auteur.courriel') de l'auteur.\nLes paramètres suivant sont abscents : %s\n";$this->erreurs[] = sprintf($msgAuteurTpl, implode(', ', $paramsAuteurManquant));}}private function verifierParamsNonVide() {$paramsNonVide = array('nom_sel', 'nom_referentiel', 'nom_sel_nn');foreach ($paramsNonVide as $param) {if (isset($this->parametres[$param]) && trim($this->parametres[$param]) == '' ) {$this->erreurs[] = "S'il est présent le paramètre «$param» ne peut pas être vide.";}}}/*** Si l'auteur du vote est désigné par un ID, va chercher ses nom, prénom, courriel;* s'il est désigné par un triplet (nom, prénom, adresse courriel), va chercher son ID*/private function completerParametresUtilisateur() {$utilisateur = (isset($this->parametres['auteur.id'])) ? $this->obtenirUtilisateurAvecId() : $this->obtenirUtilisateurSansId();if ($utilisateur != false) {foreach ($utilisateur as $param => $valeur) {$this->parametres[$param] = $valeur;}}}/*** On suppose que si l'utilisateur envoie sa proposition avec un ID, c'est* qu'il est connu d'IP, donc qu'on trouvera ses coordonnées dans* del_utilisateur_infos** @TODO valider cette hypothèse*/private function obtenirUtilisateurAvecId() {$auteurIdP = $this->bdd->proteger($this->parametres['auteur.id']);$requete = "SELECT id_utilisateur AS 'auteur.id', nom AS 'auteur.nom', prenom AS 'auteur.prenom', courriel AS 'auteur.courriel' ".'FROM del_utilisateur_infos '."WHERE id_utilisateur = $auteurIdP ".' -- '.__FILE__.' : '.__LINE__;$utilisateur = $this->bdd->recuperer($requete);return $utilisateur;}/*** Pour un utilisateur désigné par un triplet (nom, prenom, adresse courriel), demande* son ID à l'annuaire - vue la base de données (2017-03-24), aucun tuple ne contient* une adresse courriel sans contenir d'ID, mais beaucoup ne contiennent ni l'un ni* l'autre (code stupide, tentative de correction ajd)*/private function obtenirUtilisateurSansId() {$nomP = $this->bdd->proteger($this->parametres['auteur.nom']);$prenomP = $this->bdd->proteger($this->parametres['auteur.prenom']);$courrielP = $this->bdd->proteger($this->parametres['auteur.courriel']);// Si l'utilisateur s'est déjà connecté à DeL au moins une fois, on récupère ses// nom et prénom connus dans la base; on lui interdit d'usurper sa propre identité$requete = "SELECT id_utilisateur AS 'auteur.id', nom AS 'auteur.nom', prenom AS 'auteur.prenom', "."courriel AS 'auteur.courriel' ".'FROM del_utilisateur_infos '."WHERE courriel = $courrielP ".' -- '.__FILE__.' : '.__LINE__;$utilisateur = $this->bdd->recuperer($requete);// si l'utilisateur n'a pas été trouvé, on devrait aller le chercher dans// l'annuaire, au cas où il soit inscrit à TB mais ne se soit pas connecté// @TODO faire un appel au service annuaire/identite-par-courrielreturn $utilisateur;}private function gererPropositionInitiale() {if ($this->verifierExistencePropositionInitiale() === false) {$this->creerPropositionInitiale();// TODO : en cas d'échec de la création de la proposition ajouter un log...}}private function verifierExistencePropositionInitiale() {$idObsP = $this->bdd->proteger($this->parametres['observation']);$requete = 'SELECT COUNT(*) >= 1 AS existe '.'FROM del_commentaire '."WHERE ce_observation = $idObsP ".' AND proposition_initiale = 1 '.' -- '.__FILE__.' : '.__LINE__;$resultat = $this->bdd->recuperer($requete);return $resultat['existe'] == 1;}private function creerPropositionInitiale() {$idObsP = $this->bdd->proteger($this->parametres['observation']);$requete = 'INSERT IGNORE INTO del_commentaire '.'(ce_observation, ce_utilisateur, utilisateur_prenom, utilisateur_nom, utilisateur_courriel, '.'nom_sel, nom_sel_nn, nom_ret, nom_ret_nn, nt, famille, nom_referentiel, date, proposition_initiale) '.'SELECT id_observation, ce_utilisateur, prenom_utilisateur, nom_utilisateur, courriel_utilisateur, nom_sel, '."IF(nom_sel_nn = 0, NULL, nom_sel_nn), IF(nom_ret = '', NULL, nom_ret), IF(nom_ret_nn = 0, NULL, nom_ret_nn), "."IF(nt = 0, NULL, nt), IF(famille = '', NULL, famille), IF(nom_sel_nn = 0, NULL, nom_referentiel), NOW(), '1' ".'FROM del_observation AS do '."WHERE id_observation = $idObsP ".' -- '.__FILE__.' : '.__LINE__;$resultat = $this->bdd->executer($requete);return $resultat;}private function insererCommentaire() {$champs = $this->creerEnteteChamps();$values = $this->creerClauseValues();$requete = "INSERT INTO del_commentaire (date, $champs) VALUES (NOW(), $values) ".' -- '.__FILE__.' : '.__LINE__;$retour = $this->bdd->executer($requete);if ($retour == null) {$msgTpl = "Erreur inopinée lors de l'insertion du commentaire lié à l'observation «%s».";$msg = sprintf($msgTpl, $this->parametres['observation']);throw new Exception($msg, RestServeur::HTTP_CODE_ERREUR);}$idCommentaire = $this->bdd->recupererIdDernierAjout();return $idCommentaire;}private function creerEnteteChamps() {return $this->creerSuiteChampsOuValeurs('champs');}private function creerClauseValues() {return $this->creerSuiteChampsOuValeurs('valeurs');}private function creerSuiteChampsOuValeurs($mode) {$suite = array();foreach ($this->mapping as $nomChampBdd => $nomAttributSortie) {if (isset($this->parametres[$nomAttributSortie]) && $this->parametres[$nomAttributSortie] != null) {if ($mode == 'valeurs') {$suite[] = $this->bdd->proteger($this->parametres[$nomAttributSortie]);} else if ($mode == 'champs') {$suite[] = $nomChampBdd;} else {$msg = "Erreur interne : mauvais paramètre passé à la méthode 'creerSuiteChampsOuValeurs'";throw new Exception($msg, RestServeur::HTTP_CODE_ERREUR);}}}return implode(', ', $suite);}private function tenterEnrichissementTaxonomique() {if($this->commentaireEstPropositionSansNn()) {// TODO: utiliser le référentiel de l'obs si celui-ci// n'est pas fourni dans le commentaire et prendre le résultat// si celui-ci est unique$referentiel = $this->parametres['nom_referentiel'];$requete = urlencode($this->parametres['nom_sel']);$url = sprintf($this->conteneur->getParametre('nomstaxons.url_autocompletion_tpl'), $referentiel, $requete);$restClient = $this->conteneur->getRestClient();// Un retour vide est possible (un cas normal où il n'y a pas de résultat)// mais il fait planter le retour du service si on active l'affichage des erreurs// donc on passe sciemment les erreurs sous silence (car cette erreur n'en est pas une)$resultatJson = @$restClient->consulter($url);$resultats = json_decode($resultatJson, true);// On ne fait l'affectation que si l'on est sur (donc si un seul résultat)if (isset($resultats['resultat']) && count($resultats['resultat']) == 1) {$info = array_pop($resultats['resultat']);$this->parametres['nom_sel_nn'] = $info['num_nom'];}}}private function commentaireEstPropositionSansNn() {// Pas besoin de tester si c'est vide, normalement verifierParametres// l'a déjà fait au-dessusreturn isset($this->parametres['nom_sel'])&& isset($this->parametres['nom_referentiel'])&& !isset($this->parametres['nom_sel_nn']);}}