* @author Mathias Chouet * @author Raphaël Droz * @author Aurélien Peronnet * @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL * @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL * @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images */ class Changements { private $indexImagesIds = array(); private $conteneur; private $navigation; private $masque; private $gestionBdd; private $bdd; private $parametres = array(); private $ressources = array(); private $date_defaut = '1900-01-01'; public function __construct(Conteneur $conteneur = null) { /* restore_exception_handler(); */ /* restore_error_handler(); */ /* ini_set("display_errors", "1"); */ $this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; $this->conteneur->chargerConfiguration('config_plantnet.ini'); $this->navigation = $conteneur->getNavigation(); $this->masque = $conteneur->getMasque(); $this->gestionBdd = $conteneur->getGestionBdd(); $this->bdd = $this->gestionBdd->getBdd(); } /** * Méthode principale de la classe. * Lance la récupération des images dans la base et les place dans un objet ResultatService * pour l'afficher. * @param array $ressources les ressources situées après l'url de base (ex : http://url/ressource1/ressource2) * @param array $parametres les paramètres situés après le ? dans l'url * */ public function consulter($ressources, $parametres) { // initialiserRessourcesEtParametres() $this->ressources = $ressources; $this->parametres = $parametres; if(!isset($parametres['date'])) { $this->parametres['date'] = $this->date_defaut; } // Lancement du service $liaisons = $this->chargerLiaisons(); $images = array(); $total = 0; if($liaisons) { $compte = $this->bdd->recuperer('SELECT FOUND_ROWS() AS nbre'); $total = (int) $compte['nbre']; $imgdata = $this->recupererDonneeObs($liaisons); $obs = $this->regrouperObs($liaisons, $imgdata); $obs = $this->chargerPropositionPlusProbable($obs); $obs = $this->orderArray($obs); } $this->navigation->setTotal($total); // Mettre en forme le résultat et l'envoyer pour affichage $resultat = new ResultatService(); //$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $images); $resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $obs); return $resultat; } private function orderArray(&$obs) { $ret = array(); foreach ($obs as $o) { $ret[] = $o; } function cmp($a, $b) { return ($a['date_changement'] < $b['date_changement']) ? 1 : -1; } usort($ret, 'cmp'); return $ret; } /*------------------------------------------------------------------------------- CHARGEMENT DES IMAGES --------------------------------------------------------------------------------*/ private function chargerLiaisons() { $date_debut = $this->parametres['date']; $date_debut = '\'' . $date_debut . '\''; $limite = @min(intval($this->parametres['navigation.limite']), 1000); $limite = $limite ? $limite : 10; // 0 => 10 $depart = intval(@$this->parametres['navigation.depart']); $requete_sql = 'select SQL_CALC_FOUND_ROWS vdi.id_observation, vdi.id_image, '. 'GROUP_CONCAT(del_image_vote.valeur) as votes, GROUP_CONCAT(DISTINCT tag) as tags, '. 'GREATEST('. 'IFNULL(vdi.date_creation, \''.$this->date_defaut.'\'), '. 'IFNULL(vdi.date_modification, \''.$this->date_defaut.'\'), '. 'IFNULL(MAX(del_image_tag.date), \''.$this->date_defaut.'\'), '. 'IFNULL(MAX(del_image_tag.date_modification), \''.$this->date_defaut.'\'), '. 'IFNULL(MAX(del_image_vote.date), \''.$this->date_defaut.'\'), '. 'IFNULL(MAX(del_commentaire.date), \''.$this->date_defaut.'\'), '. 'IFNULL(MAX(del_commentaire_vote.date), \''.$this->date_defaut.'\')) as modif_date '. 'from v_del_image as vdi '. 'left join del_image_vote on del_image_vote.ce_image=id_image and del_image_vote.ce_protocole=3 '. 'left join del_image_tag on del_image_tag.ce_image=id_image and del_image_tag.actif=1 '. 'left join del_commentaire on del_commentaire.ce_observation=id_observation '. 'left join del_commentaire_vote on del_commentaire_vote.ce_proposition=del_commentaire.id_commentaire '. 'group by id_image, id_observation '. 'having MAX(vdi.date_creation) >= '.$date_debut.' or '. ' MAX(vdi.date_modification) >= '.$date_debut.' or '. ' MAX(del_image_tag.date) >= '.$date_debut.' or '. ' MAX(del_image_tag.date_modification) >= '.$date_debut.' or '. ' MAX(del_image_vote.date) >= '.$date_debut.' or '. ' MAX(del_commentaire.date) >= '.$date_debut.' or '. ' MAX(del_commentaire_vote.date) >= '.$date_debut.' '. 'order by modif_date DESC '. 'limit '.$depart.', '.$limite.' -- '.__FILE__.':'.__LINE__; //echo $requete_sql; exit; return $this->bdd->recupererTous($requete_sql); // GROUP BY (très couteux) car multiples observations associées à une image // charlie est ici :-) // eg: 16150,16185,16245,16246,118995,129989 } // recupere les donnée associées (fait en 2 requetes pour optimiser) private function recupererDonneeObs(&$liaisons) { // recuperer les ids $ids = array(); foreach ($liaisons as $img) { $id = $img['id_image']; $ids[] = $id; } // recuperer les donnees $resultats = $this->bdd->recupererTous(sprintf( 'SELECT '. 'vdi.id_observation, vdi.id_image, '. 'vdi.nom_sel, '. 'vdi.nom_referentiel, vdi.nom_ret, vdi.nom_ret_nn, vdi.nt, vdi.famille, '. 'vdi.zone_geo, vdi.latitude, vdi.longitude, '. 'vdi.date_observation, vdi.date_creation, vdi.date_transmission, '. 'vdi.mots_cles_texte as mots_cles_texte, '. 'vdi.i_mots_cles_texte as mots_cles_texte_image, '. 'vdi.ce_utilisateur as ce_utilisateur, '. 'vdi.prenom_utilisateur, vdi.courriel_utilisateur, vdi.nom_utilisateur, vdi.nom_original as nom_image '. 'FROM v_del_image as vdi '. 'WHERE vdi.id_image IN (%s) '. '', implode(',', $ids))); // regroupe les données par id_image $img_data = array(); foreach ($resultats as $img) { $id = $img['id_image']; $img_data[$id] = $img; } return $img_data; } /** * Retourner un tableau d'images formaté en fonction des liaisons trouvées * @param $liaisons les liaisons de la table del_obs_images * */ private function regrouperObs(&$liaisons, &$imgdatas) { // regroupe les observations $obs = array(); foreach ($liaisons as $img) { $idobs = $img['id_observation']; $idimg = $img['id_image']; $imgdata = $imgdatas[$idimg]; if (!isset($obs[$idobs])) { $obs[$idobs] = array(); } $obs[$idobs]['id_observation'] = $idobs; $obs[$idobs]['auteur_id'] = $imgdata['ce_utilisateur']; $obs[$idobs]['auteur_prenom'] = $imgdata['prenom_utilisateur']; $obs[$idobs]['auteur_nom'] = $imgdata['nom_utilisateur']; $obs[$idobs]['auteur_courriel'] = $imgdata['courriel_utilisateur']; $obs[$idobs]['mots_cles_obs_cel'] = $this->formaterMotsClesCel($imgdata['mots_cles_texte']); $obs[$idobs]['date_observation'] = $imgdata['date_observation']; $obs[$idobs]['date_publication'] = $imgdata['date_transmission']; $obs[$idobs]['date_creation'] = $imgdata['date_creation']; $obs[$idobs]['date_changement'] = $img['modif_date']; $obs[$idobs]['nom_sel'] = $imgdata['nom_sel']; $obs[$idobs]['nom_referentiel'] = $imgdata['nom_referentiel']; $obs[$idobs]['nom_ret'] = $imgdata['nom_ret']; $obs[$idobs]['nn'] = $imgdata['nom_ret_nn']; $obs[$idobs]['nt'] = $imgdata['nt']; $obs[$idobs]['famille'] = $imgdata['famille']; $obs[$idobs]['zone_geo'] = $imgdata['zone_geo']; $obs[$idobs]['latitude'] = floatval($imgdata['latitude']); $obs[$idobs]['longitude'] = floatval($imgdata['longitude']); if (!isset($obs[$idobs]['images'])) { $obs[$idobs]['images'] = array(); } $img_obj = array( 'id_image' => $img['id_image'], 'nom_image' => $imgdata['nom_image'], 'url' => sprintf('http://api.tela-botanica.org/img:%09dO.jpg', $img['id_image']), 'votes' => array_map('intval', explode(',', $img['votes'])), 'tags' => explode(',', $img['tags']), 'mots_cles_img_cel' => $this->formaterMotsClesCel($imgdata['mots_cles_texte_image']) ); // push $obs[$idobs]['images'][] = $img_obj; } return $obs; } /** * Charger les votes pour chaque image **/ private function chargerPropositionPlusProbable(&$obs) { $obsIds = array_keys($obs); $resultats = $this->bdd->recupererTous(sprintf( 'SELECT ce_observation, id_commentaire, valeur, nom_sel, nom_sel_nn, nom_ret, nom_ret_nn, del_commentaire_vote.ce_utilisateur '. 'FROM del_commentaire_vote, del_commentaire '. 'WHERE ce_observation IN (%s) '. 'AND nom_sel IS NOT NULL '. 'AND del_commentaire.id_commentaire=del_commentaire_vote.ce_proposition '. '', implode(',', $obsIds))); $votes = array(); // map ce_proposition -> score // calcul des votes // un vote identifié a un facteur de 3 // additionne tous les vote par ce_proposition foreach($resultats as $vote) { if(!isset($votes[$vote['id_commentaire']])) { $votes[$vote['id_commentaire']] = 0; } $valeur = ($vote['valeur'] == 1) ? 1 : -1; $votes[$vote['id_commentaire']] += is_numeric($vote['ce_utilisateur']) ? 3 * $valeur : $valeur; } foreach($resultats as $vote) { $idobs = $vote['ce_observation']; if(!isset($obs[$idobs]['determinations'])) { $obs[$idobs]['determinations'] = array(); } $obs[$idobs]['determinations'][$vote['id_commentaire']] = array('nom_sel' => $vote['nom_sel'], 'nom_ret' => $vote['nom_ret'], 'score' => $votes[$vote['id_commentaire']], 'nn' => $vote['nom_sel_nn'] ); } return $obs; } /*------------------------------------------------------------------------------- FORMATER ET METTRE EN FORME --------------------------------------------------------------------------------*/ /** * Formater les mots clés du cel en n'affichant que ceux faisant partie * d'une liste définie dans le fichier de configuration * @param $chaineMotCleCel la chaine de mots clés du cel * @return string la chaine filtrée * */ private function formaterMotsClesCel($chaineMotCleCel) { $mots_cles_cel_affiches = "fleur,fleurs,feuille,feuilles,ecorce,fruit,fruits,port,plantnet,plantscan_new"; $result = array_intersect( explode(',', $mots_cles_cel_affiches), // $tabMotsClesAffiches explode(',', $chaineMotCleCel)); // $tabMotsClesCel if (count($result) === 0) { return array(); } $ret = explode(',', implode(',', $result)); return $ret; } }