Rev 2067 | Rev 2178 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php// declare(encoding='UTF-8');/*** Web service récupèrant toutes les observations et, pour chacune d'elle, les images qui lui sont associées.** ATTENTION : le web service commence par récupérer seulement les id des obs (1er requete SQL), puis dans une* deuxième requête SQL récupère les informations complémentaires. Il s'avère qu'en procédant ainsi le web service* est 3 fois plus rapide !** @category DEL* @package Services* @subpackage Observations* @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 ListeObservations {private $conteneur;private $bdd;private $navigation;private $filtrage;private $sql;private $mappings = array();private $paramsFiltres = array();private $idsObsOrdonnees = array();private $infosObs = array();private $infosObsOrdonnee = array();private $evenementsObs = array();public function __construct(Conteneur $conteneur) {$this->conteneur = $conteneur;$this->conteneur->chargerConfiguration('config_departements_bruts.ini');$this->bdd = $this->conteneur->getBdd();$this->filtrage = $this->conteneur->getParametresFiltrage();$this->sql = $this->conteneur->getSql();$this->navigation = $this->conteneur->getNavigation();$this->mappings['votes'] = $this->conteneur->getParametreTableau('votes.mapping');$this->mappings['commentaires'] = $this->conteneur->getParametreTableau('commentaires.mapping');}public function consulter($ressources, $parametres) {$this->paramsFiltres = $this->filtrage->filtrerUrlParamsAppliObs();$this->sql->setAppli(Sql::APPLI_OBS);$this->sql->setParametres($this->paramsFiltres);$this->sql->ajouterContraintes();$this->sql->ajouterConstrainteAppliObs();$this->sql->definirOrdreSqlAppliObs();$this->idsObsOrdonnees = $this->getIdObs();$this->navigation->setTotal($this->sql->getTotalLignesTrouvees());// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats$resultat = new ResultatService();$resultat->corps = array('entete' => $this->navigation->getEntete(), 'resultats' => array());if (count($this->idsObsOrdonnees) > 0) {// 2) récupération des données nécessaires pour ces observations (obs + images)$this->infosObs = $this->getInfosObs();// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output$this->infosObsOrdonnees = $this->formaterObservations();// 4) Ajouter commentaires + votes à $this->infosObsOrdonnees$this->chargerDeterminations();$resultat->corps = array('entete' => $this->navigation->getEntete(),// 5) Applatissage du tableau afin de garder l'ordre de tri// (qui n'est pas garanti dans un objet json)'resultats' => array_values($this->infosObsOrdonnees));}return $resultat;}// SQL helpers/** Retourne une liste ordonnée d'id d'observation correspondant aux critères* passés dans p et aux clauses where/join présentes dans le tableau $req** @param p: $params (filtrés sauf escape-string)* @param req: le tableau représentant les composants de la requete SQL* @param db: l'instance de db*/private function getIdObs() {$requete = $this->renvoyerRequeteSelonType();//Debug::printr($requete);$resultats = $this->bdd->recupererTous($requete);$idObs = array();if ($resultats !== false ) {foreach ($resultats as $resultat) {$idObs[] = $resultat['id_observation'];}}return $idObs;}private function renvoyerRequeteSelonType() {if($this->monActiviteEstDemandee()) {$gestion_utilisateur = new GestionUtilisateur($this->conteneur);$utilisateur = $gestion_utilisateur->getUtilisateur();if ($utilisateur['connecte'] === true) {$id_utilisateur = $utilisateur['id_utilisateur'];$requete = $this->sql->getRequeteIdObsMonactiviteTout($id_utilisateur, $this->sql->getLimit()).' -- '.__FILE__.':'.__LINE__;// Enregistrement de la date de consultation pour ne pas réafficher des événements déjà consultés$gestion_utilisateur->setDerniereDateConsultationEvenements($id_utilisateur, date('Y-m-d H:i:s'));} else {//TODO: que faire si l'on n'est pas connecté ?}} else {$requete = 'SELECT SQL_CALC_FOUND_ROWS id_observation '.'FROM del_observation AS do '.$this->sql->getJoin().'WHERE '.$this->sql->getWhere().$this->sql->getGroupBy().$this->sql->getOrderBy().$this->sql->getLimit().' -- '.__FILE__.':'.__LINE__;}return $requete;}private function monActiviteEstDemandee() {return isset($this->paramsFiltres['masque.type']) && in_array('monactivite',array_keys($this->paramsFiltres['masque.type']));}/*** Après avoir récupérer seulement les ids dans une première requête, nous récupérons maintenant les infos.* Le web service est ainsi 3 fois plus rapide.*/private function getInfosObs() {$idsObsConcat = implode(',', $this->idsObsOrdonnees);$requete = "SELECT id_observation, nom_sel AS `determination.ns`, nt AS `determination.nt`, ".'nom_sel_nn AS `determination.nn`, famille AS `determination.famille`, '.'nom_referentiel AS `determination.referentiel`, ce_zone_geo AS id_zone_geo, pays, '.'zone_geo, lieudit, station, milieu, date_observation, do.mots_cles_texte, '.'do.date_transmission, do.commentaire, '.'do.ce_utilisateur AS `auteur.id`, do.prenom_utilisateur AS `auteur.prenom`, '.'do.nom_utilisateur AS `auteur.nom`, do.courriel_utilisateur AS `auteur.courriel`, '.'id_image, date_prise_de_vue AS `date`, hauteur, largeur, nom_original '.'FROM del_observation AS do '.' LEFT JOIN del_image AS di ON (do.id_observation = di.ce_observation) '."WHERE id_observation IN ($idsObsConcat) ".' -- '.__FILE__.':'.__LINE__;if ($this->monActiviteEstDemandee()) {$this->stockerEvenementsObs($idsObsConcat);}//Debug::printr($requete);return $this->bdd->recupererTous($requete);}private function stockerEvenementsObs($idsObsConcat) {$gestion_utilisateur = new GestionUtilisateur($this->conteneur);$utilisateur = $gestion_utilisateur->getUtilisateur();$id_utilisateur = $utilisateur['id_utilisateur'];$evenements = $this->sql->getEvenementsObs($idsObsConcat, $id_utilisateur);$this->evenements_obs = array();foreach($evenements as &$evenement) {$this->affecterTypeEvenement($evenement, $id_utilisateur, $evenement['id_observation']);}}private function affecterTypeEvenement(&$evenement, $id_utilisateur, $id_observation) {$type = "";$infos = "";// La date maximale détermine le type d'évènementswitch($evenement['date_max']) {// Quelqu'un a fait un nouveau commentaire ou propositioncase $evenement['date_com']:if(!empty($evenement['nom_sel_com'])) {$type = 'nouvelle_proposition';$infos = $evenement['proposition_commentaire_nom_sel'];} else {$type = 'nouveau_commentaire';$infos = $evenement['proposition_commentaire_texte'];}// J'ai commenté ou fait une propositionif($evenement['utilisateur_commentaire'] == $id_utilisateur) {$type .= "_vous_a_obs_autre";} else {$type .= "_autre_sur_obs_vous";}break;// Quelqu'un a répondu à un de mes commentaires ou une de mes propositionscase $evenement['date_com_reponse']:if(!empty($evenement['nom_sel_com_parent'])) {$type = 'nouvelle_reponse_autre_sur_proposition_vous';} else {$type = 'nouvelle_reponse_autre_sur_commentaire_vous';}$infos = $evenement['proposition_commentaire_texte_commente'];break;// Quelqu'un a fait un nouveau votecase $evenement['date_vote']:$type = 'nouveau_vote';// Sur une proposition qui n'est pas à moi sur une observation à moiif($evenement['utilisateur_commentaire_vote'] != $evenement['utilisateur_observation'] && $evenement['utilisateur_commentaire_vote'] != $id_utilisateur) {$type .= "_autre_sur_com_autre_obs_vous";} else {// Sur une proposition qui est à moi sur une observation (à moi ou non)$type .= "_autre_sur_com_vous";}$infos = $evenement['proposition_commentaire_nom_sel_votee'];break;// Quelqu'un a validé une propositioncase $evenement['date_validation']:$type = "nouvelle_validation_autre_sur_prop_vous";$infos = $evenement['proposition_validee_nom_sel'];// $type = "nouvelle_validation_vous_a_prop_autre";break;// Cas qui ne devrait jamais arriverdefault:$type = 'inconnu';$infos = "";}$infos_evts = array('type' => $type, 'infos_complementaires' => $infos);// La requête est un peu trop complexe et certains évènements sortent en doublons// donc on dédoublonne ici (mais ça n'est pas une solution pérenne)// TODO: optimiser et simplifier ceciif(empty($this->evenementsObs[$id_observation])) {$this->evenementsObs[$id_observation] = array();}if(array_search($infos_evts, $this->evenementsObs[$id_observation]) === false) {$this->evenementsObs[$id_observation][] = $infos_evts;}}/*** Les informations étant extraites d'une vue dont les infos des obs sont dupliquées pour chaque image,* il nous faut maintenant récupérer qu'une seule fois les données d'observations et y intégrer les données* des images.*/private function formaterObservations() {$observations = array_map('array_filter', $this->infosObs);$obsFormatees = array_flip($this->idsObsOrdonnees);// Permet de garder l'ordre de sortie !foreach ($observations as &$obs) {$this->nettoyerAuteur($obs);$id = $obs['id_observation'];// ATTENTION : la requête retourne de nombreuses lignes avec les mêmes données (test de l'existence nécessaire)if (is_array($obsFormatees[$id]) === false) {$obsFormatees[$id] = $obs;}$obsFormatees[$id]['images'][] = $this->extraireInfosImage($obs);if(isset($this->evenementsObs[$id])) {$obsFormatees[$id]['evenements'] = $this->evenementsObs[$id];}}return $obsFormatees;}private function nettoyerAuteur(&$obs) {// car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID// mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaireif (!isset($obs['auteur.id']) || !is_numeric($obs['auteur.id'])) {$obs['auteur.id'] = "0";}if (!isset($obs['auteur.nom'])) {$obs['auteur.nom'] = '[inconnu]';}}private function extraireInfosImage(&$obs) {$champsImageAffichables = array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original');$image = array_intersect_key($obs, array_flip($champsImageAffichables));$urlImgTpl = $this->conteneur->getParametre('cel_img_url_tpl');$image['binaire.href'] = sprintf($urlImgTpl, $image['id_image'], 'XL');unset($obs['id_image'], $obs['date'], $obs['hauteur'], $obs['largeur'], $obs['nom_original']);return $image;}/*** Récupérer toutes les déterminations et le nombre de commentaire au total* @param array $observations la liste des observations à mettre à jour*/private function chargerDeterminations() {$idObsConcat = implode(',', $this->idsObsOrdonnees);$requete = 'SELECT * '.'FROM del_commentaire AS dc '.'WHERE dc.nom_sel IS NOT NULL '."AND ce_observation IN ($idObsConcat) ".'-- '.__FILE__.':'.__LINE__;$commentaires = $this->chargerNombreCommentaireObs();$propositions = $this->bdd->recupererTous($requete);if ($propositions) {foreach ($propositions as $proposition) {$idObs = $proposition['ce_observation'];$idComment = $proposition['id_commentaire'];$comment = $this->formaterDetermination($idComment, $proposition);if ($comment) {$this->infosObsOrdonnees[$idObs]['commentaires'][$idComment] = $comment;}$this->infosObsOrdonnees[$idObs]['nb_commentaires'] = isset($commentaires[$idObs]) ? $commentaires[$idObs] : 0;}}}private function formaterDetermination($propositionId, $propositionInfos) {if (!$propositionInfos) return NULL;$propositionFormatee = array();foreach ($this->mappings['commentaires'] as $nomChamp => $nomAttributJson) {if (isset($propositionInfos[$nomChamp])) {$propositionFormatee[$nomAttributJson] = $propositionInfos[$nomChamp];}}// Charger les votes sur les déterminations$requete = "SELECT * FROM del_commentaire_vote WHERE ce_proposition = $propositionId".'-- '.__FILE__.':'.__LINE__;$resultatsVotes = $this->bdd->recupererTous($requete);foreach ($resultatsVotes as $vote) {$propositionFormatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);}$propositionFormatee['nb_commentaires'] = $this->chargerNombreCommentaire($propositionId);return $propositionFormatee;}/*** Formater un vote en fonction du fichier de configuration config_votes.ini* @param $votes array()*/private function formaterVote($vote) {$voteFormate = array();foreach ($vote as $nomChamp => $valeur) {$voteFormate[$this->mappings['votes'][$nomChamp]] = $valeur;}return $voteFormate;}private function chargerNombreCommentaireObs() {$idObsConcat = implode(',', $this->idsObsOrdonnees);$requete = 'SELECT ce_observation, COUNT( id_commentaire ) AS nb '.'FROM del_commentaire '."WHERE ce_observation IN ($idObsConcat) ".'GROUP BY ce_observation '.'-- '.__FILE__.':'.__LINE__;$commentaires = $this->bdd->recupererTous($requete);$commentaires_par_obs = array();foreach($commentaires as $commentaire) {$commentaires_par_obs[$commentaire['ce_observation']] = $commentaire['nb'];}return $commentaires_par_obs;}private function chargerNombreCommentaire($propositionId) {$requete = 'SELECT COUNT( id_commentaire ) AS nb '.'FROM del_commentaire '."WHERE ce_proposition = $propositionId ".'GROUP BY ce_proposition '.'-- '.__FILE__.':'.__LINE__;$commentaires = $this->bdd->recuperer($requete);return $commentaires ? $commentaires['nb'] : 0;}}