/branches/v1.1-helium/services/modules/0.1/Nomstaxons.php |
---|
New file |
0,0 → 1,122 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Nomstaxons extends RestService { |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
$retour = $this->initialiserService(); |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->projetNom = 'nomstaxons'; |
$this->chargerConfigProjet(); |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserService() { |
$this->chargerNomService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} else { |
//TODO : throw exception |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function chargerNomService() { |
// si la méthode est POST, on ajouter un commentaire |
$this->serviceNom = 'liste-taxons'; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Observations.php |
---|
New file |
0,0 → 1,222 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Observations extends RestService { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/observations/ => toutes les observations (infos obs, infos images, infos propositions, infos nb commentaires) |
* http://localhost/del/services/0.1/observations/#id => une observation donnée et ses images, SANS LES propositions & nombre de commentaire |
* */ |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function ajouter($ressources, $requeteDonnees) { |
$this->methode = 'ajouter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
} |
} |
public function modifier($ressources, $requeteDonnees) { |
$this->methode = 'modifier'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
} |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
if ($this->avoirRessourceService()) { |
$retour = $this->initialiserService(); |
} |
return $retour; |
} |
private function avoirRessourceIdentifiant($num) { |
$presenceId = false; |
if (is_numeric($this->ressources[$num])) { |
$presenceId = true; |
} else { |
$message = "Le service demandé '$service' nécessite d'avoir un identifiant d'image valide"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $presenceId; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->chargerNomDuProjet(); |
$this->chargerConfigProjet(); |
} |
private function chargerNomDuProjet() { |
$this->projetNom = 'observations'; |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function avoirRessourceService() { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/observations/ => toutes les observations (infos obs, infos images, infos propositions, infos nb commentaires) |
* http://localhost/del/services/0.1/observations/#id => une observation donnée et ses images, SANS LES propositions & nombre de commentaire |
* */ |
$presenceRessourceService = false; |
if (isset($this->ressources[0])) { |
if ($this->avoirRessourceIdentifiant(0)) { |
if (sizeof($this->ressources) == 1) { |
$presenceRessourceService = true; |
$this->serviceNom = 'observation'; |
} else { |
if (isset($this->ressources[1])) { |
$presenceRessourceService = $this->avoirRessourceSousService(); |
} |
} |
} |
} else { |
if (isset($this->parametres['retour.format']) && $this->parametres['retour.format'] == 'widget') { |
$this->methode = 'consulter'; |
$presenceRessourceService = true; |
$this->serviceNom = 'liste-observations-widget'; |
} else { |
$presenceRessourceService = true; |
$this->serviceNom = 'liste-observations'; |
} |
} |
return $presenceRessourceService; |
} |
private function avoirRessourceSousService() { |
$presenceRessourceService = false; |
$servicesDispo = Outils::recupererTableauConfig('servicesDispo'); |
if ($this->avoirRessourceIdentifiant(1)) { |
$service = $this->ressources[2]; |
if (in_array($service, $servicesDispo)) { |
$presenceRessourceService = true; |
$this->serviceNom = 'vote-observation'; |
} else { |
$message = "Le service demandé '$service' n'est pas disponible pour le projet {$this->projetNom} !\n". |
"Les services disponibles sont : ".implode(', ', $servicesDispo); |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
} |
return $presenceRessourceService; |
} |
private function initialiserService() { |
//$this->chargerNomDuService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'modifier') { |
$retour = $service->modifier($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/images/VoteImage.php |
---|
New file |
0,0 → 1,175 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class VoteImage { |
private $imageIds = array(); |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $ressources; |
private $parametres; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_votes.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_votes.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) { |
// Gestion des configuration du script |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
$this->configurer(); |
$this->verifierConfiguration(); |
// Lancement du service |
$votes = $this->chargerVotes(); |
$total = $this->compterVotes(); |
$this->navigation->setTotal($total); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = $votes; |
return $resultat; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
public function configurer() { |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
$tableauImages = $this->conteneur->getParametre('images'); |
if (empty($tableauImages)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [images] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
} |
if (empty($this->mappingVotes)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_observation] ou celui-ci est vide ;'; |
} else { |
$champsMappingObs = array('ce_protocole','id_vote','valeur','ce_image', 'ce_utilisateur', 'nom', 'prenom'); |
foreach ($champsMappingObs as $champ) { |
if (!isset($this->mappingVotes[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour l\'observation est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where[] = 'WHERE ce_image = '.$this->proteger($this->ressources[0]); |
$where[] = 'id_vote = '.$this->proteger($this->ressources[2]); |
return implode(' AND ', $where); |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES IMAGES |
--------------------------------------------------------------------------------*/ |
/** |
* Charger les votes pour chaque image |
* */ |
private function chargerVotes() { |
$requeteVotes = 'SELECT * FROM '. |
$this->gestionBdd->formaterTable('del_image_vote'). |
$this->chargerClauseWhere(); |
$resultatsVotes = $this->bdd->recupererTous($requeteVotes); |
$votes = $this->formaterVote($resultatsVotes[0]); |
return $votes; |
} |
/** |
* Compter le nombre total d'images dans la base pour affichage dans entete. |
* */ |
private function compterVotes() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater une observation depuis une ligne liaison |
* @param $liaison liaison issue de la recherche |
* @return $observation l'observation mise en forme |
* */ |
private function formaterVote($vote) { |
$retour = array(); |
foreach ($vote as $p=>$valeur) { |
$retour[$this->mappingVotes[$p]] = $valeur; |
} |
return $retour; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/images/ListeImages.old.php |
---|
New file |
0,0 → 1,1349 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
/** |
* FONCTION TEMPORAIRE de debug pour afficher le contenu d'une variable en format lisible |
* @param $r la variable à afficher |
* */ |
function debug($r) { |
echo '<pre>'.print_r($r, true).'</pre>'; |
} |
/** |
* Le service ListeImages récupère les données des tables observation et images |
* et les mets au format JSON pour identiplante / pictoflora |
* */ |
class ListeImages { |
// Variables : |
// Configuration générale du service |
private $conteneur; |
private $navigation; |
private $bdd; |
private $gestionBdd; |
// Parametres |
private $ressources = array(); |
private $parametres = array(); |
private $masque; |
private $tri = 'date_transmission'; |
private $directionTri = 'desc'; |
private $formatRetour = 'XL'; |
private $imageIds = array(); |
/** |
* Constructeur de l'application |
* Initialisation des variables générale de l'application |
* @param Conteneu $conteneur le conteneur de classes de l'application |
* */ |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_departements_bruts.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_votes.ini'); |
$this->conteneur->chargerConfiguration('config_images.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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->configurer(); |
$this->verifierConfiguration(); |
$this->verifierParametresTri(); |
$this->initialiserTri(); |
$this->verifierParametreFormatRetour(); |
$this->initialiserFormatRetour(); |
$parametres = $this->nettoyerParametres($parametres); |
// En fonction des paramètres de recherche, on n'effectue |
// pas la même requête, pour optimiser les jointures et les |
// rapidités d'éxécution. |
$type = $this->getTypeRequete($ressources, $parametres); |
switch ($type) { |
case 'obs' : |
$liaisons = $this->chargerLiaisonsObs(); |
break; |
case 'images' : |
$liaisons = $this->chargerLiaisonsImages(); |
break; |
case 'obs-images' : |
$liaisons = $this->chargerLiaisons(); |
break; |
case 'id': |
$liaisons = $this->chargerLiaisonsParId(); |
break; |
default : //case simple ! |
$liaisons = $this->chargerLiaisonsSimple(); |
} |
$images = array(); |
if($liaisons) { |
// Partie commune à tous les cas : on complète les liaisons avec les informations des votes |
// et des images, puis on affiche sous forme de JSON |
$images = $this->chargerImage($liaisons); |
$images = $this->chargerVotes($images); |
} |
$resultat = new ResultatService(); |
if ($type == 'id') { |
$clefsImages =array_keys($images); |
$resultat->corps = $images[$clefsImages[0]]; |
} else { |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $images); |
} |
return $resultat; |
} |
/************************************************************************************** |
* FONCTION LIEES AUX REQUETES * |
**************************************************************************************/ |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach($tableauMasque as $idMasque => $valeurMasque) { |
//TODO: scinder ceci en fonctions réutilisables ? |
// voir si c'est interessant par rapport à la recherche générale |
$idMasque = str_replace('masque.', '', $idMasque); |
switch ($idMasque) { |
// nom du masque => nom BDD |
case 'auteur' : |
$whereAuteur = ' '.$this->creerFiltreAuteur($this->masque->getMasque('auteur')); |
if($whereAuteur != '') { |
$where[] = $whereAuteur; |
} |
break; |
case 'date' : |
$whereDate = ' '.$this->creerFiltreDate($valeurMasque); |
if($whereDate != '') { |
$where[] = $whereDate; |
} |
break; |
case 'departement' : |
$where[] = ' '.$this->creerFiltreIdZoneGeo($valeurMasque); |
break; |
case 'genre' : |
$where[] = ' '.$this->mappingFiltre['ns'].' LIKE '.$this->proteger($valeurMasque.' %'); |
break; |
case 'tag' : |
$where[] = ' '.$this->creerFiltreMotsCles($valeurMasque); |
break; |
case 'tag_cel' : |
$where[] = ' '.$this->creerFiltreMotsClesCel($valeurMasque); |
break; |
case 'tag_pictoflora' : |
$where[] = ' '.$this->creerFiltreMotsClesPictoflora($valeurMasque); |
break; |
case 'referentiel' : |
$where[] = ' dob.nom_referentiel LIKE '.$this->proteger($valeurMasque.'%'); |
break; |
case 'ns' : |
$where[] = ' nom_sel LIKE '.$this->proteger($valeurMasque.'%'); |
break; |
case 'nn' : |
$num_noms = $valeurMasque; |
$num_noms = explode(',', $num_noms); |
$num_noms = array_map('intval', $num_noms); |
$num_noms = array_filter($num_noms); |
$num_noms = implode(',', $num_noms); |
$where[] = "(nom_sel_nn IN ($num_noms) OR nom_ret_nn IN ($num_noms)) "; |
break; |
case 'commune' : |
$where[] = ' '.$this->mappingFiltre[$idMasque].' LIKE '.$this->proteger(str_replace(array('-',' '), '_', $valeurMasque).'%'); |
break; |
case 'masque' : |
$where[] = ' '.$this->creerFiltreMasqueGeneral($valeurMasque); |
break; |
default: |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->proteger($valeurMasque); |
break; |
} |
} |
} |
if (!empty($where)) { |
return ' WHERE '.implode('AND', $where); |
} else { |
return; |
} |
} |
/** |
* Créer un masque général lorsque l'on souhaite utiliser le passe partout |
* @param la valeur du passe partout |
* */ |
private function creerFiltreMasqueGeneral($valeurMasque) { |
//TODO: affecter d'aborder les variables, puis les tester pour les |
// ajouter à la chaine |
$whereAuteur = $this->creerFiltreAuteur($valeurMasque); |
$whereIdZoneGeo = $this->creerFiltreIdZoneGeo($valeurMasque); |
$masqueGeneral = '( '. |
(($whereAuteur != '') ? $whereAuteur.' OR ' : '' ). |
(($whereIdZoneGeo != '') ? $whereIdZoneGeo.' OR ' : '' ). |
'zone_geo LIKE '.$this->proteger($this->remplacerParJokerCaractere($valeurMasque).'%').' OR '. |
$this->creerFiltreMotsCles($valeurMasque).' OR '. |
'nom_sel LIKE '.$this->proteger($valeurMasque.'%').' OR '. |
'famille LIKE '.$this->proteger($valeurMasque.'%').' OR '. |
'milieu LIKE '.$this->proteger($valeurMasque).' OR '. |
$this->mappingFiltre['ns'].' LIKE '.$this->proteger('%'.$valeurMasque.'% %').' OR '. |
$this->creerFiltreDate($valeurMasque). |
') '; |
return $masqueGeneral; |
} |
/** |
* Créer le filtre auteur en recherchant dans son nom, prénom, adresse email en fonction |
* de la chaine donnée |
* @param la valeur recherchée |
* */ |
private function creerFiltreAuteur($valeurMasque) { |
$masque = ''; |
$auteurId = $valeurMasque; |
if (is_numeric($auteurId)) { |
$masque = ' ce_utilisateur = '.$auteurId; |
} else { |
if (strpos($auteurId, '@') === false) { |
$tableauNomPrenom = explode(' ',$auteurId, 2); |
if(count($tableauNomPrenom) == 2) { |
// on teste potentiellement un nom prenom ou bien un prénom nom |
$masque = '('. |
'(nom LIKE '.$this->proteger($tableauNomPrenom[0].'%').' AND '. |
'prenom LIKE '.$this->proteger($tableauNomPrenom[1].'%').') OR '. |
'(nom LIKE '.$this->proteger($tableauNomPrenom[1].'%').' AND '. |
'prenom LIKE '.$this->proteger($tableauNomPrenom[0].'%').') OR '. |
'(dob.nom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[0].'%').' AND '. |
'dob.prenom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[1].'%').') OR '. |
'(dob.nom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[1].'%').' AND '. |
'dob.prenom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[0].'%').') OR '. |
'(nom LIKE '.$this->proteger($valeurMasque.'%').') OR '. |
'(prenom LIKE '.$this->proteger($valeurMasque.'%').') OR '. |
'(dob.nom_utilisateur LIKE '.$this->proteger($valeurMasque.'%').') OR '. |
'(dob.prenom_utilisateur LIKE '.$this->proteger($valeurMasque.'%').') '. |
')'; |
} else { |
$masque = '( |
(nom LIKE '.$this->proteger($auteurId.'%').' OR '. |
'prenom LIKE '.$this->proteger($auteurId.'%').' OR '. |
'dob.nom_utilisateur LIKE '.$this->proteger($auteurId.'%').' OR '. |
'dob.prenom_utilisateur LIKE '.$this->proteger($auteurId.'%').')'. |
')'; |
} |
} else { |
$masque = " ( courriel LIKE ".$this->proteger($valeurMasque.'%'). |
" OR dob.courriel_utilisateur LIKE ".$this->proteger($valeurMasque.'%').") "; |
} |
} |
return $masque; |
} |
/** |
* Obtenir une chaine de caractère concaténant nom et prénom séparé par une virgule |
* @param String $auteurId l'identifiant de l'auteur |
* @return String la chaine de concaténation |
* */ |
private function getChaineNomPrenom($auteurId) { |
$nomPrenom = explode(' ', $auteurId); |
$nomPrenom = $this->proteger($nomPrenom); |
$chaineNomPrenom = implode(', ', $nomPrenom); |
return $chaineNomPrenom; |
} |
/** |
* Créer le filtre de recherche par zone géographique en fonction du masque |
* @param $valeurMasque le terme de la recherche |
* */ |
private function creerFiltreIdZoneGeo($valeurMasque) { |
$masque = ''; |
$dept = $valeurMasque; |
if (is_numeric($dept)) { |
$dept = sprintf('%02s', $dept); |
$dept = sprintf("%-'_5s", $dept); |
$masque = " ce_zone_geo LIKE ".$this->proteger('INSEE-C:'.$dept); |
} else { |
$deptId = $this->conteneur->getParametre($dept); |
if ($deptId != null) { |
$masque = " ce_zone_geo LIKE ".$this->proteger('INSEE-C:'.$deptId.'%'); |
} else { |
$id = $this->obtenirIdDepartement($valeurMasque); |
$masque = " ce_zone_geo LIKE ".$this->proteger('INSEE-C:'.$id.'%'); |
} |
} |
return $masque; |
} |
/** |
* Générer la chaine de recherche pour la date en fonction du masque |
* @param $valeurMasque la date recherchée (AAAA ou JJ/MM/AAAA) |
* */ |
private function creerFiltreDate($valeurMasque) { |
//TODO: définir dans le fichier de config un tableau contenant plusieurs format de date |
// autorisés pour la recherche, qui seraient ajoutés au OR |
$masque = '('; |
$masque .= (is_numeric($valeurMasque)) ? ' YEAR(date_observation) = '.$this->proteger($valeurMasque).' OR ' : ''; |
$masque .= " DATE_FORMAT(date_observation, '%d/%m/%Y') = ".$this->proteger($valeurMasque).' '. |
')'; |
return $masque; |
} |
/** |
* Générer la chaine de recherche dans les mots clés en fonction du masque |
* @param $valeurMasque le mot clé recherché |
* */ |
private function creerFiltreMotsCles($valeurMasque) { |
$mots_cles = explode(' ', $valeurMasque); |
$requeteMotsClesImg = array(); |
$requeteMotsClesObs = array(); |
$requeteMotsClesImgPublic = array(); |
foreach($mots_cles as $mot_cle) { |
//TODO: rechercher sur les mots clés normalisés dans tous les cas ? |
$requeteMotsCles = $this->proteger('%'.$mot_cle.'%'); |
$motsCleProtege = $this->proteger($this->normaliserMotCle('%'.$mot_cle.'%')); |
$requeteMotsClesImgPublic[] = 'di.id_image IN (SELECT ce_image FROM del_image_tag WHERE tag_normalise LIKE '.$motsCleProtege.' AND actif = 1)'; |
$requeteMotsClesImg[] = 'di.mots_cles_texte LIKE '.$requeteMotsCles; |
$requeteMotsClesObs[] = 'dob.mots_cles_texte LIKE '.$requeteMotsCles; |
} |
$requeteMotsClesImgPublic = implode(' AND ', $requeteMotsClesImgPublic); |
$requeteMotsClesImg = implode(' AND ', $requeteMotsClesImg); |
$requeteMotsClesObs = implode(' AND ', $requeteMotsClesObs); |
$masque = '('. |
'('.$requeteMotsClesImgPublic.') OR '. |
'('.$requeteMotsClesImg.') OR '. |
'('.$requeteMotsClesObs.') '. |
')'; |
return $masque; |
} |
/** |
* Générer la chaine de recherche dans les mots clés en fonction du masque |
* @param $valeurMasque le mot clé recherché |
* */ |
private function creerFiltreMotsClesPictoflora($valeurMasque) { |
$mots_cles = explode(' ', $valeurMasque); |
$requeteMotsClesImg = array(); |
$requeteMotsClesObs = array(); |
$requeteMotsClesImgPublic = array(); |
foreach($mots_cles as $mot_cle) { |
//TODO: rechercher sur les mots clés normalisés dans tous les cas ? |
$requeteMotsCles = $this->proteger('%'.$mot_cle.'%'); |
$motsCleProtege = $this->proteger($this->normaliserMotCle('%'.$mot_cle.'%')); |
$requeteMotsClesImgPublic[] = 'di.id_image IN (SELECT ce_image FROM del_image_tag WHERE tag_normalise LIKE '.$motsCleProtege.' AND actif = 1)'; |
} |
$requeteMotsClesImgPublic = implode(' AND ', $requeteMotsClesImgPublic); |
$masque = '('.$requeteMotsClesImgPublic.') '; |
return $masque; |
} |
private function creerFiltreMotsClesCel($valeurMasque) { |
$mots_cles = explode(' ', $valeurMasque); |
$requeteMotsClesImg = array(); |
$requeteMotsClesObs = array(); |
foreach($mots_cles as $mot_cle) { |
//TODO: rechercher sur les mots clés normalisés dans tous les cas ? |
$requeteMotsCles = $this->proteger('%'.$mot_cle.'%'); |
$motsCleProtege = $this->proteger($this->normaliserMotCle('%'.$mot_cle.'%')); |
$requeteMotsClesImg[] = 'di.mots_cles_texte LIKE '.$requeteMotsCles; |
$requeteMotsClesObs[] = 'dob.mots_cles_texte LIKE '.$requeteMotsCles; |
} |
$requeteMotsClesImg = implode(' AND ', $requeteMotsClesImg); |
$requeteMotsClesObs = implode(' AND ', $requeteMotsClesObs); |
$masque = '('. |
'('.$requeteMotsClesImg.') OR '. |
'('.$requeteMotsClesObs.') '. |
')'; |
return $masque; |
} |
// ?? |
private function assemblercomptageOccurencesMotsClesCel() { |
$chaineMotsClesAffiches = $this->conteneur->getParametre('mots_cles_cel_affiches'); |
$tabMotsClesAffiches = explode(',',$chaineMotsClesAffiches); |
$chaineSql = ''; |
// Comptage du nombre de mots clés officiels présents dans la chaine mots clés texte |
foreach ($tabMotsClesAffiches as $motCle) { |
if($chaineSql != '') { |
$chaineSql .= ' + '; |
} |
$chaineSql .= 'IF(FIND_IN_SET('.$this->proteger($motCle).',di.mots_cles_texte) != 0, 1, 0)'; |
} |
return '('.$chaineSql.')'; |
} |
private function getTri() { |
$order = ''; |
if($this->doitJoindreTableVotes()) { |
$order = ' GROUP BY dvote.ce_image, dob.id_observation ORDER BY total_votes '.$this->directionTri.', date_transmission desc '; |
} else if($this->doitJoindreTableTags()) { |
$order = ' GROUP BY doi.id_image ORDER BY total_tags '.$this->directionTri.', date_transmission desc '; |
} else { |
$order = ' ORDER BY '.$this->tri.' '.$this->directionTri.' '; |
} |
return $order; |
} |
/** |
* Compter le nombre total d'images dans la base pour affichage dans entete. |
* */ |
private function getFoundRows() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/** |
* En fonction des paramètres, générer les conditions de recherche |
* des observations |
* */ |
private function getConditionsObs() { |
$conditionsObs = array(); |
$masques = $this->masque->getMasque(); |
if (isset($masques['masque'])) { |
$passe = $masques['masque']; |
// Si on a saisi le masque passe partout, alors on doit chercher dans tous les champs |
// de la table observation (OR) |
$conditionLibre = array(); |
if (!isset($masques['masque.ns'])) { |
$conditionsLibre[] = "nom_sel LIKE '$passe%'"; |
} |
if (!isset($masques['masque.famille'])) { |
$conditionsLibre[] = "famille LIKE '$passe%'"; |
} |
if (!isset($masques['masque.milieu'])) { |
$conditionsLibre[] = "nom_sel LIKE '$passe%'"; |
} |
if (!isset($masques['masque.date'])) { |
$conditionsLibre[] = $this->creerFiltreDate($passe); |
} |
if (!isset($masques['masque.auteur'])) { |
$conditionsLibre[] = $this->creerFiltreAuteur($passe); |
} |
/* |
* FIXME : remplacer par motcle projet ! |
* if (!isset($masques['masque.tag'])) { |
$conditionsLibre[] = "mots_cles_texte LIKE '%$passe%'"; |
}*/ |
$conditionsObs[] = implode(' OR ', $conditionsLibre); |
} |
// referentiel |
if (isset($masques['masque.referentiel'])) { |
$ref = $masques['masque.referentiel']; |
$conditionsObs[] = "dob.nom_referentiel LIKE '$ref%'"; |
} |
// nom sel |
if (isset($masques['masque.ns'])) { |
$nom_sel = $masques['masque.ns']; |
$conditionsObs[] = "nom_sel LIKE '$nom_sel%'"; |
} |
// num nom |
if (isset($masques['masque.nn'])) { |
$num_noms = $masques['masque.nn']; |
$num_noms = explode(',', $num_noms); |
$num_noms = array_map('intval', $num_noms); |
$num_noms = array_filter($num_noms); |
$num_noms = implode(',', $num_noms); |
$conditionsObs[] = "(nom_sel_nn IN ($num_noms) OR nom_ret_nn IN ($num_noms)) "; |
} |
// num taxon |
if (isset($masques['masque.nt'])) { |
$num_taxon = $masques['masque.nt']; |
$conditionsObs[] = 'nt = '.intval($num_taxon); |
} |
// famille |
if (isset($masques['masque.famille'])) { |
$famille = $masques['masque.famille']; |
$conditionsObs[] = "famille LIKE '$famille%'"; |
} |
// genre |
if (isset($masques['masque.genre'])) { |
$genre = $masques['masque.genre']; |
$conditionsObs[] = "nom_sel LIKE '$genre%'"; |
} |
// milieu |
if (isset($masques['masque.milieu'])) { |
$milieu = $masques['masque.milieu']; |
$conditionsObs[] = "nom_sel LIKE '$milieu%'"; |
} |
// date |
if (isset($masques['masque.date'])) { |
$date = $masques['masque.date']; |
$conditionsObs[] = $this->creerFiltreDate($date); |
} |
// utilisateur |
if (isset($masques['masque.auteur'])) { |
$auteur = $masques['masque.auteur']; |
$conditionsObs[] = $this->creerFiltreAuteur($auteur); |
} |
// commune |
if (isset($masques['masque.commune'])) { |
$commune = $masques['masque.commune']; |
$conditionsObs[] = " zone_geo LIKE ".$this->proteger(str_replace(array('-',' '), '_', $commune).'%'); |
} |
// commune |
if (isset($masques['masque.departement'])) { |
$dept = $masques['masque.departement']; |
$conditionsObs[] = $this->creerFiltreIdZoneGeo($dept); |
} |
if (isset($masques['masque.tag_cel'])) { |
$motsCles = $masques['masque.tag_cel']; |
$conditionsObs[] = $this->creerFiltreMotsClesCel($motsCles); |
} |
return $conditionsObs; |
} |
/** |
* Obtenir le tableu de chaines de condition de requete images en fonction des masques |
* */ |
private function getConditionsImages() { |
$conditionsImg = array(); |
$masques = $this->masque->getMasque(); |
if (isset($masques['masque.tag_pictoflora'])) { |
$tag = $masques['masque.tag_pictoflora']; |
$conditionsImg[] = $this->creerFiltreMotsClesPictoflora($tag); |
} |
return $conditionsImg; |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES IMAGES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis la bdd de toutes les liaisons entre images et observations |
* Méthode appelée uniquement lorsque les paramètres sont vides |
* */ |
private function chargerLiaisonsSimple() { |
// On récupère d'abord les N images de del_obs_image, éventuellement triées, |
// Et on complète avec les informations des observations associées |
$requeteImages = ' SELECT *, di.mots_cles_texte as mots_cles_texte_image '. |
' FROM del_obs_image doi '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '; |
// Si le tri se fait par date d'observation, on récupère les identifiants de N observations triées |
if (isset($this->parametres['tri']) && $this->parametres['tri'] == 'date_observation') { |
$ordre = isset($this->parametres['ordre']) ? $this->parametres['ordre'] : 'DESC'; |
$requeteIdObs = ' SELECT doi.id_image as id_image '. |
' FROM del_obs_image doi '. |
' INNER JOIN del_observation dob ON dob.id_observation = doi.id_observation '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '. |
' ORDER BY date_observation '.$ordre.', dob.id_observation '.$ordre; |
$requeteIdObs .= $this->gestionBdd->getLimitSql(); |
// Récupérer les N observations triées par date |
$observations = $this->bdd->recupererTous($requeteIdObs . ' -- ' . __FILE__ . ':' . __LINE__); |
$idsImages = array(); |
foreach ($observations as $observation) { |
$idsImages[] = $observation['id_image']; |
} |
$chaineIdImages = implode(',', $idsImages); |
$requeteImages .= ' WHERE doi.id_image IN ('.$chaineIdImages.') '. |
' GROUP BY doi.id_image, doi.id_observation '. |
' ORDER BY FIELD(doi.id_image, '.$chaineIdImages.')'. |
' LIMIT '.$this->navigation->getLimite(); // On limite sur le nombre car les obs peuvent avoir plusieurs images |
} else { |
$requeteImages .= ' GROUP BY doi.id_image, doi.id_observation '; |
$requeteImages .= ' ORDER BY doi.id_observation DESC'; |
$requeteImages .= $this->gestionBdd->getLimitSql(); |
} |
$liaisons = $this->bdd->recupererTous($requeteImages . ' -- ' . __FILE__ . ':' . __LINE__); |
// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats dans la table del_obs_images |
if (!empty($liaisons)) { |
$idsObservations = array(); |
foreach ($liaisons as $image) { |
$idObs = $image['id_observation']; |
$idsObservations[$idObs] = $idObs; |
} |
$chaineIdObs = implode(',', $idsObservations); |
// On récupère les observations qui complètent la requête précédente |
$requeteObservations = ' SELECT * '. |
' FROM del_observation dob '. |
' LEFT JOIN del_utilisateur du ON dob.ce_utilisateur = du.id_utilisateur '. |
' WHERE id_observation IN ('.$chaineIdObs.')'; |
$resultatsObservations = $this->bdd->recupererTous($requeteObservations . ' -- ' . __FILE__ . ':' . __LINE__); |
// FIXME : Ca ne doit pas arriver, mais que se passe-t-il s'il n'y a pas d'observation pour l'image ?! |
// On range les observations dans un tableau pour pouvoir les retrouver par leur id : |
$observations = array(); |
foreach ($resultatsObservations as $id => $observation) { |
$idObs = $observation['id_observation']; |
$observations[$idObs] = $observation; |
} |
// Enfin, pour chaque image préalablement récupérées, on complète avec les informations de l'observation |
// FIXME : peut-être peut-on utiliser un array_merge ici ? |
foreach ($liaisons as $id => $liaison) { |
$idObs = $liaison['id_observation']; |
$observation = $observations[$idObs]; |
foreach ($observation as $cle => $valeur) { |
$liaisons[$id][$cle] = $valeur; |
} |
} |
// On compte à part les images issues de la jointure de del_obs_image et del_image car la fonction |
// SQL_CALC_FOUND_ROWS dans la fonction requete image fait passer le temps d'éxécution de 0.0011 à 15s ! |
$requeteNbImages = 'SELECT SUM(t.nb) as nb FROM (SELECT count(DISTINCT doi.id_image) as nb '. |
'FROM del_obs_image doi '. |
'INNER JOIN del_image di '. |
'ON di.id_image = doi.id_image '. |
'GROUP BY doi.id_image, doi.id_observation) t '; |
$resultatNbImages = $this->bdd->recupererTous($requeteNbImages . ' -- ' . __FILE__ . ':' . __LINE__); |
$total = (int) $resultatNbImages[0]['nb']; |
$this->navigation->setTotal($total); |
} |
return $liaisons; |
} |
/** |
* Charge les liaisons pour une seule image dont l'id est spécifié dans l'URL |
* Copie de chargerLiaisonsObs avec critère sur l'id_image uniquement |
* Supporte seulement le masque sur referentiel |
*/ |
private function chargerLiaisonsParId() { |
$idImage = $this->ressources[0]; |
// Récupérer les liaisons |
$requeteObs = ' SELECT SQL_CALC_FOUND_ROWS dob.id_observation as id_observation, dob.nom_referentiel, nom_sel, nom_sel_nn, nt, famille, ce_zone_geo, zone_geo, lieudit, station, milieu, '. |
' date_observation, dob.mots_cles_texte as mots_cles_texte, dob.commentaire as commentaire, di.mots_cles_texte as mots_cles_texte_image , date_transmission, '. |
' doi.id_image as id_image, di.ce_utilisateur as ce_utilisateur, prenom, nom, courriel, dob.prenom_utilisateur, dob.nom_utilisateur, dob.courriel_utilisateur, nom_original '. |
'FROM del_observation dob '. |
' INNER JOIN del_obs_image doi ON dob.id_observation = doi.id_observation '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '. |
' LEFT JOIN del_utilisateur du ON dob.ce_utilisateur = du.id_utilisateur '. |
' WHERE doi.id_image = '.intval($idImage); |
if (isset($this->parametres['masque.referentiel'])) { |
$requeteObs .= " AND dob.nom_referentiel LIKE '" . $this->parametres['masque.referentiel'] . "%'"; |
} |
$observations = $this->bdd->recupererTous($requeteObs . ' -- ' . __FILE__ . ':' . __LINE__); |
$total = $this->getFoundRows(); |
$this->navigation->setTotal($total); |
return $observations; |
} |
/** |
* Chargement depuis la bdd de toutes les liaisons entre images et observations |
* Méthode appelée uniquement lorsque les paramètres concernent une observation |
* */ |
private function chargerLiaisonsObs() { |
// Récupérer les liaisons |
$requeteObs = ' SELECT SQL_CALC_FOUND_ROWS dob.id_observation as id_observation, dob.nom_referentiel, nom_sel, nom_sel_nn, nt, famille, ce_zone_geo, zone_geo, lieudit, station, milieu, '. |
' date_observation, dob.mots_cles_texte as mots_cles_texte, dob.commentaire as commentaire, di.mots_cles_texte as mots_cles_texte_image , date_transmission, '. |
' doi.id_image as id_image, di.ce_utilisateur as ce_utilisateur, prenom, nom, courriel, dob.prenom_utilisateur, dob.nom_utilisateur, dob.courriel_utilisateur, nom_original '. |
'FROM del_observation dob '. |
' INNER JOIN del_obs_image doi ON dob.id_observation = doi.id_observation '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '. |
' LEFT JOIN del_utilisateur du ON dob.ce_utilisateur = du.id_utilisateur '; |
// Récupérer les conditions sous forme de tableau |
$conditionsObs = $this->getConditionsObs(); |
if (!empty($conditionsObs)) { |
$where = ' WHERE '.implode(' AND ', $conditionsObs); |
$requeteObs .= $where; |
} |
// Gérer le tri (uniquement si c'est date_observation) |
if (isset($this->parametres['tri']) && $this->parametres['tri'] == 'date_observation') { |
$ordre = isset($this->parametres['ordre']) ? $this->parametres['ordre'] : 'DESC'; |
$tri = ' ORDER BY '.$this->parametres['tri'].' '.$ordre.', doi.id_observation '.$ordre.' '; |
$requeteObs .= $tri; |
} |
$requeteObs .= $this->gestionBdd->getLimitSql(); |
$observations = $this->bdd->recupererTous($requeteObs . ' -- ' . __FILE__ . ':' . __LINE__); |
$total = $this->getFoundRows(); |
$this->navigation->setTotal($total); |
return $observations; |
} |
/** |
* Chargement depuis la bdd de toutes les liaisons entre images et observations |
* Méthode appelée uniquement lorsque les paramètres concernent les images |
* */ |
private function chargerLiaisonsImages() { |
// FIXME : si on faisait une requete à part pour compter, ca irait plus vite |
// Récupérer tous les ID d'image en fonction des paramètres de recherche |
$requeteImages = ' SELECT SQL_CALC_FOUND_ROWS '. |
' doi.id_image as id_image, dob.id_observation as id_observation, dob.nom_referentiel, nom_sel, nom_sel_nn, nt, famille, ce_zone_geo, zone_geo, lieudit, station, milieu, '. |
' date_observation, dob.mots_cles_texte as mots_cles_texte, dob.commentaire as commentaire, di.mots_cles_texte as mots_cles_texte_image , date_transmission, '. |
' di.ce_utilisateur as ce_utilisateur, prenom, nom, courriel, dob.prenom_utilisateur, dob.nom_utilisateur, dob.courriel_utilisateur, nom_original '. |
' FROM del_obs_image doi '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '. |
' INNER JOIN del_observation dob ON dob.id_observation = doi.id_observation '. |
' LEFT JOIN del_image_tag dit ON dit.ce_image = di.id_image '. |
' LEFT JOIN del_utilisateur du ON du.id_utilisateur = di.ce_utilisateur '; |
$conditionsImg = $this->getConditionsImages(); |
if (!empty($conditionsImg)) { |
$where = ' WHERE ('.implode(' OR ', $conditionsImg).') '; |
$where .= ' AND dit.actif = 1 '; |
$requeteImages .= $where; |
} |
// Gérer le tri, sur les votes ou sur les tags |
if (isset($this->parametres['tri'])) { |
$chaineTri = ''; |
$chaineOrdre = ''; |
if ($this->parametres['tri'] == 'votes') { |
$protocole = isset($this->parametres['protocole']) ? $this->parametres['protocole'] : 1; |
$requeteVotes = ' SELECT doi.id_image as id_image, IF(divo.ce_protocole = '.$protocole.', AVG(divo.valeur), 0) as total_votes '. |
' FROM del_obs_image doi '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '. |
' INNER JOIN del_observation dob ON dob.id_observation = doi.id_observation '. |
' LEFT JOIN del_image_vote divo ON doi.id_image = divo.ce_image '. |
' AND ce_protocole = '.$protocole.' '; |
// Et si on a cherché par tag ? |
if (isset($this->parametres['masque.tag'])) { |
$tag = $this->parametres['masque.tag']; |
$requeteVotes .= ' LEFT JOIN del_image_tag dit ON dit.ce_image = di.id_image '; |
$requeteVotes .= " WHERE (dit.tag_normalise LIKE '$tag%' OR di.mots_cles_texte LIKE '%$tag%') AND dit.actif = 1 "; |
} |
$requeteVotes .= ' GROUP BY doi.id_image, doi.id_observation '. |
' ORDER by total_votes '.$this->directionTri .', doi.id_observation '.$this->directionTri.' '. |
$this->gestionBdd->getLimitSql(); |
$resultatsVotes = $this->bdd->recupererTous($requeteVotes . ' -- ' . __FILE__ . ':' . __LINE__); |
$tabVotes = array(); |
foreach ($resultatsVotes as $vote) { |
$tabVotes[] = $vote['id_image']; |
} |
$strVotes = empty($tabVotes) ? "''" : implode(',', $tabVotes); |
// Et si on a cherché par tag ? |
if (isset($this->parametres['masque.tag'])) { |
$chaineTri .= ' AND '; |
} else { |
$chaineTri .= ' WHERE '; |
} |
$chaineTri .= ' doi.id_image IN ('.$strVotes.') '; |
$chaineOrdre = ' ORDER BY FIELD(doi.id_image, '.$strVotes.') '; |
} |
if ($this->parametres['tri'] == 'tags') { |
$requetetags = ' SELECT SQL_CALC_FOUND_ROWS doi.id_image, COUNT(id_tag) as total_tags '. |
' FROM del_obs_image doi LEFT JOIN del_image_tag dit ON dit.ce_image = doi.id_image AND dit.actif = 1 '. |
' INNER JOIN del_image di ON doi.id_image = di.id_image '. |
' INNER JOIN del_observation dob ON dob.id_observation = doi.id_observation '; |
if (isset($this->parametres['masque.tag_pictoflora'])) { |
// Et si on a cherché par tag ? |
$tag = $this->parametres['masque.tag_pictoflora']; |
$requetetags .= " WHERE (dit.tag_normalise LIKE '$tag%' OR di.mots_cles_texte LIKE '%$tag%') "; |
} |
$requetetags .= ' GROUP BY doi.id_image, doi.id_observation '. |
' ORDER by total_tags '.$this->directionTri.', doi.id_observation '.$this->directionTri. |
$this->gestionBdd->getLimitSql(); |
$resultatstags = $this->bdd->recupererTous($requetetags . ' -- ' . __FILE__ . ':' . __LINE__); |
$tabtags = array(); |
foreach ($resultatstags as $tag) { |
$tabtags[] = $tag['id_image']; |
} |
$strtags = empty($tabtags) ? "''" : implode(',', $tabtags); |
// Et si on a cherché par tag ? |
if (isset($this->parametres['masque.tag_pictoflora'])) { |
$chaineTri .= ' AND '; |
} else { |
$chaineTri .= ' WHERE '; |
} |
$chaineTri .= ' doi.id_image IN ('.$strtags.') '; |
$chaineOrdre = ' ORDER BY FIELD(doi.id_image, '.$strtags.') '; |
} |
$requeteImages .= $chaineTri.' GROUP BY doi.id_image, doi.id_observation '.$chaineOrdre; |
} else { |
$requeteImages .= ' GROUP BY doi.id_image, doi.id_observation'; // des fois, on a plusieurs observations pour la même image ... |
$requeteImages .= $this->gestionBdd->getLimitSql(); |
} |
$retour = $this->bdd->recupererTous($requeteImages . ' -- ' . __FILE__ . ':' . __LINE__); |
$total = $this->getFoundRows(); |
$this->navigation->setTotal($total); |
return $retour; |
} |
/** |
* Chargement depuis la bdd de toutes les liaisons entre images et observations |
* */ |
private function chargerLiaisons() { |
$champs = array('dob.id_observation as id_observation', 'nom_sel', 'nom_sel_nn', 'nt', 'famille', 'dob.nom_referentiel', 'ce_zone_geo', 'zone_geo', |
'lieudit', 'station', 'milieu', 'date_observation', 'dob.mots_cles_texte as mots_cles_texte', 'dob.commentaire as commentaire', |
'di.mots_cles_texte as mots_cles_texte_image ', 'date_transmission', 'di.id_image as id_image', 'di.ce_utilisateur as ce_utilisateur', |
'prenom', 'nom', 'courriel', 'dob.prenom_utilisateur', 'dob.nom_utilisateur', 'dob.courriel_utilisateur', 'nom_original'); |
// Attention le LEFT JOIN est indispensable pour ramener les images n'ayant pas de votes |
// en cas de tri par votes |
$requeteLiaisons = 'SELECT DISTINCT SQL_CALC_FOUND_ROWS '.implode(', ',$champs).' '. |
($this->doitJoindreTableVotes() ? |
', IF(dvote.ce_protocole = '.$this->parametres['protocole'].', AVG(dvote.valeur), 0) as total_votes ' : |
'' |
). |
($this->doitJoindreTableTags() ? |
// attention le DISTINCT est indispensable ! |
', (COUNT(DISTINCT dtag.id_tag) + '.$this->assemblercomptageOccurencesMotsClesCel().') as total_tags ' : |
'' |
). |
'FROM '.$this->gestionBdd->formaterTable('del_obs_image', 'doi'). |
'INNER JOIN del_image di '. |
'ON doi.id_image = di.id_image '. |
'INNER JOIN del_observation dob '. |
'ON doi.id_observation = dob.id_observation '. |
'LEFT JOIN del_utilisateur du '. |
'ON du.id_utilisateur = di.ce_utilisateur '. |
($this->doitJoindreTableTags() ? |
'LEFT JOIN del_image_tag dtag '. |
'ON doi.id_image = dtag.ce_image AND dtag.actif = 1 ' : |
'' |
). |
($this->doitJoindreTableVotes() ? |
'LEFT JOIN del_image_vote dvote '. |
'ON doi.id_image = dvote.ce_image AND dvote.ce_protocole = '.$this->parametres['protocole'] : |
'' |
); |
$requeteLiaisons .= $this->chargerClauseWhere(); |
$requeteLiaisons .= $this->getTri(); |
$requeteLiaisons .= $this->gestionBdd->getLimitSql(); |
$retour = $this->bdd->recupererTous($requeteLiaisons . ' -- ' . __FILE__ . ':' . __LINE__); |
$total = $this->getFoundRows(); |
$this->navigation->setTotal($total); |
return $retour; |
} |
/** |
* Retourner un tableau d'images formaté en fonction des liaisons trouvées |
* @param $liaisons les liaisons de la table del_obs_images |
* */ |
private function chargerImage($liaisons) { |
$images = array(); |
foreach ($liaisons as $liaison) { |
$idImage = $liaison['id_image']; |
if($liaison['ce_utilisateur'] == 0) { |
$liaison['prenom'] = $liaison['prenom_utilisateur']; |
$liaison['nom'] = $liaison['nom_utilisateur']; |
} |
// On enregistre l'ID de l'image pour n'effectuer qu'une seule requête par la suite |
$this->imageIds[] = $idImage; |
$index = $liaison['id_image'].'-'.$liaison['id_observation']; |
$images[$index] = array('id_image' => $idImage, 'binaire.href' => $this->formaterLienImage($idImage), |
'protocoles_votes' => array(), |
'mots_cles_texte' => $liaison['mots_cles_texte_image'], 'observation' => $this->formaterObservation($liaison)); |
} |
return $images; |
} |
/** |
* Charger les votes pour chaque image |
* */ |
private function chargerVotes($images) { |
$requeteVotes = 'SELECT v.*, p.* FROM '. |
$this->gestionBdd->formaterTable('del_image_vote', 'v'). |
' INNER JOIN del_image_protocole p '. |
'ON v.ce_protocole = p.id_protocole '. |
$this->chargerClauseWhereVotes(); |
$resultatsVotes = $this->bdd->recupererTous($requeteVotes . ' -- ' . __FILE__ . ':' . __LINE__); |
//TODO : faire une méthode formater vote |
$votes = $this->formaterVotes($resultatsVotes); |
foreach ($images as $id => $image) { |
if (isset($votes[$image['id_image']])) { |
$images[$id]['protocoles_votes'] = $votes[$image['id_image']]; |
} |
} |
return $images; |
} |
private function chargerClauseWhereVotes() { |
if (sizeof($this->imageIds) > 0) { |
$chaineImageIds = implode(',', $this->imageIds); |
$where[] = 'v.ce_image IN ('.$chaineImageIds.')'; |
} |
if (isset($this->parametres['protocole'])) { |
$where[] = 'v.ce_protocole = '.$this->proteger($this->parametres['protocole']); |
} |
$where = (!empty($where)) ? 'WHERE '.implode(' AND ', $where) : ''; |
return $where; |
} |
/************************************************************************************** |
* FONCTION DE CONFIGURATION ET UTILITAIRES * |
***************************************************************************************/ |
/** |
* Enregistrer dans les variables de classe les paramètres et ressources |
* @param $ressources |
* @param $parametres de recherche |
* */ |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
public function configurer() { |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingObservation = $this->conteneur->getParametre('mapping_observation'); |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
$tableauImages = $this->conteneur->getParametre('images'); |
if (empty($tableauImages)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [images] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
if ($this->conteneur->getParametre('url_images') == null) { |
$erreurs[] = '- paramètre "url_images" manquant ;'; |
} |
} |
if (empty($this->mappingObservation)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_observation] ou celui-ci est vide ;'; |
} else { |
$champsMappingObs = array('id_observation', 'date_observation', 'date_transmission', 'famille', 'nom_sel', 'nom_sel_nn', 'nt', |
'ce_zone_geo', 'lieudit', 'station', 'milieu', 'ce_utilisateur', 'nom', 'prenom'); |
foreach ($champsMappingObs as $champ) { |
if (!isset($this->mappingObservation[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour l\'observation est manquant ;'; |
} |
} |
} |
if (empty($this->mappingFiltre)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide ;'; |
} else { |
$champsMappingFiltre = array('famille', 'ns', 'nn', 'date', 'tag', 'commune'); |
foreach ($champsMappingFiltre as $champ) { |
if (!isset($this->mappingFiltre[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour l\'observation est manquant ;'; |
} |
} |
} |
$tris_possibles = $this->conteneur->getParametre('tris_possibles'); |
if (empty($tris_possibles)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le parametre tris_possibles ou celui-ci est vide ;'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Verifier que les paramètres de tri sont bien autorisés et qu'ils sont au bon format. |
*/ |
private function verifierParametresTri() { |
$erreurs = array(); |
$tris_possibles = $this->conteneur->getParametre('tris_possibles'); |
$tris_possibles_tableau = explode(',', $tris_possibles); |
if(isset($this->parametres['tri']) && !in_array($this->parametres['tri'], $tris_possibles_tableau)) { |
$erreurs[] = '- le type de tri demandé est incorrect, les valeurs possibles sont '.$tris_possibles.' ;'; |
} |
if(isset($this->parametres['tri']) && $this->parametres['tri'] == "votes") { |
if(!isset($this->parametres['protocole']) || !is_numeric($this->parametres['protocole'])) { |
$erreurs[] = '- Le paramètre protocole est obligatoire en cas de tri par vote et doit être un entier ;'; |
} |
} |
$directions_tri = array('asc', 'desc'); |
if(isset($this->parametres['ordre']) && !in_array($this->parametres['ordre'], $directions_tri)) { |
$erreurs[] = '- la direction du tri demandé est incorrecte, les valeurs supportées sont asc ou desc ;'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de l\'analyse des parametres du tri : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
private function verifierParametreFormatRetour() { |
$erreurs = array(); |
$formats_possibles_str = $this->conteneur->getParametre('formats_possibles'); |
$formats_possibles = explode(',',$formats_possibles_str); |
if(isset($this->parametres['format']) && !in_array($this->parametres['format'], $formats_possibles)) { |
$erreurs[] = "- le format d'image demandé n'est pas supporté ; Les format supportés sont : ".$formats_possibles_str; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de l\'analyse du format de retour demandé : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
private function initialiserFormatRetour() { |
$this->formatRetour = isset($this->parametres['format']) ? $this->parametres['format'] : $this->formatRetour; |
} |
/** |
* Initialiser les variables de tri depuis les paramètres |
* */ |
private function initialiserTri() { |
$this->tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : $this->tri; |
$this->directionTri = isset($this->parametres['ordre']) ? $this->parametres['ordre'] : $this->directionTri; |
} |
/** Pour eviter les requêtes trop gourmandes, on supprime les caractères passe-partout |
* @param les paramètres de l'application |
* */ |
public function nettoyerParametres($parametres) { |
$parametresRetour = array(); |
foreach ($parametres as $cle => $valeur) { |
$valSansPourcent = trim($valeur, "% "); |
if ($valSansPourcent != '') { |
$parametresRetour[$cle] = $valeur; |
} |
} |
return $parametresRetour; |
} |
/** |
* Nettoyer les jokers |
* @param la valeur du masque |
* */ |
private function remplacerParJokerCaractere($valeurMasque) { |
return str_replace(array('-',' '), '_', $valeurMasque); |
} |
//TODO: déplacer les fonctions ci dessus et dessous dans une classe |
// utilitaire |
/** |
* Supprimer les accents des chaines de caractères |
* */ |
function supprimerAccents($str, $charset='utf-8') |
{ |
$str = htmlentities($str, ENT_NOQUOTES, $charset); |
$str = preg_replace('#&([A-za-z])(?:acute|cedil|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str); |
$str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str); // pour les ligatures e.g. 'œ' |
$str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères |
return $str; |
} |
/** |
* Normaliser en supprimant les accents et en mettant en minuscule |
* @param $mot_cle le mot recherché |
* */ |
private function normaliserMotCle($mot_cle) { |
return mb_strtolower($this->supprimerAccents(trim($mot_cle))); |
} |
/** |
* Récupérer le numéro du département d'un fichier de configuration |
* */ |
private function obtenirIdDepartement($nomDpt) { |
$nomDpt = $this->supprimerAccents($nomDpt); |
$nomDpt = strtolower(str_replace(' ','-',$nomDpt)); |
$idDpt = $this->conteneur->getParametre($nomDpt); |
if($idDpt == null || $idDpt == ' ') { |
$idDpt = ' '; |
} |
return $idDpt; |
} |
/** |
* Obtenir le type de requête à exécuter en fonction des paramètres de recherche |
* @param $parametres les paramètres de l'application |
* */ |
private function getTypeRequete($ressources, $parametres) { |
// une image par id |
if ((count($ressources) == 1) && is_numeric($ressources[0])) { |
return 'id'; |
} |
$typeRequete = 'simple'; |
// Dans ce cas précis, les informations concernant le depart, la limite ou l'ordre ne |
// rentre pas en compte dans le type de requête ; ce ne sont que des compléments. |
unset($parametres['navigation.depart']); |
unset($parametres['navigation.limite']); |
unset($parametres['ordre']); |
// En revanche, chaque masque est associé à un type de requête particulier. |
$masquesObservation = array('masque', 'masque.departement', 'masque.ns', 'masque.genre', 'masque.date', 'masque.commune', 'masque.famille', 'masque.auteur', 'masque.nn', 'masque.referentiel', 'masque.tag_cel'); |
$masquesImage = array('masque', 'masque.tag_pictoflora'); |
// Le type de requête est défini par les tables qu'il doit inclure (observation, image, ou les deux) |
$requeteSimple = false; |
$pourObservation = false; |
$pourImage = false; |
// S'il n'y a aucun paramètre, on lance une requête simple |
if (empty($parametres)) { |
$requeteSimple = true; |
} |
// Si l'un des masques demandé concerne l'observation |
foreach ($masquesObservation as $masque) { |
if (isset($parametres[$masque])) { |
$pourObservation = true; |
break; |
} |
} |
// Si l'un des masques demandé concerne les images |
foreach ($masquesImage as $masque) { |
if (isset($parametres[$masque])) { |
$pourImage = true; |
break; |
} |
} |
// Selon les tri |
if (isset($parametres['tri'])) { |
switch ($parametres['tri']) { |
case 'votes' : |
case 'tags' : |
$pourImage = true; |
break; |
default : //case 'date_observation' : |
if (sizeof($parametres) > 1) { |
$pourObservation = true; |
} |
} |
} |
// Vérifier la combinaison des booléens pour en déduire le type de requête |
if ($pourObservation && $pourImage) { |
$typeRequete = 'obs-images'; |
} else { |
if ($pourImage) { |
$typeRequete = 'images'; |
} else if ($pourObservation) { |
$typeRequete = 'obs'; |
} else { // if ($requeteSimple) |
$typeRequete = 'simple'; |
} |
} |
return $typeRequete; |
} |
private function doitJoindreTableVotes() { |
return ($this->tri == 'votes'); |
} |
private function doitJoindreTableTags() { |
return ($this->tri == 'tags'); |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater une observation depuis une ligne liaison |
* @param $liaison liaison issue de la recherche |
* @return $observation l'observation mise en forme |
* */ |
private function formaterObservation($liaison) { |
$observation = array(); |
foreach ($this->mappingObservation as $nomOriginal => $nomFinal) { |
$observation[$nomFinal] = $liaison[$nomOriginal]; |
} |
return $observation; |
} |
/** |
* Formater une observation depuis une ligne liaison |
* @param $liaison liaison issue de la recherche |
* @return $observation l'observation mise en forme |
* */ |
private function formaterVotes($votes) { |
$retour = array(); |
foreach ($votes as $vote) { |
$retour_vote = array(); |
foreach ($vote as $param=>$valeur) { |
if (strpos($this->mappingVotes[$param], 'protocole.') === 0) { |
$retour_protocole[$this->mappingVotes[$param]] = $valeur; |
} else { |
$retour_vote[$this->mappingVotes[$param]] = $valeur; |
} |
} |
if (!isset($retour[$vote['ce_image']][$vote['ce_protocole']])) { |
$retour[$vote['ce_image']][$vote['ce_protocole']] = $retour_protocole; |
} |
$retour[$vote['ce_image']][$vote['ce_protocole']]['votes'][$vote['id_vote']] = $retour_vote; |
} |
return $retour; |
} |
/** |
* Formater le lien de l'image en fonction du fichier de config et de l'identifiant de l'image |
* */ |
private function formaterLienImage($idImage) { |
$idImage = sprintf('%09s', $idImage); |
$url = $this->conteneur->getParametre('url_images'); |
$urlImage = sprintf($url, $idImage, $this->formatRetour); |
return $urlImage; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/images/VotesImage.php |
---|
New file |
0,0 → 1,332 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class VotesImage { |
private $imageIds = array(); |
private $conteneur; |
private $navigation; |
private $masque; |
protected $gestionBdd; |
protected $bdd; |
private $ressources; |
private $parametres; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_votes.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_votes.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) { |
// Gestion des configuration du script |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
$this->configurer(); |
$this->verifierConfiguration(); |
// Lancement du service |
$votes = $this->chargerVotes(); |
$total = $this->compterVotes(); |
$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' => $votes); |
return $resultat; |
} |
public function ajouter($ressources, $parametres) { |
$this->verifierParametresAjoutModif($ressources, $parametres); |
$insertion = 'INSERT INTO del_image_vote '. |
'(ce_image, ce_protocole, ce_utilisateur, valeur, date) '. |
'VALUES ('. |
$this->proteger($ressources[0]).','. |
$this->proteger($parametres['protocole']).','. |
$this->proteger($parametres['utilisateur']).','. |
$this->proteger($parametres['valeur']).', '. |
'NOW()'. |
');'; |
$resultat = $this->bdd->requeter($insertion); |
if ($resultat == false) { |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} else { |
$retour = $this->bdd->recupererIdDernierAjout(); |
$resultat = new ResultatService(); |
$resultat->corps = array('id_vote' => $retour); |
self::updateStats($this->bdd, $ressources[0],$parametres['protocole']); |
return $resultat; |
} |
} |
public function modifier($ressources, $parametres) { |
$this->verifierParametresAjoutModif($ressources, $parametres); |
//TODO: est il nécessaire de tester si ça existe et renoyer une erreur 404 |
// si l'on vote ? Cela peut ralentir considérablement les choses |
// une contrainte d'unicité sur le triplet image, protocole, vote existe, |
// ça suffira pour provoquer une erreur 500 |
$modification = 'UPDATE del_image_vote '. |
'SET valeur = '.$this->proteger($parametres['valeur']).', '. |
' date = NOW() '. |
'WHERE '. |
'ce_image = '.$this->proteger($ressources[0]).' AND '. |
'ce_protocole = '.$this->proteger($parametres['protocole']).' AND '. |
'ce_utilisateur = '.$this->proteger($parametres['utilisateur']).' '; |
$resultat = $this->bdd->requeter($modification); |
if ($resultat == false) { |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} else { |
self::updateStats($this->bdd, $ressources[0],$parametres['protocole']); |
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_OK); |
} |
} |
public function supprimer($ressources) { |
$id_image = $ressources[0]; |
$id_vote = $ressources[2]; |
$id_vote_p = $this->proteger($id_vote); |
$requete_infos_vote = 'SELECT * FROM del_image_vote '. |
'WHERE id_vote = '.$id_vote_p; |
$infos_vote = $this->bdd->recuperer($requete_infos_vote); |
if ($infos_vote == false) { |
throw new Exception("Aucun vote ne correspond à cet identifiant", RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE); |
} |
$controle_acces = new ControleAcces($this->conteneur); |
$utilisateur = $controle_acces->getInfosUtilisateurConnecte(); |
if($utilisateur['id_utilisateur'] != $infos_vote['ce_utilisateur'] && |
$controle_acces->getIdAnonymeTemporaire() != $infos_vote['ce_utilisateur']) { |
throw new Exception("Vous n'êtes pas autorisé à supprimer ce vote", |
RestServeur::HTTP_CODE_ACCES_NON_AUTORISE); |
} |
$suppression = 'DELETE FROM del_image_vote '. |
'WHERE id_vote = '.$id_vote_p; |
$resultat = $this->bdd->requeter($suppression); |
if ($resultat == false) { |
throw new Exception("Impossible de supprimer le vote", RestServeur::HTTP_CODE_ERREUR); |
} else { |
self::updateStats($this->bdd, $ressources[0],$infos_vote['ce_protocole']); |
} |
} |
static function updateStats($db, $id_image, $id_proto) { |
$id_image = intval($id_image); |
$id_proto = intval($id_proto); |
if(!$id_image || !$id_proto) throw new Exception("Ne peut mettre à jour les statistiques de vote", |
RestServeur::HTTP_CODE_ERREUR); |
/* REPLACE ... SELECT: réinitalise les champs non-défini (MySQL 5.1) |
REPLACE ... SET a=b, c=d: idem ou plusieurs requête |
Du coup il faut récupérer les données actuelles mais REPLACE ne le permet pas |
(http://dev.mysql.com/doc/refman/5.5/en/replace.html : |
You cannot refer to values from the current row and use them in the new row.) |
D'où INSERT ... ON DUPLICATE KEY UPDATE. Notons que VALUES() récupère la valeur |
*associée* au champ passé en paramètre, c'est à dire VALUES(moyenne) == divo.moyenne */ |
$db->requeter(sprintf('INSERT INTO del_image_stat (ce_image, ce_protocole, moyenne, nb_votes)'. |
' SELECT ce_image, ce_protocole, AVG(valeur) AS moyenne, COUNT(valeur) AS nb_votes'. |
' FROM del_image_vote divo'. |
' WHERE ce_image = %d AND ce_protocole = %d GROUP BY ce_image, ce_protocole'. |
' ON DUPLICATE KEY UPDATE moyenne = VALUES(moyenne), nb_votes = VALUES(nb_votes)', |
$id_image, $id_proto)); |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
public function configurer() { |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
$tableauImages = $this->conteneur->getParametre('images'); |
if (empty($tableauImages)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [images] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
} |
if (empty($this->mappingVotes)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_votes] ou celui-ci est vide ;'; |
} else { |
$champsMappingObs = array('ce_protocole','id_vote','valeur','ce_image', 'ce_utilisateur', 'nom', 'prenom'); |
foreach ($champsMappingObs as $champ) { |
if (!isset($this->mappingVotes[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour le vote est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
public function verifierParametresAjoutModif($ressources, $parametres) { |
$erreurs = array(); |
if (!is_numeric($ressources[0])) { |
$erreurs[] = '- le paramètre indiquant l\'identifiant de l\'image doit être numérique ;'; |
} |
if (!isset($parametres['utilisateur'])) { |
$erreurs[] = '- paramètre "utilisateur" manquant ;'; |
} |
if (!isset($parametres['protocole'])) { |
$erreurs[] = '- paramètre "id_protocole" manquant ;'; |
} else { |
if (!is_numeric($parametres['protocole'])) { |
$erreurs[] = '- le paramètre "protocole" doit être numérique ;'; |
} |
} |
if (!isset($parametres['valeur'])) { |
$erreurs[] = '- paramètre "valeur" manquant ;'; |
} else { |
if (!is_numeric($parametres['valeur'])) { |
$erreurs[] = '- le paramètre "valeur" doit être numérique ;'; |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
public function verifierParametresSuppression($ressources, $parametres) { |
$erreurs = array(); |
if (!is_numeric($ressources[0])) { |
$erreurs[] = '- le paramètre indiquant l\'identifiant de l\'image doit être numérique ;'; |
} |
/*if (!is_numeric($parametres['id_protocole'])) { |
$erreurs[] = '- le paramètre indiquant l\'identifiant du vote doit être numérique ;'; |
}*/ |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where[] = 'WHERE ce_image = '.$this->proteger($this->ressources[0]); |
if (isset($this->parametres['protocole'])) { |
$where[] = 'ce_protocole = '.$this->proteger($this->parametres['protocole']); |
} |
return implode(' AND ', $where); |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES IMAGES |
--------------------------------------------------------------------------------*/ |
/** |
* Charger les votes pour chaque image |
* */ |
private function chargerVotes() { |
$requeteVotes = 'SELECT * FROM '. |
$this->gestionBdd->formaterTable('del_image_vote'). |
$this->chargerClauseWhere(); |
$resultatsVotes = $this->bdd->recupererTous($requeteVotes); |
$votes = $this->formaterVotes($resultatsVotes); |
return $votes; |
} |
/** |
* Compter le nombre total d'images dans la base pour affichage dans entete. |
* */ |
private function compterVotes() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater une observation depuis une ligne liaison |
* @param $liaison liaison issue de la recherche |
* @return $observation l'observation mise en forme |
* */ |
private function formaterVotes($votes) { |
$retour = array(); |
foreach ($votes as $vote) { |
foreach ($vote as $p=>$valeur) { |
$retour[$vote['id_vote']][$this->mappingVotes[$p]] = $valeur; |
} |
} |
return $retour; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/images/ListeImages.php |
---|
New file |
0,0 → 1,649 |
<?php |
/** |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @copyright Copyright (c) 2013, Tela Botanica (accueil@tela-botanica.org) |
* @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 |
* @see http://www.tela-botanica.org/wikini/identiplante/wakka.php?wiki=IdentiPlante_PictoFlora_MoteurRecherche |
* |
* Backend pour PictoFlora (del.html#page_recherche_images) |
* |
* |
* == Notes == |
* |
* tri=votes et tri=tags: affectent le choix des images affichées (donc getIdImages()) |
* Cependant ce total ne nous intéresse même pas (MoyenneVotePresenteur.java s'en occupe). |
* Seul tri=date_transmission nous évite l'AVG() + GROUP BY |
* |
* protocole: il affecte l'affichage des information, mais le JSON contient déjà |
* l'intégralité (chercher les données de vote pour 1 ou plusieurs protocoles) est quasi-identique. |
* Par contre, le tri par moyenne des votes, sous-entend "pour un protocole donné". |
* Dès lors le choix d'un protocole doit avoir été fait afin de régler le JOIN et ainsi l'ORDER BY. |
* (cf requestFilterParams()) |
* |
* Histoire: auparavant (pré-r142x) un AVG + GROUP BY étaient utilisés pour générer on-the-fly les valeurs |
* utilisées ensuite pour l'ORDER BY. La situation à base de del_image_stat |
* est déjà bien meilleure sans être pour autant optimale. cf commentaire de sqlAddConstraint() |
* |
* |
* Tags: |
* Le comportement habituel dans le masque *général*: les mots sont séparés par des espaces, |
* implod()ed par des AND (tous les mots doivent matcher). |
* Et le test effectué doit matcher sur: |
* %(les tags d'observations)% *OU* %(les tags d'images)% *OU* %(les tags publics)% |
* |
* Le comportement habituel dans le masque *tag*: les mots ne sont *pas* splittés (1 seule expression), |
* Et le test effectué doit matcher sur: |
* ^(expression)% *OU* %(expression)% [cf getConditionsImages()] |
* |
* Par défaut les tags sont comma-separated (OU logique). |
* Cependant pour conserver le comportement du masque général qui sous-entend un ET logique sur |
* des tags séparés par des espaces recherche |
* |
* TODO: |
* -affiner la gestion de passage de mots-clefs dans le masque général. |
* - subqueries dans le FROM pour les critère WHERE portant directement sur v_del_image |
* plutôt que dans WHERE (qui nécessite dès lors un FULL-JOIN) |
* (http://www.mysqlperformanceblog.com/2007/04/06/using-delayed-join-to-optimize-count-and-limit-queries/) |
* - éviter de dépendre d'une jointure systématique sur `cel_obs`, uniquement pour `(date_)transmission |
* (cf VIEW del_image) |
* - poursuivre la réorganisation des méthodes statiques parmis Observation, ListeObservations et ListeImages2 |
* - *peut-être*: passer requestFilterParams() en méthode de classe |
* |
* |
* MySQL sux: |
* EXPLAIN SELECT id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1 LIMIT 1); |
* MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery |
* EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT 3); |
* PRIMARY |
* EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT MIN(3)); |
* DEPENDENT SUBQUERY ... ... ... mwarf ! |
* EXPLAIN SELECT id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1); |
* 5.5: MATERIALIZED del_image_tag ALL ce_image NULL NULL NULL 38276 Using where |
* 5.1: DEPENDENT SUBQUERY del_image_tag index_subquery ce_image ce_image 8 func 1 Using where |
* FORCE INDEX/IGNORE INDEX semble incapable de résoudre le problème de l'optimiseur MySQL |
* |
*/ |
require_once(dirname(__FILE__) . '/../DelTk.php'); |
require_once(dirname(__FILE__) . '/../observations/Observation.php'); |
restore_error_handler(); |
restore_exception_handler(); |
error_reporting(E_ALL); |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc&masque=plop |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc&protocole=3 |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc&protocole=3&masque=plop |
class ListeImages { |
// TODO: PHP-x.y, ces variables devrait être des "const" |
static $format_image_possible = array('O','CRX2S','CRS','CXS','CS','XS','S','M','L','XL','X2L','X3L'); |
static $tri_possible = array('date_transmission', 'date_observation', 'votes', 'tags'); |
// en plus de ceux dans DelTk |
static $parametres_autorises = array('protocole', 'masque.tag_cel', 'masque.tag_pictoflora', 'masque.milieu'); |
static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10, |
'tri' => 'date_transmission', 'ordre' => 'desc', |
// spécifiques à PictoFlora: |
'format' => 'XL'); |
static $default_proto = 3; // proto par défaut: capitalisation d'img (utilisé uniquement pour tri=(tags|votes)) |
static $mappings = array( |
'observations' => array( // v_del_image |
"id_observation" => 1, |
"date_observation" => 1, |
"date_transmission" => 1, |
"famille" => "determination.famille", |
"nom_sel" => "determination.ns", |
"nom_sel_nn" => "determination.nn", |
"nom_referentiel" => "determination.referentiel", |
"nt" => "determination.nt", |
"ce_zone_geo" => "id_zone_geo", |
"zone_geo" => 1, |
"lieudit" => 1, |
"station" => 1, |
"milieu" => 1, |
"mots_cles_texte" => "mots_cles_texte", |
"commentaire" => 1, |
"ce_utilisateur" => "auteur.id", |
"nom_utilisateur" => "auteur.nom", |
"prenom_utilisateur" => "auteur.prenom", |
), |
'images' => array( // v_del_image |
'id_image' => 1, |
// l'alias suivant est particulier: in-fine il doit s'appeler mots_cles_texte |
// mais nous afin d'éviter un conflit d'alias nous le renommons plus tard (reformateImagesDoubleIndex) |
'i_mots_cles_texte' => 1 |
)); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_images.ini'); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
public function consulter($ressources, $parametres) { |
/* Certes nous sélectionnons ici (nom|prenom|courriel)_utilisateur de cel_obs, mais il ne nous intéressent pas |
Par contre, ci-dessous nous prenons i_(nom|prenom|courriel)_utilisateur. |
Notons cependant qu'aucun moyen ne devrait permettre que i_*_utilisateur != *_utilisateur |
Le propriétaire d'une obs et de l'image associée est *toujours* le même. */ |
array_walk(self::$mappings['observations'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
array_walk(self::$mappings['images'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
// pour les votes, les mappings de "Observation" nous suffisent |
array_walk(Observation::$mappings['votes'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
// la nécessité du 'groupby' dépend des 'join's utilisés (LEFT ou INNER) ainsi que de la cardinalité |
// de `ce_image` dans ces tables jointes. |
// Contrairement à IdentiPlantes, nous n'avons de HAVING pour PictoFlora, mais par contre un ORDER BY |
$req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'orderby' => array()); |
$db = $this->bdd; |
// filtrage de l'INPUT général, on réutilise 90% de identiplante en terme de paramètres autorisés |
// ($parametres_autorises) sauf... masque.type qui fait des modif' de WHERE sur les mots-clefs. |
// Évitons ce genre de chose pour PictoFlora et les risques de conflits avec masque.tag |
// même si ceux-ci sont improbables (pas d'<input> pour cela). |
$params_ip = DelTk::requestFilterParams($parametres, |
array_diff(DelTk::$parametres_autorises, |
array('masque.type')), |
$this->conteneur); |
// notre propre filtrage sur l'INPUT |
$params_pf = self::requestFilterParams($parametres, |
array_merge(DelTk::$parametres_autorises, |
self::$parametres_autorises)); |
/* filtrage des tags + sémantique des valeurs multiples: |
Lorsqu'on utilise masque.tag* pour chercher des tags, ils sont |
postulés comme séparés par des virgule, et l'un au moins des tags doit matcher. */ |
$params_pf['masque.tag_cel'] = DelTk::buildTagsAST(@$parametres['masque.tag_cel'], 'OR', ','); |
if(!isset($parametres['masque.tag_pictoflora']) && isset($parametres['masque.tag'])) { |
$parametres['masque.tag_pictoflora'] = $parametres['masque.tag']; |
} |
$params_pf['masque.tag_pictoflora'] = DelTk::buildTagsAST(@$parametres['masque.tag_pictoflora'], 'OR', ','); |
$params = array_merge( |
DelTk::$default_params, // paramètre par défaut Identiplante |
self::$default_params, // paramètres par défaut PictoFlora |
$params_ip, // les paramètres passés, traités par Identiplante |
$params_pf); // les paramètres passés, traités par PictoFlora |
if(isset($parametres['format'])) { |
$params['format'] = $parametres['format']; |
} |
// création des contraintes (génériques de DelTk) |
DelTk::sqlAddConstraint($params, $db, $req); |
// création des contraintes spécifiques (sur les tags essentiellement) |
self::sqlAddConstraint($params, $db, $req, $this->conteneur); |
// création des contraintes spécifiques impliquées par le masque général |
self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur); |
// l'ORDER BY s'avére complexe |
self::sqlOrderBy($params, $db, $req); |
// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS) |
// $idobs_tab = ListeObservations::getIdObs($params, $req, $db); |
$idobs_tab = self::getIdImages($params, $req, $db); |
// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats dans la table del_obs_images |
if(!$idobs_tab) { |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => DelTk::makeJSONHeader(0, $params, Config::get('url_service')), |
'resultats' => array()); |
return $resultat; |
/* |
header('HTTP/1.0 404 Not Found'); |
// don't die (phpunit) |
throw(new Exception()); */ |
} |
// idobs est une liste (toujours ordonnée) des id d'observations recherchées |
$idobs = array_values(array_map(create_function('$a', 'return $a["id_image"];'), $idobs_tab)); |
$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']); |
$liaisons = self::chargerImages($db, $idobs); |
/* |
// Q&D |
$images = array(); |
$o = new Observation($this->conteneur); |
foreach($idobs as $i) { |
$images[$i] = $o->consulter(array($i), array('justthrow' => 1)); |
} |
*/ |
list($images, $images_keyed_by_id_image) = self::reformateImagesDoubleIndex( |
$liaisons, |
$this->conteneur->getParametre('images.url_images'), |
$params['format']); |
// on charge les votes pour ces images et pour *tous* les protocoles |
$votes = Observation::chargerVotesImage($db, $liaisons, NULL); |
// subtilité, nous passons ici le tableau d'images indexé par id_image qui est bien plus pratique pour |
// associer les vote à un tableau, puisque nous ne connaissons pas les id d'observation. |
// Mais magiquement (par référence), cela va remplir notre tableau indexé par couple d'id (id_image, id_observation) |
// cf reformateImagesDoubleIndex() à qui revient la tâche de créer ces deux versions simultanément lorsque |
// c'est encore possible. |
if($votes) Observation::mapVotesToImages($votes, $images_keyed_by_id_image); |
// les deux masques de tags sont transformés en AST dans le processus de construction de la requête. |
// Reprenous les paramètres originaux non-nettoyés (ils sont valables car le nettoyage est déterministe) |
$params_header = array_merge($params, array_filter(array('masque.tag_cel' => @$parametres['masque.tag_cel'], |
'masque.tag_pictoflora' => @$parametres['masque.tag_pictoflora']))); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => DelTk::makeJSONHeader($total, $params_header, Config::get('url_service')), |
'resultats' => $images); |
return $resultat; |
} |
/** |
* TODO: partie spécifique liées à la complexité de PictoFlora: |
* génération de la clause ORDER BY (génère la valeur de la clef orderby' de $req) |
* nécessaire ? tableau sprintf(key (tri) => value (ordre), key => value ...). |
* Cependant il est impensable de joindre sur un AVG() des valeurs des votes pour |
* *chaque* couple (id_image, protocole) de la base afin de trouver les images |
* les "mieux notées", ou bien les images ayant le "plus de tags" (COUNT()) |
*/ |
static function sqlOrderBy($p, $db, &$req) { |
// parmi self::$tri_possible |
if($p['tri'] == 'votes') { // LEFT JOIN sur "dis" ci-dessous |
$req['orderby'] = 'dis.moyenne ' . $p['ordre'] . ', dis.nb_votes ' . $p['ordre']; |
return; |
} |
if($p['tri'] == 'tags') { // LEFT JOIN sur "dis" ci-dessous |
$req['orderby'] = 'dis.nb_tags ' . $p['ordre']; |
return; |
} |
if($p['tri'] == 'date_observation') { |
$req['orderby'] = 'date_observation ' . $p['ordre'] . ', id_observation ' . $p['ordre']; |
return; |
} |
// tri == 'date_transmission' |
// avant cel:r1860, date_transmission pouvait être NULL |
// or nous voulons de la consistence (notamment pour phpunit) |
$req['orderby'] = 'date_transmission ' . $p['ordre'] . ', id_observation ' . $p['ordre']; |
} |
/* |
* in $p: un tableau de paramètres, dont: |
* - 'masque.tag_cel': *tableau* de mots-clefs à chercher parmi cel_image.mots_clefs_texte |
* - 'masque.tag_pictoflora': *tableau* de mots-clefs à chercher parmi del_image_tag.tag_normalise |
* - 'tag_explode_semantic': défini si les éléments sont tous recherchés ou NON |
* |
* in/ou: $req: un tableau de structure de requête MySQL |
* |
* Attention, le fait que nous cherchions masque.tag_cel OU/ET masque.tag_cel |
* ne dépend pas de nous, mais du niveau supérieur de construction de la requête: |
* Soit directement $this->consulter() si des masque.tag* sont passés |
* (split sur ",", "AND" entre chaque condition, "OR" pour chaque valeur de tag) |
* Soit via sqlAddMasqueConstraint(): |
* (pas de split, "OR" entre chaque condition) [ comportement historique ] |
* équivalent à: |
* (split sur " ", "OR" entre chaque condition, "AND" pour chaque valeur de tag) |
* |
*/ |
static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) { |
// TODO implement dans DelTk ? |
if(!empty($p['masque.milieu'])) { |
$req['where'][] = 'vdi.milieu LIKE '.$db->proteger('%' . $p['masque.milieu'].'%'); |
} |
/* Pour le tri par AVG() des votes nous avons toujours un protocole donné, |
celui-ci indique sur quels votes porte l'AVG. |
(c'est un *vote* qui porte sur un protocole et non l'image elle-même) */ |
/* TODO: perf problème: |
1) SQL_CALC_FOUND_ROWS: fixable en: |
- dissociant le comptage de la récup d'id + javascript async |
- ou ne rafraîchir le total *que* pour les requête impliquant un changement de pagination |
(paramètre booléen "with-total" par exemple) |
2) jointure forcées: en utilisant `del_imagè`, nous forçons les 2 premiers |
JOIN sur cel_obs_images et cel_obs pour filtrer sur "transmission". |
Dénormaliser cette valeur et l'intégrer à `cel_images` ferait économiser cette couteuse |
jointure, ... lorsqu'aucun masque portant sur `cel_obs` n'est utilisé |
3) non-problème: l'ordre des joins est forcé par l'usage de la vue: |
(cel_images/cel_obs_images/cel_obs/del_image_stat) |
Cependant c'est à l'optimiseur de définir son ordre préféré. */ |
if($p['tri'] == 'votes') { |
// $p['protocole'] *est* défini (cf requestFilterParams()) |
// petite optimisation: INNER JOIN si ordre DESC car les 0 à la fin |
if($p['ordre'] == 'desc') { |
// pas de group by nécessaire pour cette jointure |
// PRIMARY KEY (`ce_image`, `ce_protocole`) |
$req['join'][] = sprintf('INNER JOIN del_image_stat dis'. |
' ON vdi.id_image = dis.ce_image'. |
' AND dis.ce_protocole = %d', |
$p['protocole']); |
} else { |
$req['join'][] = sprintf('LEFT JOIN del_image_stat dis'. |
' ON vdi.id_image = dis.ce_image'. |
' AND dis.ce_protocole = %d', |
$p['protocole']); |
// nécessaire (dup ce_image dans del_image_stat) |
$req['groupby'][] = 'vdi.id_observation'; |
} |
} |
if($p['tri'] == 'tags') { |
$req['join'][] = sprintf('%s JOIN del_image_stat dis ON vdi.id_image = dis.ce_image', |
($p['ordre'] == 'desc') ? 'INNER' : 'LEFT'); |
// nécessaire (dup ce_image dans del_image_stat) |
$req['groupby'][] = 'vdi.id_observation'; |
} |
// car il ne sont pas traités par la générique requestFilterParams() les clefs "masque.tag_*" |
// sont toujours présentes; bien que parfois NULL. |
if($p['masque.tag_cel']) { |
if(isset($p['masque.tag_cel']['AND'])) { |
// TODO: utiliser les tables de mots clefs normaliées dans tb_cel ? |
// et auquel cas laisser au client le choix du couteux "%" ? |
$tags = $p['masque.tag_cel']['AND']; |
array_walk($tags, create_function('&$val, $k, $db', |
'$val = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) LIKE %s", |
$db->proteger("%".$val."%"));'), |
$db); |
$req['where'][] = '(' . implode(' AND ', $tags) . ')'; |
} |
else { |
$req['where'][] = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) REGEXP %s", |
$db->proteger(implode('|', $p['masque.tag_cel']['OR']))); |
} |
} |
if($p['masque.tag_pictoflora']) { |
// inutilisable pour l'instant |
// self::sqlAddPictoFloraTagConstraint1($p, $db, $req); |
// intéressante, mais problème d'optimiseur MySQL 5.5 (dependant subquery) |
// self::sqlAddPictoFloraTagConstraint2($p, $db, $req); |
// approche fiable mais sous-optimale |
self::sqlAddPictoFloraTagConstraint3($p, $db, $req); |
} |
} |
/* approche intéressante si les deux problèmes suivants peuvent être résolu: |
- LEFT JOIN => dup => *gestion de multiples GROUP BY* (car in-fine un LIMIT est utilisé) |
- dans le cas d'un ET logique, comment chercher les observations correspondantes ? */ |
static function sqlAddPictoFloraTagConstraint1($p, $db, &$req) { |
// XXX: utiliser tag plutôt que tag_normalise ? |
$req['join'][] = 'LEFT JOIN del_image_tag dit ON dit.ce_image = vdi.id_image'; |
$req['where'][] = 'dit.actif = 1'; |
$req['groupby'][] = 'vdi.id_image'; // TODO: nécessaire (car dup') mais risque de conflict en cas de tri (multiple GROUP BY) |
// XXX: en cas de ET, possibilité du GROUP_CONCAT(), mais probablement sans grand intérêt, d'où une boucle |
if(isset($p['masque.tag_pictoflora']['AND'])) { |
// TODO/XXX : comment matcher les observations ayant tous les mots-clef passés ? |
// ... le LEFT-JOIN n'y semble pas adapté |
} |
else { |
$protected_tags = array(); |
foreach($p['masque.tag_pictoflora']['OR'] as $tag) $protected_tags[] = $db->proteger(strtolower($tag)); |
$req['where'][] = sprintf('tag_normalise IN (%s)', implode(',', $protected_tags)); |
} |
} |
// inutilisé pour l'instant pour cause de soucis d'optimiseur MySQL (cf commentaire en intro) |
static function sqlAddPictoFloraTagConstraint2($p, $db, &$req) { |
// Note à propos des 4 "@ instruction" ci-dessous (notamment sur recupererTous()) |
// REGEXP permet un puissant mécanisme de sélection des obs/image à qui sait |
// l'utiliser, mais peut sortir une erreur en cas de REGEXP invalide |
// ex: REGEX "^(". |
// Pour l'heure nous ignorons ce type d'erreur car aucun de nos champ de recherche |
// ne peuvent (ou ne devrait) comporter des meta-caractères |
// ([])?*+\\ |
if(isset($p['masque.tag_pictoflora']['AND'])) { |
// optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT() |
// donc nous utilisons des ".*" plutôt que de multiples conditions et "|" |
sort($p['masque.tag_pictoflora']['AND']); |
$req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s)", |
$db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND']))); |
} |
else { |
$req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise) REGEXP %s)", |
$db->proteger(implode('|', $p['masque.tag_pictoflora']['OR']))); |
} |
} |
// si l'on est bassiné par les "DEPENDENT SUBQUERY", nous la faisons donc indépendemment via cette fonction |
static function sqlAddPictoFloraTagConstraint3($p, $db, &$req) { |
if(isset($p['masque.tag_pictoflora']['AND'])) { |
// optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT() |
// donc nous utilisons des ".*" plutôt que de multiples conditions et "|" |
sort($p['masque.tag_pictoflora']['AND']); |
// plutôt que db->connexion->query->fetchColumn(), une API pourrie nous oblige à ... |
$ids = @$db->recupererTous(sprintf( |
"SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s", |
$db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND'])))); |
// puis: |
$ids = @array_map(create_function('$e', 'return $e["ce_image"];'), $ids); |
$ids = !empty($ids) ? implode(',', $ids) : 'SELECT ce_image FROM del_image_tag WHERE false'; |
$req['where'][] = sprintf("vdi.id_image IN (%s)", $ids); |
} |
else { |
$ids = @$db->recupererTous(sprintf( |
"SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise) REGEXP %s", |
$db->proteger(implode('|', $p['masque.tag_pictoflora']['OR'])))); |
$ids = @array_map(create_function('$e', 'return $e["ce_image"];'), $ids); |
$ids = !empty($ids) ? implode(',', $ids) : 'SELECT ce_image FROM del_image_tag WHERE false'; |
$req['where'][] = sprintf("vdi.id_image IN (%s)", $ids); |
} |
} |
static function getIdImages($p, $req, $db) { |
return $db->recupererTous(sprintf( |
'SELECT SQL_CALC_FOUND_ROWS id_image' . |
' FROM v_del_image vdi'. |
' %s' . // LEFT JOIN if any |
' WHERE %s'. // where-clause ou TRUE |
' %s'. // group-by |
' ORDER BY %s'. |
' LIMIT %d, %d -- %s', |
$req['join'] ? implode(' ', array_unique($req['join'])) : '', |
$req['where'] ? implode(' AND ', $req['where']) : 'TRUE', |
$req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '', |
$req['orderby'], |
$p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__)); |
} |
static function chargerImages($db, $idImg) { |
$obs_fields = DelTk::sqlFieldsToAlias(self::$mappings['observations'], NULL); |
$image_fields = DelTk::sqlFieldsToAlias(self::$mappings['images'], NULL); |
return $db->recupererTous(sprintf('SELECT '. |
' CONCAT(id_image, "-", id_observation) AS jsonindex,'. |
' %1$s, %2$s FROM v_del_image '. |
' WHERE %3$s'. |
' -- %4$s', |
$obs_fields, $image_fields, |
sprintf('id_image IN (%s)', implode(',', $idImg)), |
__FILE__ . ':' . __LINE__)); |
} |
/* "masque" ne fait jamais que faire une requête sur la plupart des champs, (presque) tous traités |
de manière identique à la seule différence que: |
1) ils sont combinés par des "OU" logiques plutôt que des "ET". |
2) les tags sont traités différemment pour conserver la compatibilité avec l'utilisation historique: |
Tous les mots-clefs doivent matcher et sont séparés par des espaces |
(dit autrement, str_replace(" ", ".*", $mots-clefs-requête) =~ $mots-clefs-mysql) |
Pour plus d'information: (ListeObservations|DelTk)::sqlAddMasqueConstraint() */ |
static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) { |
if(!empty($p['masque'])) { |
$or_params = array('masque.auteur' => $p['masque'], |
'masque.departement' => $p['masque'], |
'masque.commune' => $p['masque'], // TODO/XXX ? |
'masque.id_zone_geo' => $p['masque'], |
/* tous-deux remplacent masque.tag |
mais sont traité séparément des requestFilterParams() */ |
// 'masque.tag_cel' => $p['masque'], |
// 'masque.tag_pictoflora' => $p['masque'], |
'masque.ns' => $p['masque'], |
'masque.famille' => $p['masque'], |
'masque.date' => $p['masque'], |
'masque.genre' => $p['masque'], |
'masque.milieu' => $p['masque'], |
'masque.tag_cel' => $p['masque'], |
'masque.tag_pictoflora' => $p['masque'], |
// tri est aussi nécessaire car affecte les contraintes de JOIN |
'tri' => $p['tri'], |
'ordre' => $p['ordre']); |
/* Cependant les champs spécifiques ont priorité sur le masque général. |
Pour cette raison nous supprimons la génération de SQL du masque général sur les |
champ spécifiques qui feront l'objet d'un traitement avec une valeur propre. */ |
if(isset($p['masque.auteur'])) unset($or_params['masque.auteur']); |
if(isset($p['masque.departement'])) unset($or_params['masque.departement']); |
if(isset($p['masque.commune'])) unset($or_params['masque.commune']); |
if(isset($p['masque.id_zone_geo'])) unset($or_params['masque.id_zone_geo']); |
if(isset($p['masque.ns'])) unset($or_params['masque.ns']); |
if(isset($p['masque.famille'])) unset($or_params['masque.famille']); |
if(isset($p['masque.date'])) unset($or_params['masque.date']); |
if(isset($p['masque.genre'])) unset($or_params['masque.genre']); |
if(isset($p['masque.milieu'])) unset($or_params['masque.milieu']); |
if(isset($p['masque.tag_cel'])) unset($or_params['masque.tag_cel']); |
if(isset($p['masque.tag_pictoflora'])) unset($or_params['masque.tag_pictoflora']); |
$or_masque = array_merge( |
DelTk::requestFilterParams($or_params, NULL, $c /* pour masque.departement */), |
self::requestFilterParams($or_params)); |
/* Lorsqu'on utilise le masque général pour chercher des tags, ils sont |
postulés comme séparés par des espaces, et doivent être tous matchés. */ |
if(isset($or_params['masque.tag_cel'])) |
$or_masque['masque.tag_cel'] = DelTk::buildTagsAST($p['masque'], 'AND', ' '); |
if(isset($or_params['masque.tag_pictoflora'])) |
$or_masque['masque.tag_pictoflora'] = DelTk::buildTagsAST($p['masque'], 'AND', ' '); |
// pas de select, groupby & co ici: uniquement 'join' et 'where' |
$or_req = array('join' => array(), 'where' => array()); |
DelTk::sqlAddConstraint($or_masque, $db, $or_req); |
self::sqlAddConstraint($or_masque, $db, $or_req); |
if($or_req['where']) { |
$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')'; |
// utile au cas ou des jointures seraient rajoutées |
$req['join'] = array_unique(array_merge($req['join'], $or_req['join'])); |
} |
} |
} |
// cf Observation::reformateObservationSimpleIndex() et ListeObservations::reformateObservation() |
// (trop de variétés de formatage, à unifier côté client pour unifier côté backend ...) |
static function reformateImagesDoubleIndex($obs, $url_pattern = '', $image_format = 'XL') { |
// XXX: cf Observation.php::consulter(), nous pourriouns ici |
// conserver les valeurs vides (pour les phptests notamment, ou non) |
// $obs = array_map('array_filter', $obs); |
$obs_merged = $obs_keyed_by_id_image = array(); |
foreach($obs as $o) { |
// ceci nous complique la tâche pour le reste du processing... |
$id = $o['jsonindex']; |
// ainsi nous utilisons deux tableaux: le final, indexé par couple d'id(image-obs) |
// et celui indexé par simple id_image qui est fort utile pour mapVotesToImages() |
// mais tout deux partage leur référence à "protocole" |
$image = array( |
'id_image' => $o['id_image'], |
'binaire.href' => sprintf($url_pattern, $o['id_image'], $image_format), |
'mots_cles_texte' => @$o['i_mots_cles_texte'], // @, peut avoir été filtré par array_map() ci-dessus |
); |
unset($o['id_image'], $o['i_mots_cles_texte'], $o['jsonindex']); |
if(!isset($obs_merged[$id])) $obs_merged[$id] = $image; |
$obs_merged[$id]['observation'] = $o; |
$obs_merged[$id]['protocoles_votes'] = array(); |
$obs_keyed_by_id_image[$image['id_image']]['protocoles_votes'] = &$obs_merged[$id]['protocoles_votes']; |
} |
return array($obs_merged,$obs_keyed_by_id_image); |
} |
// complete & override DelTk::requestFilterParams() (même usage) |
static function requestFilterParams(Array $params, $parametres_autorises = NULL) { |
if($parametres_autorises) { // filtrage de toute clef inconnue |
$params = array_intersect_key($params, array_flip($parametres_autorises)); |
} |
$p = array(); |
$p['tri'] = DelTk::unsetIfInvalid($params, 'tri', self::$tri_possible); |
$p['format'] = DelTk::unsetIfInvalid($params, 'format', self::$format_image_possible); |
// "milieu" inutile pour IdentiPlantes ? |
if(isset($params['masque.milieu'])) $p['masque.milieu'] = trim($params['masque.milieu']); |
// compatibilité |
if(isset($params['masque.tag'])) { |
$params['masque.tag_cel'] = $params['masque.tag_pictoflora'] = $params['masque.tag']; |
} |
if($p['tri'] == 'votes' || $p['tri'] == 'tags') { |
// ces critère de tri des image à privilégier ne s'applique qu'à un protocole donné |
if(!isset($params['protocole']) || !is_numeric($params['protocole'])) |
$p['protocole'] = self::$default_proto; |
else |
$p['protocole'] = intval($params['protocole']); |
} |
return array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);')); |
} |
// met à jour *toutes* les stats de nombre de tags et de moyenne des votes |
static function _update_statistics($db) { |
$db->requeter("TRUNCATE TABLE del_image_stat"); |
$db->requeter(<<<EOF |
INSERT INTO `del_image_stat` ( |
SELECT id_image, divo.ce_protocole, divo.moyenne, divo.nb_votes, dit.ctags |
FROM `tb_cel`.`cel_images` ci |
LEFT JOIN |
( SELECT ce_image, ce_protocole, AVG(valeur) AS moyenne, COUNT(valeur) AS nb_votes FROM del_image_vote |
GROUP BY ce_image, ce_protocole ) AS divo |
ON ci.id_image = divo.ce_image |
LEFT JOIN |
( SELECT ce_image, COUNT(id_tag) as ctags FROM del_image_tag |
GROUP BY ce_image ) AS dit |
ON ci.id_image = dit.ce_image ) |
EOF |
); |
} |
static function revOrderBy($orderby) { |
return $orderby == 'asc' ? 'desc' : 'asc'; |
} |
} |
/branches/v1.1-helium/services/modules/0.1/images/ListeImages2.php |
---|
New file |
0,0 → 1,643 |
<?php |
/** |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @copyright Copyright (c) 2013, Tela Botanica (accueil@tela-botanica.org) |
* @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 |
* @see http://www.tela-botanica.org/wikini/identiplante/wakka.php?wiki=IdentiPlante_PictoFlora_MoteurRecherche |
* |
* Backend pour PictoFlora (del.html#page_recherche_images) |
* |
* |
* == Notes == |
* |
* tri=votes et tri=tags: affectent le choix des images affichées (donc getIdImages()) |
* Cependant ce total ne nous intéresse même pas (MoyenneVotePresenteur.java s'en occupe). |
* Seul tri=date_transmission nous évite l'AVG() + GROUP BY |
* |
* protocole: il affecte l'affichage des information, mais le JSON contient déjà |
* l'intégralité (chercher les données de vote pour 1 ou plusieurs protocoles) est quasi-identique. |
* Par contre, le tri par moyenne des votes, sous-entend "pour un protocole donné". |
* Dès lors le choix d'un protocole doit avoir été fait afin de régler le JOIN et ainsi l'ORDER BY. |
* (cf requestFilterParams()) |
* |
* Histoire: auparavant (pré-r142x) un AVG + GROUP BY étaient utilisés pour générer on-the-fly les valeurs |
* utilisées ensuite pour l'ORDER BY. La situation à base de del_image_stat |
* est déjà bien meilleure sans être pour autant optimale. cf commentaire de sqlAddConstraint() |
* |
* |
* Tags: |
* Le comportement habituel dans le masque *général*: les mots sont séparés par des espaces, |
* implod()ed par des AND (tous les mots doivent matcher). |
* Et le test effectué doit matcher sur: |
* %(les tags d'observations)% *OU* %(les tags d'images)% *OU* %(les tags publics)% |
* |
* Le comportement habituel dans le masque *tag*: les mots ne sont *pas* splittés (1 seule expression), |
* Et le test effectué doit matcher sur: |
* ^(expression)% *OU* %(expression)% [cf getConditionsImages()] |
* |
* Par défaut les tags sont comma-separated (OU logique). |
* Cependant pour conserver le comportement du masque général qui sous-entend un ET logique sur |
* des tags séparés par des espaces recherche |
* |
* TODO: |
* -affiner la gestion de passage de mots-clefs dans le masque général. |
* - subqueries dans le FROM pour les critère WHERE portant directement sur v_del_image |
* plutôt que dans WHERE (qui nécessite dès lors un FULL-JOIN) |
* (http://www.mysqlperformanceblog.com/2007/04/06/using-delayed-join-to-optimize-count-and-limit-queries/) |
* - éviter de dépendre d'une jointure systématique sur `cel_obs`, uniquement pour `(date_)transmission |
* (cf VIEW del_image) |
* - poursuivre la réorganisation des méthodes statiques parmis Observation, ListeObservations et ListeImages2 |
* - *peut-être*: passer requestFilterParams() en méthode de classe |
* |
* |
* MySQL sux: |
* EXPLAIN SELECT id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1 LIMIT 1); |
* MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery |
* EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT 3); |
* PRIMARY |
* EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT MIN(3)); |
* DEPENDENT SUBQUERY ... ... ... mwarf ! |
* EXPLAIN SELECT id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1); |
* 5.5: MATERIALIZED del_image_tag ALL ce_image NULL NULL NULL 38276 Using where |
* 5.1: DEPENDENT SUBQUERY del_image_tag index_subquery ce_image ce_image 8 func 1 Using where |
* FORCE INDEX/IGNORE INDEX semble incapable de résoudre le problème de l'optimiseur MySQL |
* |
*/ |
require_once(dirname(__FILE__) . '/../DelTk.php'); |
require_once(dirname(__FILE__) . '/../observations/Observation.php'); |
restore_error_handler(); |
restore_exception_handler(); |
error_reporting(E_ALL); |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc&masque=plop |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc&protocole=3 |
// del/services/0.1/images?navigation.depart=0&navigation.limite=12&tri=votes&ordre=desc&protocole=3&masque=plop |
class ListeImages2 { |
// TODO: PHP-x.y, ces variables devrait être des "const" |
static $format_image_possible = array('O','CRX2S','CRS','CXS','CS','XS','S','M','L','XL','X2L','X3L'); |
static $tri_possible = array('date_transmission', 'date_observation', 'votes', 'tags'); |
// en plus de ceux dans DelTk |
static $parametres_autorises = array('protocole', 'masque.tag_cel', 'masque.tag_pictoflora', 'masque.milieu'); |
static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10, |
'tri' => 'date_transmission', 'ordre' => 'desc', |
// spécifiques à PictoFlora: |
'format' => 'XL'); |
static $default_proto = 3; // proto par défaut: capitalisation d'img (utilisé uniquement pour tri=(tags|votes)) |
static $mappings = array( |
'observations' => array( // v_del_image |
"id_observation" => 1, |
"date_observation" => 1, |
"date_transmission" => 1, |
"famille" => "determination.famille", |
"nom_sel" => "determination.ns", |
"nom_sel_nn" => "determination.nn", |
"nom_referentiel" => "determination.referentiel", |
"nt" => "determination.nt", |
"ce_zone_geo" => "id_zone_geo", |
"zone_geo" => 1, |
"lieudit" => 1, |
"station" => 1, |
"milieu" => 1, |
"mots_cles_texte" => "mots_cles_texte", |
"commentaire" => 1, |
"ce_utilisateur" => "auteur.id", |
"nom_utilisateur" => "auteur.nom", |
"prenom_utilisateur" => "auteur.prenom", |
), |
'images' => array( // v_del_image |
'id_image' => 1, |
// l'alias suivant est particulier: in-fine il doit s'appeler mots_cles_texte |
// mais nous afin d'éviter un conflit d'alias nous le renommons plus tard (reformateImagesDoubleIndex) |
'i_mots_cles_texte' => 1 |
)); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_images.ini'); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
public function consulter($ressources, $parametres) { |
/* Certes nous sélectionnons ici (nom|prenom|courriel)_utilisateur de cel_obs, mais il ne nous intéressent pas |
Par contre, ci-dessous nous prenons i_(nom|prenom|courriel)_utilisateur. |
Notons cependant qu'aucun moyen ne devrait permettre que i_*_utilisateur != *_utilisateur |
Le propriétaire d'une obs et de l'image associée est *toujours* le même. */ |
array_walk(self::$mappings['observations'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
array_walk(self::$mappings['images'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
// pour les votes, les mappings de "Observation" nous suffisent |
array_walk(Observation::$mappings['votes'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
// la nécessité du 'groupby' dépend des 'join's utilisés (LEFT ou INNER) ainsi que de la cardinalité |
// de `ce_image` dans ces tables jointes. |
// Contrairement à IdentiPlantes, nous n'avons de HAVING pour PictoFlora, mais par contre un ORDER BY |
$req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'orderby' => array()); |
$db = $this->bdd; |
// filtrage de l'INPUT général, on réutilise 90% de identiplante en terme de paramètres autorisés |
// ($parametres_autorises) sauf... masque.type qui fait des modif' de WHERE sur les mots-clefs. |
// Évitons ce genre de chose pour PictoFlora et les risques de conflits avec masque.tag |
// même si ceux-ci sont improbables (pas d'<input> pour cela). |
$params_ip = DelTk::requestFilterParams($parametres, |
array_diff(DelTk::$parametres_autorises, |
array('masque.type')), |
$this->conteneur); |
// notre propre filtrage sur l'INPUT |
$params_pf = self::requestFilterParams($parametres, |
array_merge(DelTk::$parametres_autorises, |
self::$parametres_autorises)); |
/* filtrage des tags + sémantique des valeurs multiples: |
Lorsqu'on utilise masque.tag* pour chercher des tags, ils sont |
postulés comme séparés par des virgule, et l'un au moins des tags doit matcher. */ |
$params_pf['masque.tag_cel'] = DelTk::buildTagsAST(@$parametres['masque.tag_cel'], 'OR', ','); |
$params_pf['masque.tag_pictoflora'] = DelTk::buildTagsAST(@$parametres['masque.tag_pictoflora'], 'OR', ','); |
$params = array_merge( |
DelTk::$default_params, // paramètre par défaut Identiplante |
self::$default_params, // paramètres par défaut PictoFlora |
$params_ip, // les paramètres passés, traités par Identiplante |
$params_pf); // les paramètres passés, traités par PictoFlora |
// XXX: temp tweak |
/* $this->conteneur->setParametre('url_images', sprintf($this->conteneur->getParametre('images.url_images'), |
"%09d", $params['format']));*/ |
// création des contraintes (génériques de DelTk) |
DelTk::sqlAddConstraint($params, $db, $req); |
// création des contraintes spécifiques (sur les tags essentiellement) |
self::sqlAddConstraint($params, $db, $req, $this->conteneur); |
// création des contraintes spécifiques impliquées par le masque général |
self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur); |
// l'ORDER BY s'avére complexe |
self::sqlOrderBy($params, $db, $req); |
// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS) |
// $idobs_tab = ListeObservations::getIdObs($params, $req, $db); |
$idobs_tab = self::getIdImages($params, $req, $db); |
// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats dans la table del_obs_images |
if(!$idobs_tab) { |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => DelTk::makeJSONHeader(0, $params, Config::get('url_service')), |
'resultats' => array()); |
return $resultat; |
/* |
header('HTTP/1.0 404 Not Found'); |
// don't die (phpunit) |
throw(new Exception()); */ |
} |
// idobs est une liste (toujours ordonnée) des id d'observations recherchées |
$idobs = array_values(array_map(create_function('$a', 'return $a["id_image"];'), $idobs_tab)); |
$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']); |
$liaisons = self::chargerImages($db, $idobs); |
/* |
// Q&D |
$images = array(); |
$o = new Observation($this->conteneur); |
foreach($idobs as $i) { |
$images[$i] = $o->consulter(array($i), array('justthrow' => 1)); |
} |
*/ |
list($images, $images_keyed_by_id_image) = self::reformateImagesDoubleIndex( |
$liaisons, |
$this->conteneur->getParametre('images.url_images'), |
$params['format']); |
// on charge les votes pour ces images et pour *tous* les protocoles |
$votes = Observation::chargerVotesImage($db, $liaisons, NULL); |
// subtilité, nous passons ici le tableau d'images indexé par id_image qui est bien plus pratique pour |
// associer les vote à un tableau, puisque nous ne connaissons pas les id d'observation. |
// Mais magiquement (par référence), cela va remplir notre tableau indexé par couple d'id (id_image, id_observation) |
// cf reformateImagesDoubleIndex() à qui revient la tâche de créer ces deux versions simultanément lorsque |
// c'est encore possible. |
if($votes) Observation::mapVotesToImages($votes, $images_keyed_by_id_image); |
// les deux masques de tags sont transformés en AST dans le processus de construction de la requête. |
// Reprenous les paramètres originaux non-nettoyés (ils sont valables car le nettoyage est déterministe) |
$params_header = array_merge($params, array_filter(array('masque.tag_cel' => @$parametres['masque.tag_cel'], |
'masque.tag_pictoflora' => @$parametres['masque.tag_pictoflora']))); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => DelTk::makeJSONHeader($total, $params_header, Config::get('url_service')), |
'resultats' => $images); |
return $resultat; |
} |
/** |
* TODO: partie spécifique liées à la complexité de PictoFlora: |
* génération de la clause ORDER BY (génère la valeur de la clef orderby' de $req) |
* nécessaire ? tableau sprintf(key (tri) => value (ordre), key => value ...). |
* Cependant il est impensable de joindre sur un AVG() des valeurs des votes pour |
* *chaque* couple (id_image, protocole) de la base afin de trouver les images |
* les "mieux notées", ou bien les images ayant le "plus de tags" (COUNT()) |
*/ |
static function sqlOrderBy($p, $db, &$req) { |
// parmi self::$tri_possible |
if($p['tri'] == 'votes') { // LEFT JOIN sur "dis" ci-dessous |
$req['orderby'] = 'dis.moyenne ' . $p['ordre'] . ', dis.nb_votes ' . $p['ordre']; |
return; |
} |
if($p['tri'] == 'tags') { // LEFT JOIN sur "dis" ci-dessous |
$req['orderby'] = 'dis.nb_tags ' . $p['ordre']; |
return; |
} |
if($p['tri'] == 'date_observation') { |
$req['orderby'] = 'date_observation ' . $p['ordre'] . ', id_observation ' . $p['ordre']; |
return; |
} |
// tri == 'date_transmission' |
// avant cel:r1860, date_transmission pouvait être NULL |
// or nous voulons de la consistence (notamment pour phpunit) |
$req['orderby'] = 'date_transmission ' . $p['ordre'] . ', id_observation ' . $p['ordre']; |
} |
/* |
* in $p: un tableau de paramètres, dont: |
* - 'masque.tag_cel': *tableau* de mots-clefs à chercher parmi cel_image.mots_clefs_texte |
* - 'masque.tag_pictoflora': *tableau* de mots-clefs à chercher parmi del_image_tag.tag_normalise |
* - 'tag_explode_semantic': défini si les éléments sont tous recherchés ou NON |
* |
* in/ou: $req: un tableau de structure de requête MySQL |
* |
* Attention, le fait que nous cherchions masque.tag_cel OU/ET masque.tag_cel |
* ne dépend pas de nous, mais du niveau supérieur de construction de la requête: |
* Soit directement $this->consulter() si des masque.tag* sont passés |
* (split sur ",", "AND" entre chaque condition, "OR" pour chaque valeur de tag) |
* Soit via sqlAddMasqueConstraint(): |
* (pas de split, "OR" entre chaque condition) [ comportement historique ] |
* équivalent à: |
* (split sur " ", "OR" entre chaque condition, "AND" pour chaque valeur de tag) |
* |
*/ |
static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) { |
// TODO implement dans DelTk ? |
if(!empty($p['masque.milieu'])) { |
$req['where'][] = 'vdi.milieu LIKE '.$db->proteger('%' . $p['masque.milieu'].'%'); |
} |
/* Pour le tri par AVG() des votes nous avons toujours un protocole donné, |
celui-ci indique sur quels votes porte l'AVG. |
(c'est un *vote* qui porte sur un protocole et non l'image elle-même) */ |
/* TODO: perf problème: |
1) SQL_CALC_FOUND_ROWS: fixable en: |
- dissociant le comptage de la récup d'id + javascript async |
- ou ne rafraîchir le total *que* pour les requête impliquant un changement de pagination |
(paramètre booléen "with-total" par exemple) |
2) jointure forcées: en utilisant `del_imagè`, nous forçons les 2 premiers |
JOIN sur cel_obs_images et cel_obs pour filtrer sur "transmission". |
Dénormaliser cette valeur et l'intégrer à `cel_images` ferait économiser cette couteuse |
jointure, ... lorsqu'aucun masque portant sur `cel_obs` n'est utilisé |
3) non-problème: l'ordre des joins est forcé par l'usage de la vue: |
(cel_images/cel_obs_images/cel_obs/del_image_stat) |
Cependant c'est à l'optimiseur de définir son ordre préféré. */ |
if($p['tri'] == 'votes') { |
// $p['protocole'] *est* défini (cf requestFilterParams()) |
// petite optimisation: INNER JOIN si ordre DESC car les 0 à la fin |
if($p['ordre'] == 'desc') { |
// pas de group by nécessaire pour cette jointure |
// PRIMARY KEY (`ce_image`, `ce_protocole`) |
$req['join'][] = sprintf('INNER JOIN del_image_stat dis'. |
' ON vdi.id_image = dis.ce_image'. |
' AND dis.ce_protocole = %d', |
$p['protocole']); |
} else { |
$req['join'][] = sprintf('LEFT JOIN del_image_stat dis'. |
' ON vdi.id_image = dis.ce_image'. |
' AND dis.ce_protocole = %d', |
$p['protocole']); |
// nécessaire (dup ce_image dans del_image_stat) |
$req['groupby'][] = 'vdi.id_observation'; |
} |
} |
if($p['tri'] == 'tags') { |
$req['join'][] = sprintf('%s JOIN del_image_stat dis ON vdi.id_image = dis.ce_image', |
($p['ordre'] == 'desc') ? 'INNER' : 'LEFT'); |
// nécessaire (dup ce_image dans del_image_stat) |
$req['groupby'][] = 'vdi.id_observation'; |
} |
// car il ne sont pas traités par la générique requestFilterParams() les clefs "masque.tag_*" |
// sont toujours présentes; bien que parfois NULL. |
if($p['masque.tag_cel']) { |
if(isset($p['masque.tag_cel']['AND'])) { |
// TODO: utiliser les tables de mots clefs normaliées dans tb_cel ? |
// et auquel cas laisser au client le choix du couteux "%" ? |
$tags = $p['masque.tag_cel']['AND']; |
array_walk($tags, create_function('&$val, $k, $db', |
'$val = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) LIKE %s", |
$db->proteger("%".$val."%"));'), |
$db); |
$req['where'][] = '(' . implode(' AND ', $tags) . ')'; |
} |
else { |
$req['where'][] = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) REGEXP %s", |
$db->proteger(implode('|', $p['masque.tag_cel']['OR']))); |
} |
} |
if($p['masque.tag_pictoflora']) { |
// inutilisable pour l'instant |
// self::sqlAddPictoFloraTagConstraint1($p, $db, $req); |
// intéressante, mais problème d'optimiseur MySQL 5.5 (dependant subquery) |
// self::sqlAddPictoFloraTagConstraint2($p, $db, $req); |
// approche fiable mais sous-optimale |
self::sqlAddPictoFloraTagConstraint3($p, $db, $req); |
} |
} |
/* approche intéressante si les deux problèmes suivants peuvent être résolu: |
- LEFT JOIN => dup => *gestion de multiples GROUP BY* (car in-fine un LIMIT est utilisé) |
- dans le cas d'un ET logique, comment chercher les observations correspondantes ? */ |
static function sqlAddPictoFloraTagConstraint1($p, $db, &$req) { |
// XXX: utiliser tag plutôt que tag_normalise ? |
$req['join'][] = 'LEFT JOIN del_image_tag dit ON dit.ce_image = vdi.id_image'; |
$req['where'][] = 'dit.actif = 1'; |
$req['groupby'][] = 'vdi.id_image'; // TODO: nécessaire (car dup') mais risque de conflict en cas de tri (multiple GROUP BY) |
// XXX: en cas de ET, possibilité du GROUP_CONCAT(), mais probablement sans grand intérêt, d'où une boucle |
if(isset($p['masque.tag_pictoflora']['AND'])) { |
// TODO/XXX : comment matcher les observations ayant tous les mots-clef passés ? |
// ... le LEFT-JOIN n'y semble pas adapté |
} |
else { |
$protected_tags = array(); |
foreach($p['masque.tag_pictoflora']['OR'] as $tag) $protected_tags[] = $db->proteger(strtolower($tag)); |
$req['where'][] = sprintf('tag_normalise IN (%s)', implode(',', $protected_tags)); |
} |
} |
// inutilisé pour l'instant pour cause de soucis d'optimiseur MySQL (cf commentaire en intro) |
static function sqlAddPictoFloraTagConstraint2($p, $db, &$req) { |
// Note à propos des 4 "@ instruction" ci-dessous (notamment sur recupererTous()) |
// REGEXP permet un puissant mécanisme de sélection des obs/image à qui sait |
// l'utiliser, mais peut sortir une erreur en cas de REGEXP invalide |
// ex: REGEX "^(". |
// Pour l'heure nous ignorons ce type d'erreur car aucun de nos champ de recherche |
// ne peuvent (ou ne devrait) comporter des meta-caractères |
// ([])?*+\\ |
if(isset($p['masque.tag_pictoflora']['AND'])) { |
// optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT() |
// donc nous utilisons des ".*" plutôt que de multiples conditions et "|" |
sort($p['masque.tag_pictoflora']['AND']); |
$req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s)", |
$db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND']))); |
} |
else { |
$req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise) REGEXP %s)", |
$db->proteger(implode('|', $p['masque.tag_pictoflora']['OR']))); |
} |
} |
// si l'on est bassiné par les "DEPENDENT SUBQUERY", nous la faisons donc indépendemment via cette fonction |
static function sqlAddPictoFloraTagConstraint3($p, $db, &$req) { |
if(isset($p['masque.tag_pictoflora']['AND'])) { |
// optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT() |
// donc nous utilisons des ".*" plutôt que de multiples conditions et "|" |
sort($p['masque.tag_pictoflora']['AND']); |
// plutôt que db->connexion->query->fetchColumn(), une API pourrie nous oblige à ... |
$ids = @$db->recupererTous(sprintf( |
"SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s", |
$db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND'])))); |
// puis: |
$ids = @array_map(create_function('$e', 'return $e["ce_image"];'), $ids); |
if($ids) $req['where'][] = sprintf("vdi.id_image IN (%s)", implode(',', $ids)); |
} |
else { |
$ids = @$db->recupererTous(sprintf( |
"SELECT ce_image FROM del_image_tag WHERE actif = 1". |
" GROUP BY ce_image". |
" HAVING GROUP_CONCAT(tag_normalise) REGEXP %s", |
$db->proteger(implode('|', $p['masque.tag_pictoflora']['OR'])))); |
$ids = @array_map(create_function('$e', 'return $e["ce_image"];'), $ids); |
if($ids) $req['where'][] = sprintf("vdi.id_image IN (%s)", implode(',', $ids)); |
} |
} |
static function getIdImages($p, $req, $db) { |
return $db->recupererTous(sprintf( |
'SELECT SQL_CALC_FOUND_ROWS id_image' . |
' FROM v_del_image vdi'. |
' %s' . // LEFT JOIN if any |
' WHERE %s'. // where-clause ou TRUE |
' %s'. // group-by |
' ORDER BY %s'. |
' LIMIT %d, %d -- %s', |
$req['join'] ? implode(' ', array_unique($req['join'])) : '', |
$req['where'] ? implode(' AND ', $req['where']) : 'TRUE', |
$req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '', |
$req['orderby'], |
$p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__)); |
} |
static function chargerImages($db, $idImg) { |
$obs_fields = DelTk::sqlFieldsToAlias(self::$mappings['observations'], NULL); |
$image_fields = DelTk::sqlFieldsToAlias(self::$mappings['images'], NULL); |
return $db->recupererTous(sprintf('SELECT '. |
' CONCAT(id_image, "-", id_observation) AS jsonindex,'. |
' %1$s, %2$s FROM v_del_image '. |
' WHERE %3$s'. |
' -- %4$s', |
$obs_fields, $image_fields, |
sprintf('id_image IN (%s)', implode(',', $idImg)), |
__FILE__ . ':' . __LINE__)); |
} |
/* "masque" ne fait jamais que faire une requête sur la plupart des champs, (presque) tous traités |
de manière identique à la seule différence que: |
1) ils sont combinés par des "OU" logiques plutôt que des "ET". |
2) les tags sont traités différemment pour conserver la compatibilité avec l'utilisation historique: |
Tous les mots-clefs doivent matcher et sont séparés par des espaces |
(dit autrement, str_replace(" ", ".*", $mots-clefs-requête) =~ $mots-clefs-mysql) |
Pour plus d'information: (ListeObservations|DelTk)::sqlAddMasqueConstraint() */ |
static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) { |
if(!empty($p['masque'])) { |
$or_params = array('masque.auteur' => $p['masque'], |
'masque.departement' => $p['masque'], |
'masque.commune' => $p['masque'], // TODO/XXX ? |
'masque.id_zone_geo' => $p['masque'], |
/* tous-deux remplacent masque.tag |
mais sont traité séparément des requestFilterParams() */ |
// 'masque.tag_cel' => $p['masque'], |
// 'masque.tag_pictoflora' => $p['masque'], |
'masque.ns' => $p['masque'], |
'masque.famille' => $p['masque'], |
'masque.date' => $p['masque'], |
'masque.genre' => $p['masque'], |
'masque.milieu' => $p['masque'], |
// tri est aussi nécessaire car affecte les contraintes de JOIN |
'tri' => $p['tri'], |
'ordre' => $p['ordre']); |
/* Cependant les champs spécifiques ont priorité sur le masque général. |
Pour cette raison nous supprimons la génération de SQL du masque général sur les |
champ spécifiques qui feront l'objet d'un traitement avec une valeur propre. */ |
if(isset($p['masque.auteur'])) unset($or_params['masque.auteur']); |
if(isset($p['masque.departement'])) unset($or_params['masque.departement']); |
if(isset($p['masque.commune'])) unset($or_params['masque.commune']); |
if(isset($p['masque.id_zone_geo'])) unset($or_params['masque.id_zone_geo']); |
if(isset($p['masque.ns'])) unset($or_params['masque.ns']); |
if(isset($p['masque.famille'])) unset($or_params['masque.famille']); |
if(isset($p['masque.date'])) unset($or_params['masque.date']); |
if(isset($p['masque.genre'])) unset($or_params['masque.genre']); |
if(isset($p['masque.milieu'])) unset($or_params['masque.milieu']); |
if(isset($p['masque.tag_cel'])) unset($or_params['masque.tag_cel']); |
if(isset($p['masque.tag_pictoflora'])) unset($or_params['masque.tag_pictoflora']); |
$or_masque = array_merge( |
DelTk::requestFilterParams($or_params, NULL, $c /* pour masque.departement */), |
self::requestFilterParams($or_params)); |
/* Lorsqu'on utilise le masque général pour chercher des tags, ils sont |
postulés comme séparés par des espaces, et doivent être tous matchés. */ |
if(isset($or_params['masque.tag_cel'])) |
$or_masque['masque.tag_cel'] = DelTk::buildTagsAST($p['masque'], 'AND', ' '); |
if(isset($or_params['masque.tag_pictoflora'])) |
$or_masque['masque.tag_pictoflora'] = DelTk::buildTagsAST($p['masque'], 'AND', ' '); |
// pas de select, groupby & co ici: uniquement 'join' et 'where' |
$or_req = array('join' => array(), 'where' => array()); |
DelTk::sqlAddConstraint($or_masque, $db, $or_req); |
self::sqlAddConstraint($or_masque, $db, $or_req); |
if($or_req['where']) { |
$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')'; |
// utile au cas ou des jointures seraient rajoutées |
$req['join'] = array_unique(array_merge($req['join'], $or_req['join'])); |
} |
} |
} |
// cf Observation::reformateObservationSimpleIndex() et ListeObservations::reformateObservation() |
// (trop de variétés de formatage, à unifier côté client pour unifier côté backend ...) |
static function reformateImagesDoubleIndex($obs, $url_pattern = '', $image_format = 'XL') { |
// XXX: cf Observation.php::consulter(), nous pourriouns ici |
// conserver les valeurs vides (pour les phptests notamment, ou non) |
// $obs = array_map('array_filter', $obs); |
$obs_merged = $obs_keyed_by_id_image = array(); |
foreach($obs as $o) { |
// ceci nous complique la tâche pour le reste du processing... |
$id = $o['jsonindex']; |
// ainsi nous utilisons deux tableaux: le final, indexé par couple d'id(image-obs) |
// et celui indexé par simple id_image qui est fort utile pour mapVotesToImages() |
// mais tout deux partage leur référence à "protocole" |
$image = array( |
'id_image' => $o['id_image'], |
'binaire.href' => sprintf($url_pattern, $o['id_image'], $image_format), |
'mots_cles_texte' => @$o['i_mots_cles_texte'], // @, peut avoir été filtré par array_map() ci-dessus |
); |
unset($o['id_image'], $o['i_mots_cles_texte'], $o['jsonindex']); |
if(!isset($obs_merged[$id])) $obs_merged[$id] = $image; |
$obs_merged[$id]['observation'] = $o; |
$obs_merged[$id]['protocoles_votes'] = array(); |
$obs_keyed_by_id_image[$image['id_image']]['protocoles_votes'] = &$obs_merged[$id]['protocoles_votes']; |
} |
return array($obs_merged,$obs_keyed_by_id_image); |
} |
// complete & override DelTk::requestFilterParams() (même usage) |
static function requestFilterParams(Array $params, $parametres_autorises = NULL) { |
if($parametres_autorises) { // filtrage de toute clef inconnue |
$params = array_intersect_key($params, array_flip($parametres_autorises)); |
} |
$p = array(); |
$p['tri'] = DelTk::unsetIfInvalid($params, 'tri', self::$tri_possible); |
$p['format'] = DelTk::unsetIfInvalid($params, 'format', self::$format_image_possible); |
// "milieu" inutile pour IdentiPlantes ? |
if(isset($params['masque.milieu'])) $p['masque.milieu'] = trim($params['masque.milieu']); |
// compatibilité |
if(isset($params['masque.tag'])) { |
$params['masque.tag_cel'] = $params['masque.tag_pictoflora'] = $params['masque.tag']; |
} |
if($p['tri'] == 'votes' || $p['tri'] == 'tags') { |
// ces critère de tri des image à privilégier ne s'applique qu'à un protocole donné |
if(!isset($params['protocole']) || !is_numeric($params['protocole'])) |
$p['protocole'] = self::$default_proto; |
else |
$p['protocole'] = intval($params['protocole']); |
} |
return array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);')); |
} |
// met à jour *toutes* les stats de nombre de tags et de moyenne des votes |
static function _update_statistics($db) { |
$db->requeter("TRUNCATE TABLE del_image_stat"); |
$db->requeter(<<<EOF |
INSERT INTO `del_image_stat` ( |
SELECT id_image, divo.ce_protocole, divo.moyenne, divo.nb_votes, dit.ctags |
FROM `tb_cel`.`cel_images` ci |
LEFT JOIN |
( SELECT ce_image, ce_protocole, AVG(valeur) AS moyenne, COUNT(valeur) AS nb_votes FROM del_image_vote |
GROUP BY ce_image, ce_protocole ) AS divo |
ON ci.id_image = divo.ce_image |
LEFT JOIN |
( SELECT ce_image, COUNT(id_tag) as ctags FROM del_image_tag |
GROUP BY ce_image ) AS dit |
ON ci.id_image = dit.ce_image ) |
EOF |
); |
} |
static function revOrderBy($orderby) { |
return $orderby == 'asc' ? 'desc' : 'asc'; |
} |
} |
/branches/v1.1-helium/services/modules/0.1/nomstaxons/ListeTaxons.php |
---|
New file |
0,0 → 1,88 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service récupère une liste de noms suivant un référentiel et un masque donné |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Aurélien Peronnet <aurelien@tela-botanica.org> |
* @author Grégoire Duché <gregoire@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class ListeTaxons { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $requete = null; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_nomstaxons.ini'); |
$this->navigation = $conteneur->getNavigation(); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
/** |
* Méthode principale de la classe. |
* @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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Lancement du service |
$taxons = $this->chargerNoms($this->masque->getMasque('referentiel'), $this->masque->getMasque('nom')); |
$total = $this->compterNoms($taxons); |
$this->navigation->setTotal($total); |
$this->conteneur->setSansLimite(); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $taxons); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES COMMENTAIRES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis le serveur de tous les noms |
* */ |
private function chargerNoms($referentiel, $requete) { |
$url = sprintf($this->conteneur->getParametre('url_service_completion_base'), $referentiel, urlencode($requete)); |
$res = json_decode(@file_get_contents($url),true); |
$res = (array)$res; |
$res_fmt = array(); |
if(isset($res['resultat'])) { |
foreach($res['resultat'] as $nn => $info_nom) { |
$res_fmt[] = array($info_nom['nom_sci_complet'], (string)$nn); |
} |
} |
return $res_fmt; |
} |
/** |
* Compter le nombre total de noms pour affichage dans entete. |
* */ |
private function compterNoms($taxons) { |
return sizeof($taxons); |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Syndication.php |
---|
New file |
0,0 → 1,175 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services de syndication |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package del-service |
* @author Aurélien 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> |
* @version 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Syndication extends RestService { |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $squelette_dossier = null; |
private $formats_autorises = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
$this->squelette_dossier = dirname(__FILE__).DIRECTORY_SEPARATOR.'syndication'.DIRECTORY_SEPARATOR.'squelettes'.DIRECTORY_SEPARATOR; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserProjet(); |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$this->verifierRessourcesEtParametres(); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($this->creerResultatService($resultat)); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function verifierRessourcesEtParametres() { |
$servicesDispos = Config::get('servicesDispo'); |
if (!isset($this->ressources[0]) || !in_array($this->ressources[0], explode(',',$servicesDispos))) { |
$message = "Vous devez indiquer un nom de service valide, les services disponibles sont ".$servicesDispos; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} |
$chaineFormatsAutorises = Config::get('formatsRss'); |
$this->formats_autorises = explode(',', $chaineFormatsAutorises); |
if (!isset($this->ressources[1]) || !in_array($this->ressources[1], $this->formats_autorises)) { |
$message = "Vous devez indiquer un format de flux valide, les formats acceptés sont ".$chaineFormatsAutorises; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} else { |
$this->format = $this->ressources[1]; |
} |
} |
private function traiterRessources() { |
$retour = ''; |
$retour = $this->initialiserService(); |
return $retour; |
} |
private function creerResultatService($donnees) { |
$resultat = new ResultatService(); |
$resultat->mime = $this->getTypeMime(); |
$resultat->corps = SquelettePhp::analyser($this->squelette_dossier.$this->format.'.tpl.xml', $donnees); |
return $resultat; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->projetNom = 'syndication'; |
$this->chargerConfigProjet(); |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserService() { |
$this->chargerNomService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function chargerNomService() { |
if (!isset($this->ressources[0])) { |
$message = "Vous devez indiquer un nom de service"; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} else { |
$this->serviceNom = $this->ressources[0]; |
} |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = 'Syndication'.ucwords($mot); |
return $classeNom; |
} |
private function getTypeMime() { |
$mime = ''; |
switch ($this->format) { |
case 'atom' : |
$mime = 'application/atom+xml'; |
break; |
case 'rss1' : |
case 'rss2' : |
$mime = 'application/rss+xml'; |
break; |
case 'opml' : |
$mime = 'text/x-opml'; |
break; |
default: |
$mime = 'text/html'; |
} |
return $mime; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Determinations.php |
---|
New file |
0,0 → 1,201 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Determinations extends RestService { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/images/ => toutes les images, appel à la classe ListeImages |
* http://localhost/del/services/0.1/images/#id => une image donnée => non utilisé sur DEL pour l'instant |
* http://localhost/del/services/0.1/images/#id/votes/ => tous les votes d'une image classés par protocole |
* http://localhost/del/services/0.1/images/#id/votes/protocole/#id => tous les votes d'une image et d'un protocole donné |
* http://localhost/del/services/0.1/images/#id/votes/#id => un vote donné pour une image donnée. |
* */ |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function ajouter($ressources, $requeteDonnees) { |
$this->methode = 'ajouter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
echo $reponseHttp->getCorps(); |
} |
} |
public function modifier($ressources, $requeteDonnees) { |
$this->methode = 'modifier'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
echo $reponseHttp->getCorps(); |
} |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
if ($this->avoirRessourceService()) { |
$retour = $this->initialiserService(); |
} |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->chargerNomDuProjet(); |
$this->chargerConfigProjet(); |
} |
private function chargerNomDuProjet() { |
$this->projetNom = 'determinations'; |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function avoirRessourceService() { |
$presenceRessourceService = false; |
if (isset($this->ressources[0])) { |
if($this->ressources[0] == 'images-determinations-probables') { |
$presenceRessourceService = true; |
$this->serviceNom = 'liste-images-determinations-probables'; |
} else if($this->ressources[0] == 'valider-determination') { |
$presenceRessourceService = true; |
$this->serviceNom = 'valider-determination'; |
} else { |
$this->editerMessageErreurRessource(); |
} |
} |
return $presenceRessourceService; |
} |
private function editerMessageErreurRessource() { |
$message = "Le service demandé '".$this->projetNom.'/'.implode('/', $this->ressources). |
"' n'est pas disponible pour le projet ".$this->projetNom." !\n". |
"Les services disponibles sont : images, images/#id/votes, images/#id/vote/#id_vote"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
private function etreRessourceIdentifiant($num) { |
$presenceId = false; |
if (is_numeric($this->ressources[$num])) { |
$presenceId = true; |
} else { |
$message = "Le service demandé '$service' nécessite d'avoir un identifiant d'image valide"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $presenceId; |
} |
private function initialiserService() { |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'modifier') { |
$retour = $service->modifier($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Commentaires.php |
---|
New file |
0,0 → 1,178 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Commentaires extends RestService { |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function ajouter($ressources, $parametres) { |
$this->methode = 'ajouter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function supprimer($ressources) { |
$this->methode = 'supprimer'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->ressources = $ressources; |
$this->conteneur = new Conteneur(); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
echo $reponseHttp->getCorps(); |
} |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
$retour = $this->initialiserService(); |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->projetNom = 'commentaires'; |
$this->chargerConfigProjet(); |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserService() { |
$this->chargerNomService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'supprimer') { |
$retour = $service->supprimer($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function chargerNomService() { |
// si la méthode est POST, on ajouter un commentaire |
if ($this->methode == 'ajouter') { |
$this->serviceNom = 'ajouter-commentaire'; |
} else if ($this->methode == 'supprimer') { |
$this->serviceNom = 'supprimer-commentaire'; |
} |
else { |
//S'il n'y a pas de ressources => tous les commentaires |
if (!isset($this->ressources) || empty($this->ressources)) { |
$this->serviceNom = 'liste-commentaires'; |
} else { |
if (!is_numeric($this->ressources[0])) { |
$message = "La première ressource doit être un identifiant"; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} else { |
$this->serviceNom = 'consulter-commentaire'; |
} |
} |
} |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Communes.php |
---|
New file |
0,0 → 1,122 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Communes extends RestService { |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
$retour = $this->initialiserService(); |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->projetNom = 'communes'; |
$this->chargerConfigProjet(); |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserService() { |
$this->chargerNomService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} else { |
//TODO : throw exception |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function chargerNomService() { |
// si la méthode est POST, on ajouter un commentaire |
$this->serviceNom = 'liste-communes'; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/observations/ListeObservationsWidget.php |
---|
New file |
0,0 → 1,394 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service observations récupère toutes les observations et, pour chacune d'elle, les |
* images qui lui sont associées. |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations |
*/ |
class ListeObservationsWidget { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $tri = 'date_transmission'; |
private $directionTri = 'desc'; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_observations.ini'); |
$this->conteneur->chargerConfiguration('config_departements_bruts.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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
$this->verifierConfiguration(); |
$this->verifierParametresTri(); |
$this->initialiserTri(); |
// Lancement du service |
$observations = $this->chargerObservations(); |
$total = $this->compterObservations(); |
$this->navigation->setTotal($total); |
$observations = $this->formaterObservations($observations); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $observations); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function verifierParametresTri() { |
$erreurs = array(); |
$tris_possibles = $this->conteneur->getParametre('tris_possibles'); |
$tris_possibles_tableau = explode(',', $tris_possibles); |
if(isset($this->parametres['tri']) && !in_array($this->parametres['tri'], $tris_possibles_tableau)) { |
$erreurs[] = '- le type de tri demandé est incorrect, les valeurs possibles sont '.$tris_possibles.' ;'; |
} |
$directions_tri = array('asc', 'desc'); |
if(isset($this->parametres['ordre']) && !in_array($this->parametres['ordre'], $directions_tri)) { |
$erreurs[] = '- la direction du tri demandé est incorrecte, les valeurs supportées sont asc ou desc ;'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de l\'analyse des parametres du tri : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
private function initialiserTri() { |
$this->tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : $this->tri; |
$this->directionTri = isset($this->parametres['ordre']) ? $this->parametres['ordre'] : $this->directionTri; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
private function configurer() { |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingObservation = $this->conteneur->getParametre('mapping_observation'); |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
private function verifierConfiguration() { |
$erreurs = array(); |
$tableauObservations = $this->conteneur->getParametre('observations'); |
if (empty($tableauObservations)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [images] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
if ($this->conteneur->getParametre('url_images') == null) { |
$erreurs[] = '- paramètre "url_images" manquant ;'; |
} |
} |
if (empty($this->mappingObservation)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_observation] ou celui-ci est vide ;'; |
} else { |
$champsMappingObs = array('id_observation', 'date_observation', 'date_transmission', 'famille', 'nom_sel', 'nom_sel_nn', 'nt', |
'ce_zone_geo', 'zone_geo', 'lieudit', 'station', 'courriel', 'ce_utilisateur', 'nom', 'prenom'); |
foreach ($champsMappingObs as $champ) { |
if (!isset($this->mappingObservation[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour l\'observation est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach($tableauMasque as $idMasque => $valeurMasque) { |
$idMasque = str_replace('masque.', '', $idMasque); |
switch ($idMasque) { |
// nom du masque => nom BDD |
case 'auteur' : |
$whereAuteur = ' '.$this->creerFiltreAuteur($this->masque->getMasque('auteur')); |
if($whereAuteur != '') { |
$where[] = $whereAuteur; |
} |
break; |
case 'date' : |
$whereDate = ' '.$this->creerFiltreDate($valeurMasque); |
if($whereDate != '') { |
$where[] = $whereDate; |
} |
break; |
case 'departement' : |
$where[] = ' '.$this->creerFiltreIdZoneGeo($valeurMasque); |
break; |
case 'genre' : |
$where[] = ' '.$this->mappingFiltre['ns'].' LIKE '.$this->proteger('%'.$valeurMasque.'% %'); |
break; |
case 'tag' : |
$where[] = ' '.$this->creerFiltreMotsCles($valeurMasque); |
break; |
case 'ns' : |
$where[] = ' nom_sel LIKE '.$this->proteger($valeurMasque.'%'); |
break; |
case 'commune' : |
$where[] = ' '.$this->mappingFiltre[$idMasque].' LIKE '.$this->proteger(str_replace(array('-',' '), '_', $valeurMasque).'%'); |
break; |
case 'masque' : |
$where[] = ' '.$this->creerFiltreMasqueGeneral($valeurMasque); |
break; |
default: |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->proteger($valeurMasque); |
break; |
} |
} |
} |
if (!empty($where)) { |
return ' WHERE '.implode('AND', $where); |
} else { |
return; |
} |
} |
private function creerFiltreMasqueGeneral($valeurMasque) { |
//TODO: affecter d'aborder les variables, puis les tester pour les |
// ajouter à la chaine |
$whereAuteur = $this->creerFiltreAuteur($valeurMasque); |
$whereIdZoneGeo = $this->creerFiltreIdZoneGeo($valeurMasque); |
$masqueGeneral = '( '. |
(($whereAuteur != '') ? $whereAuteur.' OR ' : '' ). |
(($whereIdZoneGeo != '') ? $whereIdZoneGeo.' OR ' : '' ). |
'zone_geo LIKE '.$this->proteger($this->remplacerParJokerCaractere($valeurMasque).'%').' OR '. |
$this->creerFiltreMotsCles($valeurMasque).' OR '. |
'nom_sel LIKE '.$this->proteger($valeurMasque.'%').' OR '. |
'famille LIKE '.$this->proteger($valeurMasque.'%').' OR '. |
'milieu LIKE '.$this->proteger($valeurMasque).' OR '. |
$this->mappingFiltre['ns'].' LIKE '.$this->proteger('%'.$valeurMasque.'% %').' OR '. |
$this->creerFiltreDate($valeurMasque). |
') '; |
return $masqueGeneral; |
} |
private function creerFiltreAuteur($valeurMasque) { |
$masque = ''; |
$auteurId = $valeurMasque; |
if (is_numeric($auteurId)) { |
$masque = ' ce_utilisateur = '.$auteurId; |
} else { |
if (strpos($auteurId, '@') === false) { |
$tableauNomPrenom = explode(' ',$auteurId, 2); |
if(count($tableauNomPrenom) == 2) { |
// on teste potentiellement un nom prenom ou bien un prénom nom |
$masque = '('. |
'(nom LIKE '.$this->proteger($tableauNomPrenom[0].'%').' AND '. |
'prenom LIKE '.$this->proteger($tableauNomPrenom[1].'%').') OR '. |
'(nom LIKE '.$this->proteger($tableauNomPrenom[1].'%').' AND '. |
'prenom LIKE '.$this->proteger($tableauNomPrenom[0].'%').') OR '. |
'(dob.nom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[0].'%').' AND '. |
'dob.prenom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[1].'%').') OR '. |
'(dob.nom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[1].'%').' AND '. |
'dob.prenom_utilisateur LIKE '.$this->proteger($tableauNomPrenom[0].'%').') '. |
')'; |
} else { |
$masque = '( |
(nom LIKE '.$this->proteger($auteurId.'%').' OR '. |
'prenom LIKE '.$this->proteger($auteurId.'%').' OR '. |
'dob.nom_utilisateur LIKE '.$this->proteger($auteurId.'%').' OR '. |
'dob.prenom_utilisateur LIKE '.$this->proteger($auteurId.'%').')'. |
')'; |
} |
} else { |
$masque = " courriel LIKE ".$this->proteger($valeurMasque.'%'). |
" OR dob.courriel_utilisateur LIKE ".$this->proteger($valeurMasque.'%')." "; |
} |
} |
return $masque; |
} |
private function remplacerParJokerCaractere($valeurMasque) { |
return str_replace(array('-',' '), '_', $valeurMasque); |
} |
//TODO: déplacer les fonctions ci dessus et dessous dans une classe |
// utilitaire |
function supprimerAccents($str, $charset='utf-8') |
{ |
$str = htmlentities($str, ENT_NOQUOTES, $charset); |
$str = preg_replace('#&([A-za-z])(?:acute|cedil|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str); |
$str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str); // pour les ligatures e.g. 'œ' |
$str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères |
return $str; |
} |
private function obtenirIdDepartement($nomDpt) { |
$nomDpt = $this->supprimerAccents($nomDpt); |
$nomDpt = strtolower(str_replace(' ','-',$nomDpt)); |
$idDpt = $this->conteneur->getParametre($nomDpt); |
if($idDpt == null || $idDpt == ' ') { |
$idDpt = ' '; |
} |
return $idDpt; |
} |
private function creerFiltreIdZoneGeo($valeurMasque) { |
$masque = ''; |
$dept = $valeurMasque; |
if (is_numeric($dept)) { |
$dept = sprintf('%02s', $dept); |
$dept = sprintf("%-'_5s", $dept); |
$masque = " ce_zone_geo LIKE ".$this->proteger('INSEE-C:'.$dept); |
} else { |
$deptId = $this->conteneur->getParametre($dept); |
if ($deptId != null) { |
$masque = " ce_zone_geo LIKE ".$this->proteger('INSEE-C:'.$deptId.'%'); |
} else { |
$id = $this->obtenirIdDepartement($valeurMasque); |
$masque = " ce_zone_geo LIKE ".$this->proteger('INSEE-C:'.$id.'%'); |
} |
} |
return $masque; |
} |
private function creerFiltreDate($valeurMasque) { |
//TODO: définir dans le fichier de config un tableau contenant plusieurs format de date |
// autorisés pour la recherche, qui seraient ajoutés au OR |
$masque = '('; |
$masque .= (is_numeric($valeurMasque)) ? ' YEAR(date_observation) = '.$this->proteger($valeurMasque).' OR ' : ''; |
$masque .= " DATE_FORMAT(date_observation, '%d/%m/%Y') = ".$this->proteger($valeurMasque).' '. |
')'; |
return $masque; |
} |
private function creerFiltreMotsCles($valeurMasque) { |
$mots_cles = explode(' ', $valeurMasque); |
$requeteMotsClesImg = ''; |
$requeteMotsClesObs = ''; |
//TODO voir s'il existe un moyen plus simple que le foreach + rtrim |
// comme avec implode (attention au fait que l'on concatène des % au début et à la fin) |
foreach($mots_cles as $mot_cle) { |
$requeteMotsCles = $this->proteger('%'.$mot_cle.'%'); |
$requeteMotsClesObs .= 'dob.mots_cles_texte LIKE '.$requeteMotsCles.' AND '; |
} |
$requeteMotsClesImg = rtrim($requeteMotsClesImg, ' AND '); |
$requeteMotsClesObs = rtrim($requeteMotsClesObs, ' AND '); |
$masque = '('. |
'('.$requeteMotsClesImg.') OR '. |
'('.$requeteMotsClesObs.') '. |
') '; |
return $masque; |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES OBSERVATIONS |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis la bdd de toutes les liaisons entre images et observations |
* */ |
private function chargerObservations() { |
$requete = 'SELECT DISTINCT dob.id_observation '. |
'FROM '.$this->gestionBdd->formaterTable('del_observation', 'dob'). |
'INNER JOIN '.$this->gestionBdd->formaterTable('del_obs_image', 'doi'). |
'ON doi.id_observation = dob.id_observation '. |
$this->chargerClauseWhere(). |
' ORDER BY '.$this->tri.' '.$this->directionTri.' '. |
$this->gestionBdd->getLimitSql(); |
return $this->bdd->recupererTous($requete); |
} |
/** |
* Compter le nombre total d'images dans la base pour affichage dans entete. |
* */ |
private function compterObservations() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/** |
* Retourner un tableau d'images formaté en fonction des liaisons trouvées |
* @param $liaisons les liaisons de la table del_obs_images |
* */ |
private function formaterObservations($liaisons) { |
$observations = array(); |
foreach ($liaisons as $liaison) { |
$observations[] = $liaison['id_observation']; |
} |
return $observations; |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/observations/VoteObservation.php |
---|
New file |
0,0 → 1,279 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Les web service permet d'ajouter ou de modifier les votes associés aux propositions d'une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class VoteObservation extends RestService { |
protected $conteneur; |
protected $gestionBdd; |
protected $bdd; |
protected $navigation; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
$this->navigation = $conteneur->getNavigation(); |
$this->conteneur->chargerConfiguration('config_mapping_votes.ini'); |
} |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
private function configurer() { |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
} |
/** |
* Méthode seulement présente pour interdire proprement l'accès à la consultation |
* */ |
public function consulter($ressources, $parametres) { |
$this->configurer(); |
//TODO: faut il vérifier quelque chose, si on n'a pas renseigné les valeurs correctement |
// dans ressource, le service n'est même pas appelé |
$votes = $this->chargerVotes($ressources[1]); |
$this->conteneur->getNavigation()->setTotal(count($votes)); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $votes); |
return $resultat; |
} |
private function chargerVotes($id_commentaire) { |
$requeteVotes = 'SELECT * FROM '. |
$this->gestionBdd->formaterTable('del_commentaire_vote'). |
'WHERE ce_proposition = '.$this->proteger($id_commentaire); |
$resultatsVotes = $this->bdd->recupererTous($requeteVotes); |
$votes = array(); |
foreach ($resultatsVotes as $vote) { |
$votes[$vote['id_vote']] = $this->formaterVotes($vote); |
$utilisateur = $this->chercherUtilisateur($vote['ce_utilisateur']); |
if($utilisateur) { |
$votes[$vote['id_vote']] = array_merge($votes[$vote['id_vote']], $utilisateur); |
} |
} |
return $votes; |
} |
/** |
* Trouver l'utilisateur en fonction des paramètres ou de la base de données si le nom, prénom et courriel ne sont pas donnés |
* @return le tableau utilisateur |
* */ |
private function chercherUtilisateur($id) { |
$utilisateur = array(); |
$requete = "SELECT id_utilisateur as 'auteur.id', nom as 'auteur.nom', prenom as 'auteur.prenom', courriel as 'auteur.courriel' ". |
'FROM '.$this->gestionBdd->formaterTable('del_utilisateur'). |
'WHERE id_utilisateur = '.$this->bdd->proteger($id); |
$utilisateur = $this->bdd->recuperer($requete); |
return $utilisateur; |
} |
/** |
* Formater un vote en fonction du fichier de configuration config_votes.ini |
* @param $votes array() |
* */ |
private function formaterVotes($vote) { |
$retour = array(); |
foreach ($vote as $param => $valeur) { |
$retour[$this->mappingVotes[$param]] = $valeur; |
} |
return $retour; |
} |
/** |
* Ajoute un vote à une proposition grâce aux informations passées en paramètres |
* @param array $ressources tableau des informations contenues dans l'url après le nom du service |
* @param array $parametres contenu du post |
* |
* @return void |
* |
* */ |
public function ajouter($ressources, $parametres) { |
$this->verifierParametresAjoutModif($ressources, $parametres); |
// Vérifie si la proposition existe, et la crée sinon |
// (cas du vote sur la proposition fabriquée à partir de l'observation originale) |
if($ressources[1] == 0) { |
$ressources[1] = $this->renvoyerIdOuCreerPropositionDeterminationInitiale($ressources[0]); |
} |
$insertion = 'INSERT INTO del_commentaire_vote '. |
'(ce_proposition , ce_utilisateur , valeur , date) '. |
'VALUES ('.$this->proteger($ressources[1]).','.$this->proteger($parametres['utilisateur']).','. |
$this->proteger($parametres['valeur']).', NOW());'; |
$resultatsVotes = $this->bdd->requeter($insertion); |
if ($resultatsVotes == false) { |
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_MAUVAISE_REQUETE); |
} else { |
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_CREATION_OK); |
} |
} |
private function renvoyerIdPropositionObservation($id_observation) { |
$id_commentaire = null; |
// Récupération de l'utilisateur + nom sel de l'observation originale |
$requete_selection_obs = 'SELECT ce_utilisateur, nom_sel '. |
'FROM del_observation '. |
'WHERE id_observation ='.$this->proteger($id_observation); |
$obs = $this->bdd->recuperer($requete_selection_obs); |
if(is_array($obs) && isset($obs['ce_utilisateur'])) { |
// On considère que la proposition faite par le même utilisateur et ayant le même |
// nom sélectionné est bien la proposition composée à partir de l'obs originale |
$requete_selection_comm = 'SELECT id_commentaire FROM del_commentaire '. |
'WHERE ce_observation = '.$this->proteger($id_observation).' '. |
' AND nom_sel = '.$this->proteger($obs['nom_sel']).' AND '. |
' ce_utilisateur = '.$this->proteger($obs['ce_utilisateur']); |
$commentaire = $this->bdd->recuperer($requete_selection_comm); |
$id_commentaire = (is_array($commentaire) && $commentaire['id_commentaire'] != null) ? $commentaire['id_commentaire'] : null; |
} |
return $id_commentaire; |
} |
private function renvoyerIdOuCreerPropositionDeterminationInitiale($id_observation) { |
$proposition_existe = $this->propositionInitialeExiste($id_observation); |
if(!$proposition_existe) { |
$id_proposition = $this->creerPropositionAPartirObservation($id_observation); |
} else { |
$requete = "SELECT id_commentaire FROM del_commentaire WHERE ce_observation = ".$id_observation." ". |
"AND proposition_initiale = 1"; |
$resultat = $this->bdd->recuperer($requete); |
$id_proposition = $resultat['id_commentaire']; |
} |
return $id_proposition; |
} |
private function propositionInitialeExiste($id_observation) { |
$requete = "SELECT COUNT(*) >= 1 as existe FROM del_commentaire WHERE ce_observation = ".$id_observation." ". |
"AND proposition_initiale = 1"; |
$resultat = $this->bdd->recuperer($requete); |
return $resultat['existe'] == 1; |
} |
private function creerPropositionAPartirObservation($id_observation) { |
$insertion = '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, nom, '. |
' courriel, nom_sel, nom_sel_nn, nom_ret, nom_ret_nn, '. |
" nt, famille, 'bdtfx_v1', NOW(), '1' ". |
'FROM del_observation do '. |
' LEFT JOIN del_utilisateur du ON '. |
'do.ce_utilisateur = du.id_utilisateur '. |
'WHERE id_observation = '.$this->proteger($id_observation); |
$resultat = $this->bdd->requeter($insertion); |
// Attention à l'abstraction utilisée, récupérer le dernier id en mysql ou msqli ça marche bien, mais pour d'autres moins |
$id = $this->bdd->recupererIdDernierAjout(); |
return $id; |
} |
/** |
* Modifie un vote associé à une proposition grâce aux informations passées en paramètres |
* @param array $ressources tableau des informations contenues dans l'url après le nom du service |
* @param array $parametres contenu du post |
* |
* @return void |
* |
* */ |
public function modifier($ressources, $parametres) { |
$this->verifierParametresAjoutModif($ressources, $parametres); |
// Si l'identifiant de proposition vaut 0, c'est un vote sur une proposition |
// fabriquée à partir de l'observation originale, dont on doit obtenir l'id |
// (cas où l'on vient de voter pour celle et cela a créé la proposition, puis |
// on revote pour celle ci en changeant d'avis sans recharger la page) |
if($ressources[1] == 0) { |
$id_proposition = $this->renvoyerIdOuCreerPropositionDeterminationInitiale($ressources[0]); |
if($id_proposition == null) { |
$this->envoyerMessageErreurIdProposition(); |
exit; |
} else { |
$ressources[1] = $id_proposition; |
} |
} |
$modification = 'UPDATE del_commentaire_vote '. |
'SET valeur ='.$this->proteger($parametres['valeur']).', '. |
'date = NOW() '. |
'WHERE '. |
'ce_proposition = '.$this->proteger($ressources[1]).' AND '. |
'ce_utilisateur = '.$this->proteger($parametres['utilisateur']); |
$resultatsVotes = $this->bdd->requeter($modification); |
if ($resultatsVotes == false) { |
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_MAUVAISE_REQUETE); |
} else { |
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_OK); |
} |
} |
public function verifierParametresAjoutModif($ressources, $parametres) { |
$erreurs = array(); |
if (!is_numeric($ressources[1])) { |
$erreurs[] = '- le paramètre indiquant l\'identifiant de la proposition doit être numérique ;'; |
} |
if (!isset($parametres['utilisateur'])) { |
$erreurs[] = '- paramètre "utilisateur" manquant ;'; |
} |
if (!isset($parametres['valeur'])) { |
$erreurs[] = '- paramètre "valeur" manquant ;'; |
} else { |
if (!is_numeric($parametres['valeur'])) { |
$erreurs[] = '- le paramètre "valeur" doit être numérique ;'; |
} elseif($parametres['valeur'] != 0 && $parametres['valeur'] != 1) { |
$erreurs[] = '- le paramètre "valeur" ne peut prendre que la valeur 0 ou 1 ;'; |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
RestServeur::ajouterMessage($e); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
protected function envoyerMessageErreurIdProposition() { |
$erreurs = array('Aucun identifiant de proposition n\'est lié à cette observation'); |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
RestServeur::ajouterMessage($e); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
protected function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/observations/Observation.php |
---|
New file |
0,0 → 1,347 |
<?php |
/** |
* Le web service observations récupère toutes les information pour une observation: |
* images, votes sur image et protocole, commentaires, votes sur commentaires, ... |
* |
* @category php 5.2 |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @copyright Copyright (c) 2013, Tela Botanica (accueil@tela-botanica.org) |
* @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=ApiIdentiplante01Observations |
* |
* @config-depend: "url_image" (dans configurations/config_observations.ini) |
* ex: http://www.tela-botanica.org/appli:cel-img:%09dXL.jpg |
*/ |
// http://localhost/del/services/0.1/observations/#id => une observation donnée et ses images, SANS LES propositions & nombre de commentaire |
require_once(dirname(__FILE__) . '/../DelTk.php'); |
class Observation { |
/* Map les champs MySQL vers les champs utilisés dans le JSON pour les clients pour |
chacune des différentes tables utilisées pour le chargement de résultats ci-dessous. |
- chargerObservation() (v_del_image) |
- chargerVotesImage() (del_image_vote, del_image_protocole) |
- chargerCommentaires() (del_commentaire_vote, del_commentaire). |
Si la valeur vaut 1, aucun alias ne sera défini (nom du champ d'origine), cf consulter() */ |
static $mappings = array( |
'observations' => array( // v_del_image |
"id_observation" => 1, |
"date_observation" => 1, |
"date_transmission" => 1, |
"famille" => "determination.famille", |
"nom_sel" => "determination.ns", |
"nom_sel_nn" => "determination.nn", |
"nom_referentiel" => "determination.referentiel", |
"nt" => "determination.nt", |
"ce_zone_geo" => "id_zone_geo", |
"zone_geo" => 1, |
"lieudit" => 1, |
"station" => 1, |
"milieu" => 1, |
"ce_utilisateur" => "auteur.id", |
"mots_cles_texte" => "mots_cles_texte", |
"commentaire" => 1), |
/* exclus car issus de la jointure annuaire: |
"nom" => "auteur.nom", // XXX: jointure annuaire |
"prenom" => "auteur.prenom", // XXX: jointure annuaire |
"courriel" => "observateur", // XXX: jointure annuaire */ |
/* présents dans cel_obs mais exclus: |
ordre, nom_ret, nom_ret_nn, latitude, longitude, altitude, geodatum |
transmission, date_creation, date_modificationabondance, certitude, phenologie, code_insee_calcule */ |
'images' => array( // v_del_image |
"id_image" => 1, |
"hauteur" => 1, |
// "largeur" => 1, inutile semble-t-il |
"date_prise_de_vue" => "date"), |
/* présents dans cel_images mais exclus: |
i_commentaire, nom_original, publiable_eflore, i_mots_cles_texte, i_ordre, |
i_ce_utilisateur, i_prenom_utilisateur, i_nom_utilisateur, i_courriel_utilisateur */ |
'protocoles' => array( // del_image_protocole |
"ce_protocole" => "protocole.id", |
"id_protocole" => "protocole.id", |
"intitule" => "protocole.intitule", |
"descriptif" => "protocole.descriptif", |
"tag" => "protocole.tag"), |
/* See desc del_commentaire_vote & desc del_image_vote; |
Les deux schémas sont similaires, à l'exception de ce_protocole |
spécifique à del_image_vote et ce_proposition => ce_image */ |
'votes' => array( // del_image_vote et del_commentaire_vote |
"id_vote" => "vote.id", |
"ce_proposition" => "proposition.id", |
"ce_image" => "image.id", |
"ce_utilisateur" => "auteur.id", // attention, conflit avec commentaire, cf ci-dessous |
"valeur" => "vote", |
"date" => 1, // attention, conflit avec commentaire, cf ci-dessous |
// absents du JSON, et pourtant présents dans services/configurations/config_mapping_votes.ini |
// (nécessiterait une propre jointure sur del_utilisateur) |
/* "nom" => "auteur.nom", |
"prenom" => "auteur.prenom", |
"courriel" => "auteur.courriel" */), |
'commentaires' => array( // del_commentaire |
"id_commentaire" => 1, |
"ce_observation" => "observation", |
"ce_proposition" => "proposition", |
"ce_commentaire_parent" => "id_parent", |
// les deux alias suivants sont particuliers afin d'éviter un conflit d'alias |
// lors des jointures avec del_commentaire_vote ci-dessus |
// (cf cas particulier dans la boucle de chargerCommentaires()) |
"ce_utilisateur" => "__auteur_com", |
"date" => "__date_com", |
"texte" => 1, |
"utilisateur_nom" => "auteur.nom", |
"utilisateur_prenom" => "auteur.prenom", |
"utilisateur_courriel" => "auteur.courriel", |
"nom_sel" => 1, |
"nom_sel_nn" => 1, |
"nom_ret_nn" => 1, |
"nom_referentiel" => 1, |
"proposition_initiale" => 1), |
); |
private $conteneur; |
private $gestionBdd; |
private $bdd; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_votes.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_votes.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_commentaires.ini'); |
$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) { |
if (!$ressources || count($ressources) != 1 ) { |
throw new Exception("Le service observation accepte un unique identifiant d'observation", RestServeur::HTTP_CODE_ERREUR); |
} |
// initialise les mappings: |
// substitue les valeurs à 1 par le nom de la clef (pas d'alias de champ) |
array_walk(self::$mappings['observations'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
array_walk(self::$mappings['images'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
array_walk(self::$mappings['protocoles'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
array_walk(self::$mappings['votes'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
array_walk(self::$mappings['commentaires'], create_function('&$val, $k', 'if($val==1) $val = $k;')); |
// Gestion des configuration du script |
$idobs = $ressources[0]; |
$protocole = isset($parametres['protocole']) && is_numeric($parametres['protocole']) ?intval($parametres['protocole']) : NULL; |
// 1) récupération de l'observation (et de ses images (v_del_image est une vue utilisant des INNER JOIN)) |
$liaisons = self::chargerObservation($this->bdd, $idobs); |
if(!$liaisons) { |
header('HTTP/1.0 404 Not Found'); |
// don't die (phpunit) |
throw(new Exception()); |
} |
// 2) réassocie les images "à plat" à leur observation (merge) |
// TODO: appliquer le formattage dépendant de la configuration en fin de processus |
$observations = self::reformateObservationSimpleIndex($liaisons, $this->conteneur->getParametre('url_images')); |
// bien que dans notre cas il n'y ait qu'une seule observation, issue de plusieurs images |
// dans $liaisons, $observation est un tableau (cf reformateObservation). |
// Considérons la chose comme telle au cas où le webservice doivent demain demander une paire |
// d'observations (... convergence avec ListeObservations & DelTk) |
$observation = array_pop($observations); |
// 3) charge les données de votes et protocoles associés aux images |
if($observation['images']) { |
$votes = self::chargerVotesImage($this->bdd, $observation['images'], $protocole); |
// 3") merge/reformate les données retournées |
self::mapVotesToImages($votes, |
$observation['images']); |
} |
// 4) charge les commentaires et les votes associés |
// modifie/créé $observation['commentaires'] |
self::chargerCommentaires($this->bdd, $observation); |
// désindexe le tableau (tel qu'apparement attendu par les applis), c'est une exception |
// corriger l'appli cliente pour utiliser les index puis supprimer cette ligne |
$observation['images'] = array_values($observation['images']); |
// autre élément de post-processing: le ce_utilisateur de l'observation non-numeric... |
if(!is_numeric($observation['auteur.id'])) $observation['auteur.id'] = "0"; |
if(!isset($observation['auteur.nom'])) $observation['auteur.nom'] = '[inconnu]'; |
if(isset($parametres['justthrow'])) return $observation; |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = $observation; |
return $resultat; |
} |
static function chargerObservation($db, $idobs) { |
// prenom_utilisateur, nom_utilisateur, courriel_utilisateur sont exclus du mapping |
// car nous utilisons une construction SQL élaborée pour eux (cf IFNULL ci-dessous) |
$obs_fields = DelTk::sqlFieldsToAlias(self::$mappings['observations'], NULL, 'dob'); |
$image_fields = DelTk::sqlFieldsToAlias(self::$mappings['images'], NULL, 'dob'); |
// champs de l'annuaire (del_utilisateur): id_utilisateur prenom, nom, courriel |
$annuaire_fields = implode(', ', array("IFNULL(du.prenom, prenom_utilisateur) AS `auteur.prenom`", |
"IFNULL(du.nom, nom_utilisateur) AS `auteur.nom`", |
"IFNULL(du.courriel, courriel_utilisateur) AS observateur")); |
return $db->recupererTous(sprintf( |
'SELECT %s, %s, %s FROM v_del_image as dob'. |
' LEFT JOIN del_utilisateur du ON CAST(du.id_utilisateur AS CHAR) = CAST(dob.ce_utilisateur AS CHAR)'. |
' WHERE dob.id_observation = %d -- %s', |
$obs_fields, $image_fields, $annuaire_fields, $idobs, __FILE__ . ':' . __LINE__)); |
} |
// Charger les images et leurs votes associés |
static function chargerVotesImage($db, $images, $protocole = NULL) { |
if(!$images) return NULL; |
$select = array('votes' => |
array('id_vote', 'ce_image', 'ce_protocole', 'ce_utilisateur', 'valeur', 'date', /* del_image_vote */), |
'protocole' => |
array('id_protocole', 'intitule', 'descriptif', 'tag' /* del_image_protocole */ )); |
$vote_fields = DelTk::sqlFieldsToAlias(self::$mappings['votes'], $select['votes'], 'v'); // "v": cf alias dans la requête |
$proto_fields = DelTk::sqlFieldsToAlias(self::$mappings['protocoles'], $select['protocole'], 'p'); |
$where = array(); |
$where[] = sprintf('v.ce_image IN (%s)', |
implode(',', array_values(array_map(create_function('$a', 'return $a["id_image"];'), $images)))); |
if ($protocole) { |
$where[] = "v.ce_protocole = $protocole"; |
} |
return $db->recupererTous(sprintf( |
'SELECT %s, %s FROM del_image_vote AS v'. |
' INNER JOIN del_image_protocole p ON v.ce_protocole = p.id_protocole'. |
' WHERE %s -- %s', |
$vote_fields, $proto_fields, |
$where ? implode(' AND ', $where) : 1, |
__FILE__ . ':' . __LINE__)); |
} |
/** |
* Formater une observation depuis une ligne liaison |
* @param $liaison liaison issue de la recherche |
* @return $observation l'observation mise en forme |
* Exemple: vote, au sortir de MySQL contient: |
* 'xxx' => 'blah', 'descriptif' => 'foo', 'valeur' => 3 |
* et le tableau de mapping contient: |
* descriptif = protocole.descriptif, valeur = vote |
* Alors $retour[ contient: |
* |
* */ |
static function mapVotesToImages($votes, &$images) { |
if(!$votes) return; |
// pour chaque vote |
foreach ($votes as $vote) { |
$imgid = $vote['image.id']; |
$protoid = $vote['protocole.id']; |
// un vote sans image associée ? est-ce possible ? |
// if(!isset($images[$imgid])) continue; |
if(!array_key_exists('protocoles_votes', $images[$imgid]) || |
!array_key_exists($protoid, $images[$imgid]['protocoles_votes'])) { |
// extrait les champs spécifique au protocole (le LEFT JOIN de chargerVotesImage les ramène en doublons |
$protocole = array_intersect_key($vote, array_flip(self::$mappings['protocoles'])); |
$images[$imgid]['protocoles_votes'][$protoid] = $protocole; |
} |
$vote = array_intersect_key($vote, array_flip(self::$mappings['votes'])); |
$images[$imgid]['protocoles_votes'][$protoid]['votes'][$vote['vote.id']] = $vote; |
} |
} |
// Charger les commentaires et leurs votes associés |
static function chargerCommentaires($db, &$observation) { |
$select = array('votes' => |
array('id_vote', 'ce_proposition', 'ce_utilisateur', 'valeur', 'date' /* del_commentaire_vote */), |
'commentaires' => |
array('id_commentaire', 'ce_observation', 'ce_proposition', 'ce_commentaire_parent', 'texte', |
'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')); |
$vote_fields = DelTk::sqlFieldsToAlias(self::$mappings['votes'], $select['votes'], 'cv'); // "v": cf alias dans la requête |
$comment_fields = DelTk::sqlFieldsToAlias(self::$mappings['commentaires'], $select['commentaires'], 'dc'); |
$commentaires = $db->recupererTous(sprintf( |
"SELECT %s, %s FROM del_commentaire as dc". |
// LEFT JOIN optionnel, mais explicatif: |
// on ne récupère des infos de vote que pour les commentaires comportant un |
// nom_sel "valide" |
" LEFT JOIN del_commentaire_vote cv". |
" ON cv.ce_proposition = dc.id_commentaire AND dc.nom_sel != '' AND dc.nom_sel IS NOT NULL". |
" WHERE ce_observation = %d -- %s", |
$comment_fields, $vote_fields, |
$observation['id_observation'], |
__FILE__ . ':' . __LINE__)); |
if(!$commentaires) return; |
// les commentaires réunifiées et dont les votes sont mergés |
$ret = array(); |
foreach ($commentaires as $comment) { |
$commentid = $comment['id_commentaire']; |
$voteid = $comment['vote.id']; |
if(!array_key_exists($commentid, $ret)) { |
$comment_extract = array_intersect_key($comment, array_flip(self::$mappings['commentaires'])); |
// cas particulier: conflit d'aliases avec del_commentaire_vote |
$comment_extract['auteur.id'] = $comment_extract['__auteur_com']; |
$comment_extract['date'] = $comment_extract['__date_com']; |
unset($comment_extract['__auteur_com'], $comment_extract['__date_com']); |
// toujours un éléments "votes", quand bien même il n'y en aurait pas |
$comment_extract['votes'] = array(); |
$ret[$commentid] = $comment_extract; |
} |
if(!$comment['nom_sel'] || ! $voteid) continue; |
$vote = array_intersect_key($comment, array_flip(self::$mappings['votes'])); |
$ret[$commentid]['votes'][$voteid] = $vote; |
} |
$observation['commentaires'] = $ret; |
} |
// cf ListeObservation::reformateObservation() et ListeImages2::reformateImagesDoubleIndex() |
// (trop de variétés de formatage, à unifier côté client pour unifier côté backend ...) |
static function reformateObservationSimpleIndex($obs, $url_pattern = '') { |
// XXX: cf Observation.php::consulter(), nous pourriouns ici |
// conserver les valeurs vides (pour les phptests notamment, ou non) |
$obs = array_map('array_filter', $obs); |
$obs_merged = array(); |
foreach($obs as $o) { |
$id = $o['id_observation']; |
$image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original'))); |
$image['binaire.href'] = sprintf($url_pattern, $image['id_image']); |
unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']); |
if(!isset($obs_merged[$id])) $obs_merged[$id] = $o; |
$obs_merged[$id]['images'][$image['id_image']] = $image; |
} |
return $obs_merged; |
} |
} |
/branches/v1.1-helium/services/modules/0.1/observations/ListeObservations.php |
---|
New file |
0,0 → 1,435 |
<?php |
/** |
* Le web service observations récupère toutes les observations et, pour chacune d'elle, les |
* images qui lui sont associées. |
* Basée sur la classe antérieure dans ListeObservations.php de |
* Grégoire Duché et Aurélien Peronnet |
* (formaterVote, formaterDeterminations, chargerNombreCommentaire, chargerVotes, chargerDeterminations) |
* |
* @category php 5.2 |
* @package del |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @copyright Copyright (c) 2013 Tela Botanica (accueil@tela-botanica.org) |
* @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=ApiIdentiplante01Observations |
* |
* TODO: |
* PDO::prepare() |
* Sphinx pour auteur, genre, ns, commune, tag et masque-général |
*/ |
require_once(dirname(__FILE__) . '/../DelTk.php'); |
/* |
restore_error_handler(); |
restore_exception_handler(); |
error_reporting(E_ALL); |
*/ |
class ListeObservations { |
private $conteneur; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
static $tris_possibles = array('date_observation'); |
// paramètres autorisés |
static $sql_fields_liaisons = array( |
'dob' => array('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', 'zone_geo', 'lieudit', |
'station', 'milieu', 'date_observation', 'mots_cles_texte', 'date_transmission', |
'ce_utilisateur AS `auteur.id`', 'prenom_utilisateur AS `auteur.prenom`', |
'nom_utilisateur AS `auteur.nom`', 'courriel_utilisateur AS observateur', |
'commentaire'), |
'di' => array('id_image', 'date_prise_de_vue AS `date`', 'hauteur',/* 'largeur','nom_original' // apparemment inutilisés */), |
'du' => array('prenom', 'nom', 'courriel'), |
'dc' => array('commentaire') |
); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_departements_bruts.ini'); |
$this->conteneur->chargerConfiguration('config_observations.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_votes.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_commentaires.ini'); |
$this->navigation = $conteneur->getNavigation(); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
static function reformateObservation($obs, $url_pattern = '') { |
$obs = array_map('array_filter', $obs); |
$obs_merged = array(); |
foreach($obs as $o) { |
$id = $o['id_observation']; |
// 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'affaire |
if(!isset($o['auteur.id']) || !is_numeric($o['auteur.id'])) $o['auteur.id'] = "0"; |
if(!isset($o['auteur.nom'])) $o['auteur.nom'] = '[inconnu]'; |
$image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original'))); |
$image['binaire.href'] = sprintf($url_pattern, $image['id_image']); |
unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']); |
if(!isset($obs_merged['"' . $id . '"'])) $obs_merged['"' . $id . '"'] = $o; |
$obs_merged['"' . $id . '"']['images'][] = $image; |
} |
return $obs_merged; |
} |
/** |
* 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) { |
// SELECT, à terme, pourrait affecter getInfos(), mais en aucune manière getIdObs() |
$req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array()); |
// toujours nécessaire puisque nous tapons sur v_del_image qui INNER JOIN cel_images, or nous voulons certes |
// toutes les images, mais nous voulons $limite observations uniques. |
$req['groupby'][] = 'vdi.id_observation'; |
$db = $this->bdd; |
// filtrage de l'INPUT |
$params = DelTk::requestFilterParams($parametres, DelTk::$parametres_autorises, $this->conteneur); |
$params['masque.tag'] = DelTk::buildTagsAST(@$parametres['masque.tag'], 'OR', ','); |
// ... et paramètres par défaut |
$params = array_merge(DelTk::$default_params, $params); |
// création des contraintes (masques) |
DelTk::sqlAddConstraint($params, $db, $req); |
self::sqlAddConstraint($params, $db, $req, $this->conteneur); |
self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur); |
// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS) |
$idobs_tab = self::getIdObs($params, $req, $db); |
// idobs est une liste (toujours ordonnée) des id d'observations recherchées |
$idobs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'), $idobs_tab)); |
if($idobs) { |
$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']); |
// 2) récupération des données nécessaires pour ces observations (obs + images) |
// ici les champs récupérés sont issus de self::$sql_fields_liaisons mais sans préfixes |
// car tout provient de v_del_image |
$obs_unfmt = self::getInfos($idobs, $db); |
// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output |
$observations = self::reformateObservation($obs_unfmt, $this->conteneur->getParametre('url_images')); |
// 4) récupération des données nécessaires pour ces observations (commentaires + votes) |
// modifie $observations |
$this->configurer(); |
$this->chargerDeterminations($observations); |
// 5) restauration de l'ordre souhaité initialement |
$observations = self::sortArrayByArray($observations, $idobs); |
} else { |
$observations = array(); |
$total = 0; |
} |
// 6) JSON output |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => DelTk::makeJSONHeader($total, $params, Config::get('url_service')), |
'resultats' => $observations); |
return $resultat; |
} |
static function sortArrayByArray($array, $orderArray) { |
$ordered = array(); |
foreach($orderArray as $key) { |
if(array_key_exists('"' . $key . '"', $array)) { |
$ordered['"' . $key . '"'] = $array['"' . $key . '"']; |
unset($array['"' . $key . '"']); |
} |
} |
return $ordered + $array; |
} |
// 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 |
*/ |
static function getIdObs($p, $req, $db) { |
$req_s = sprintf('SELECT SQL_CALC_FOUND_ROWS id_observation' . |
' FROM v_del_image vdi'. |
' %s' . // LEFT JOIN if any |
' WHERE %s'. // where-clause ou TRUE |
' %s'. // group-by |
' %s'. // having (si commentaires) |
' ORDER BY %s %s %s'. |
' LIMIT %d, %d -- %s', |
$req['join'] ? implode(' ', $req['join']) : '', |
$req['where'] ? implode(' AND ', $req['where']) : 'TRUE', |
$req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '', |
$req['having'] ? ('HAVING ' . implode(' AND ', $req['having'])) : '', |
$p['tri'], strtoupper($p['ordre']), |
// date_transmission peut-être NULL et nous voulons de la consistence |
// (sauf après r1860 de Cel) |
$p['tri'] == 'date_transmission' ? ', id_observation' : '', |
$p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__); |
$res = $db->recupererTous($req_s); |
$err = mysql_error(); |
if(!$res && $err) { |
// http_response_code(400); |
// if(defined('DEBUG') && DEBUG) header("X-Debug: $req_s"); |
throw new Exception('not found', 400); |
} |
// ordre préservé, à partir d'ici c'est important. |
return $res; |
} |
/* |
Champs récupérés: |
Pour del_images, la vue retourne déjà ce que nous recherchons de cel_obs et cel_images |
(cel_obs.* et cel_[obs_]images.{id_observation, id_image, date_prise_de_vue AS date, hauteur, largeur}) |
Pour del_commentaires: nous voulons * |
Reste ensuite à formatter. |
Note: le préfixe de table utilisé ici (vdi) n'impacte *aucune* autre partie du code car rien |
n'en dépend pour l'heure. (inutilisation de $req['select']) |
*/ |
static function getInfos($idobs, $db) { |
/*$select_fields = implode(',', array_merge( |
array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['dob']), |
array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['di']), |
array_map(create_function('$a', 'return "du.".$a;'), self::$sql_fields_liaisons['du'])));*/ |
$select_fields = array_merge(self::$sql_fields_liaisons['dob'], |
self::$sql_fields_liaisons['di']); |
$req_s = sprintf('SELECT %s FROM v_del_image vdi'. |
// ' LEFT JOIN del_commentaire AS dc ON di.id_observation = dc.ce_observation AND dc.nom_sel IS NOT NULL'. |
' WHERE id_observation IN (%s)', |
implode(',', $select_fields), |
implode(',', $idobs)); |
return $db->recupererTous($req_s); |
} |
/** |
* Complément à DelTk::sqlAddConstraint() |
* |
* @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes) |
* @param $req le tableau, passé par référence représentant les composants de la requête à bâtir |
* @param $c conteneur, utilisé soit pour l'appel récursif à requestFilterParams() en cas de param "masque" |
* soit pour la définition du type (qui utilise la variable nb_commentaires_discussion) |
*/ |
static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) { |
if(!empty($p['masque.tag'])) { |
// TODO: remove LOWER() lorsqu'on est sur que les tags sont uniformés en minuscule |
// i_mots_cles_texte provient de la VIEW v_del_image |
if(isset($p['masque.tag']['AND'])) { |
/* Lorsque nous interprêtons la chaîne provenant du masque général (cf: buildTagsAST($p['masque'], 'OR', ' ') dans sqlAddMasqueConstraint()), |
nous sommes splittés par espace. Cependant, assurons que si une virgule à été saisie, nous n'aurons pas le motif |
" AND CONCAT(mots_cles_texte, i_mots_cles_texte) REGEXP ',' " dans notre requête. |
XXX: Au 12/11/2013, une recherche sur tag depuis le masque général implique un OU, donc le problème ne se pose pas ici */ |
$subwhere = array(); |
foreach($p['masque.tag']['AND'] as $tag) { |
if(trim($tag) == ',') continue; |
$subwhere[] = sprintf('LOWER(CONCAT(%s)) REGEXP %s', |
DelTk::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')), |
$db->proteger(strtolower($tag))); |
} |
$req['where'][] = '(' . implode(' AND ', $subwhere) . ')'; |
} |
else { |
$req['where'][] = sprintf('LOWER(CONCAT(%s)) REGEXP %s', |
DelTk::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')), |
$db->proteger(strtolower(implode('|', $p['masque.tag']['OR'])))); |
} |
} |
if(!empty($p['masque.type'])) { |
self::addTypeConstraints($p['masque.type'], $db, $req, $c); |
} |
} |
/* Le masque fait une recherche générique parmi de nombreux champs ci-dessus. |
Nous initialisons donc ces paramètres (excepté masque biensur), et nous rappelons |
récursivement. À la seule différence que nous n'utiliserons que $or_req['where'] |
imploded par des " OR ". */ |
static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) { |
if(!empty($p['masque'])) { |
$or_params = array('masque.auteur' => $p['masque'], |
'masque.departement' => $p['masque'], |
'masque.id_zone_geo' => $p['masque'], |
'masque.tag' => $p['masque'], |
'masque.ns' => $p['masque'], |
'masque.famille' => $p['masque'], |
'masque.date' => $p['masque'], |
'masque.genre' => $p['masque'], |
/* milieu: TODO ? */ ); |
/* Cependant les champs spécifiques ont priorité sur le masque général. |
Pour cette raison nous supprimons la génération de SQL du masque général sur les |
champ spécifiques qui feront l'objet d'un traitement avec une valeur propre. */ |
if(isset($p['masque.auteur'])) unset($or_params['masque.auteur']); |
if(isset($p['masque.departement'])) unset($or_params['masque.departement']); |
if(isset($p['masque.id_zone_geo'])) unset($or_params['masque.id_zone_geo']); |
if(isset($p['masque.tag'])) unset($or_params['masque.tag']); |
if(isset($p['masque.famille'])) unset($or_params['masque.famille']); |
if(isset($p['masque.date'])) unset($or_params['masque.date']); |
if(isset($p['masque.genre'])) unset($or_params['masque.genre']); |
$or_masque = DelTk::requestFilterParams($or_params, array_keys($or_params), $c); |
if(isset($or_params['masque.tag'])) { |
$or_masque['masque.tag'] = DelTk::buildTagsAST($p['masque'], 'OR', ' '); |
} |
// $or_req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array()); |
$or_req = array('join' => array(), 'where' => array()); |
DelTk::sqlAddConstraint($or_masque, $db, $or_req); |
self::sqlAddConstraint($or_masque, $db, $or_req); |
if($or_req['where']) { |
$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')'; |
// utile au cas ou des jointures seraient rajoutées |
$req['join'] = array_unique(array_merge($req['join'], $or_req['join'])); |
} |
} |
} |
private function configurer() { |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire'); |
} |
/* |
* @param $req: la représentation de la requête MySQL complète, à amender. |
*/ |
static function addTypeConstraints($val, $db, &$req, Conteneur $c) { |
if(array_key_exists('adeterminer', $val)) { |
// On récupère toutes les observations qui on le tag "aDeterminer" *ou* qui n'ont pas de nom d'espèce |
// *ou* qui ont la "certitude" à ("aDeterminer" *ou* "douteux") |
$req['where'][] = '(' . implode(' OR ', array( |
'vdi.certitude = "aDeterminer"', |
'vdi.certitude = "douteux"', |
'vdi.mots_cles_texte LIKE "%aDeterminer%"', |
'vdi.nom_sel_nn IS NULL', // TODO: ensure pas d'entrée à 0 |
)) . ')'; |
} |
if(array_key_exists('validees', $val)) { |
//On récupère toutes les observations ayant un commentaire doté de proposition_retenue = 1 |
$req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation AND dc.proposition_retenue = 1'; |
} |
// solution n°1: impraticable |
if(false && array_key_exists('endiscussion', $val)) { |
//Si on veut les observations en discussion, |
// on va récupérer les ids des observations dont le nombre de commentaire est supérieur à N |
$req['select'][] = 'COUNT(dc.id_commentaire) AS comm_count'; |
$req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation'; |
$req['groupby'][] = 'vdi.id_observation'; |
$req['having'][] = "COUNT(id_commentaire) > " . $c->getParametre('nb_commentaires_discussion'); |
} |
if(array_key_exists('endiscussion', $val)) { |
$req['where'][] = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc'. |
' WHERE ce_observation = id_observation) > ' . intval($c->getParametre('nb_commentaires_discussion')); |
} |
} |
/** |
* 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(&$observations) { |
$idObs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'), |
$observations)); |
$r = sprintf('SELECT * FROM del_commentaire AS dc WHERE dc.nom_sel IS NOT NULL AND ce_observation IN (%s) -- %s', |
implode(',',$idObs), |
__FILE__ . ':' . __LINE__); |
$propositions = $this->bdd->recupererTous($r); |
if(!$propositions) return; |
foreach ($propositions as $proposition) { |
$idObs = $proposition['ce_observation']; |
$idComment = $proposition['id_commentaire']; |
$comment = $this->formaterDetermination($idComment, $proposition); |
if($comment) $observations['"' . $idObs . '"']['commentaires'][$idComment] = $comment; |
} |
} |
private function formaterDetermination($commentId, $proposition) { |
if(!$proposition) return NULL; |
$proposition_formatee = array('nb_commentaires' => '0'); |
foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) { |
if (isset($proposition[$nomOriginal])) { |
$proposition_formatee[$nomFinal] = $proposition[$nomOriginal]; |
} |
} |
// Charger les votes sur les déterminations |
$resultatsVotes = $this->bdd->recupererTous( |
sprintf('SELECT * FROM del_commentaire_vote WHERE ce_proposition = %d', $commentId)); |
foreach ($resultatsVotes as $vote) { |
$proposition_formatee['votes'][$vote['id_vote']] = $this->formaterVote($vote); |
} |
// chargerNombreCommentaire() |
// Charger le nombre de commentaires (sans détermination) associé à l'observation |
$listeCommentaires = $this->bdd->recupererTous(sprintf( |
'SELECT ce_commentaire_parent, ce_proposition, COUNT( id_commentaire ) AS nb '. |
'FROM del_commentaire WHERE ce_proposition = %d GROUP BY ce_proposition -- %s', |
$commentId, __FILE__ . ':' . __LINE__)); |
foreach ($listeCommentaires as $ligneProposition) { |
// ce test sert à exclure les proposition de 1er niveau qui sont elles aussi des commentaires |
if($ligneProposition['ce_commentaire_parent']) { |
// TODO/debug: id_commentaire_parent != $commentId ?? |
// reprendre la "logique" du code... moins de boucles, moins de requêtes, ... |
if($ligneProposition['ce_commentaire_parent'] != $commentId) { |
// restore_error_handler(); |
error_log(sprintf("possible error: nb_commentaires = %s: comment = %d, parent = %d, %s", |
$ligneProposition['nb'], $commentId, $ligneProposition['ce_commentaire_parent'], __FILE__)); |
} |
$proposition_formatee['nb_commentaires'] = $ligneProposition['nb']; |
} else { |
$proposition_formatee['observation']['nb_commentaires'] = $ligneProposition['nb']; |
} |
} |
return $proposition_formatee; |
} |
/** |
* Formater un vote en fonction du fichier de configuration config_votes.ini |
* @param $votes array() |
* */ |
private function formaterVote($vote) { |
$retour = array(); |
foreach ($vote as $param=>$valeur) { |
$retour[$this->mappingVotes[$param]] = $valeur; |
} |
return $retour; |
} |
} |
/branches/v1.1-helium/services/modules/0.1/MotsCles.php |
---|
New file |
0,0 → 1,211 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package del |
* @author Aurélien 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> |
* @version 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class MotsCles extends RestService { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/motscles/#id => les mots clés associés à une image donnée |
* */ |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function ajouter($ressources, $parametres) { |
$this->methode = 'ajouter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function supprimer($ressources) { |
$this->methode = 'supprimer'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->ressources = $ressources; |
$this->conteneur = new Conteneur(); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
echo $reponseHttp->getCorps(); |
} |
} |
public function modifier($ressources, $requeteDonnees) { |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
$retour = $this->initialiserService(); |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->chargerNomDuProjet(); |
$this->chargerConfigProjet(); |
} |
private function chargerNomDuProjet() { |
$this->projetNom = 'motscles'; |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_mots_cles.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function chargerNomService() { |
// si la méthode est POST, on ajouter un commentaire |
if ($this->methode == 'ajouter') { |
$this->serviceNom = 'ajouter-mot-cle'; |
} else if ($this->methode == 'supprimer') { |
$this->serviceNom = 'supprimer-mot-cle'; |
} |
else { |
//S'il n'y a pas de ressources => tous les commentaires |
if (!isset($this->ressources) || empty($this->ressources)) { |
$this->serviceNom = 'liste-mots-cles'; |
} else { |
if (!is_numeric($this->ressources[0])) { |
$message = "La première ressource doit être un identifiant"; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} else { |
$this->serviceNom = 'consulter-mots-cles'; |
} |
} |
} |
} |
private function editerMessageErreurRessource() { |
$message = "Le service demandé '".$this->projetNom.'/'.implode('/', $this->ressources). |
"' n'est pas disponible pour le projet ".$this->projetNom." !\n". |
"Les services disponibles sont : images, images/#id/votes, images/#id/vote/#id_vote"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
private function etreRessourceIdentifiant($num) { |
$presenceId = false; |
if (is_numeric($this->ressources[$num])) { |
$presenceId = true; |
} else { |
$message = "Le service demandé '$service' nécessite d'avoir un identifiant d'image valide"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $presenceId; |
} |
private function initialiserService() { |
$this->chargerNomService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_mots_cles.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'modifier') { |
$retour = $service->modifier($this->ressources, $this->parametres); |
} elseif ($this->methode == 'supprimer') { |
$retour = $service->supprimer($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Protocoles.php |
---|
New file |
0,0 → 1,196 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Protocoles extends RestService { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/observations/ => toutes les observations (infos obs, infos images, infos propositions, infos nb commentaires) |
* http://localhost/del/services/0.1/observations/#id => une observation donnée et ses images, SANS LES propositions & nombre de commentaire |
* */ |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function ajouter($ressources, $requeteDonnees) { |
$this->methode = 'ajouter'; |
$resultat = ''; |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
if ($this->avoirRessourceService()) { |
$retour = $this->initialiserService(); |
} |
return $retour; |
} |
private function avoirRessourceIdentifiant($num) { |
$presenceId = false; |
if (is_numeric($this->ressources[$num])) { |
$presenceId = true; |
} else { |
$message = "Le service demandé '$service' nécessite d'avoir un identifiant d'image valide"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $presenceId; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->chargerNomDuProjet(); |
$this->chargerConfigProjet(); |
} |
private function chargerNomDuProjet() { |
$this->projetNom = 'protocoles'; |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function avoirRessourceService() { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/observations/ => toutes les observations (infos obs, infos images, infos propositions, infos nb commentaires) |
* http://localhost/del/services/0.1/observations/#id => une observation donnée et ses images, SANS LES propositions & nombre de commentaire |
* */ |
$presenceRessourceService = false; |
if (isset($this->ressources[0])) { |
if ($this->avoirRessourceIdentifiant(0)) { |
if (sizeof($this->ressources) == 1) { |
$presenceRessourceService = true; |
$this->serviceNom = 'observation'; |
} else { |
if (isset($this->ressources[1])) { |
$presenceRessourceService = $this->avoirRessourceSousService(); |
} |
} |
} |
} else { |
$presenceRessourceService = true; |
$this->serviceNom = 'liste-protocoles'; |
} |
return $presenceRessourceService; |
} |
private function avoirRessourceSousService() { |
$presenceRessourceService = false; |
$servicesDispo = Outils::recupererTableauConfig('servicesDispo'); |
if ($this->avoirRessourceIdentifiant(1)) { |
$service = $this->ressources[2]; |
if (in_array($service, $servicesDispo)) { |
$presenceRessourceService = true; |
$this->serviceNom = 'vote-observation'; |
} else { |
$message = "Le service demandé '$service' n'est pas disponible pour le projet {$this->projetNom} !\n". |
"Les services disponibles sont : ".implode(', ', $servicesDispo); |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
} |
return $presenceRessourceService; |
} |
private function initialiserService() { |
//$this->chargerNomDuService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Utilisateurs.php |
---|
New file |
0,0 → 1,159 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Utilisateurs extends RestService { |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function modifier($ressources, $parametres) { |
$this->methode = 'modifier'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
$retour = $this->initialiserService(); |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->projetNom = 'utilisateurs'; |
$this->chargerConfigProjet(); |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserService() { |
$this->chargerNomService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'modifier') { |
$retour = $service->modifier($this->ressources, $this->parametres); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function chargerNomService() { |
//S'il n'y a pas de ressources => envoyer sur identification anonyme |
if (!isset($this->ressources) || empty($this->ressources)) { |
$this->serviceNom = 'identification-anonyme'; |
} else { |
//S'il y a 1 ressource et que celle ci est 'deconnecter', envoyer vers deconnecter |
if (sizeof($this->ressources) == 1 && ($this->ressources[0] == 'deconnecter')) { |
$this->serviceNom = 'deconnecter'; |
} else if(sizeof($this->ressources) == 2 && $this->ressources[1] == 'preferences') { |
$this->serviceNom = 'preferences'; |
} else if (sizeof($this->ressources) == 2) { |
$this->serviceNom = 'connecter'; |
} else { |
$this->serviceNom = 'identification-anonyme'; |
} |
} |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/syndication/squelettes/opml.tpl.xml |
---|
New file |
0,0 → 1,18 |
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?> |
<opml version="1.0"> |
<head> |
<text/> |
</head> |
<body> |
<outline text="DEL"> |
<?php foreach ($liste_flux as $flux) : ?> |
<outline title="<?=$flux['titre']?>" |
description="<?=$flux['description']?>" |
htmlUrl="<?=$flux['url_html']?>" |
xmlUrl="<?=$flux['url_xml']?>" |
type="<?=$flux['type']?>" |
text="<?=$flux['texte']?>"/> |
<?php endforeach; ?> |
</outline> |
</body> |
</opml> |
/branches/v1.1-helium/services/modules/0.1/syndication/squelettes/rss1.tpl.xml |
---|
New file |
0,0 → 1,44 |
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?> |
<!DOCTYPE rdf:RDF [ |
<!ENTITY % HTMLlat1 PUBLIC |
"-//W3C//ENTITIES Latin 1 for XHTML//EN" |
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent"> |
%HTMLlat1; |
]> |
<rdf:RDF |
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
xmlns:dc="http://purl.org/dc/elements/1.1/" |
xmlns="http://purl.org/rss/1.0/"> |
<channel rdf:about="<?=$guid?>"> |
<title><?=$titre?></title> |
<link><?=$lien_service?></link> |
<description><?=$description?></description> |
<dc:publisher><?=$editeur?></dc:publisher> |
<dc:date><?=$date_maj_W3C?></dc:date> |
<?php if (isset($items)) : ?> |
<items> |
<rdf:Seq> |
<?php foreach ($items as $item) : ?> |
<rdf:li resource="<?=$item['guid']?>" /> |
<?php endforeach; ?> |
</rdf:Seq> |
</items> |
<?php endif; ?> |
</channel> |
<?php if (isset($items)) : ?> |
<?php foreach ($items as $item) : ?> |
<item rdf:about="<?=$item['guid']?>"> |
<title><?=$item['titre']?></title> |
<link><?=(isset($item['lien'])) ? $item['lien'] : 'http://www.tela-botanica.org/'?></link> |
<description><?=$item['description_encodee']?></description> |
<dc:creator><?=$item['modifier_par']?></dc:creator> |
<dc:date><?=$item['date_maj_W3C']?></dc:date> |
</item> |
<?php endforeach; ?> |
<?php endif; ?> |
</rdf:RDF> |
/branches/v1.1-helium/services/modules/0.1/syndication/squelettes/rss2.tpl.xml |
---|
New file |
0,0 → 1,26 |
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?> |
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> |
<channel> |
<title><?=$titre?></title> |
<link><?=$lien_service?></link> |
<atom:link href="<?=$lien_service?>" rel="self" type="application/rss+xml" /> |
<description><?=$description?></description> |
<?php if (isset($items)) : ?> |
<?php foreach ($items as $item) : ?> |
<item> |
<guid><?=$item['guid']?></guid> |
<title><?=$item['titre']?></title> |
<? if (isset($item['lien'])) : ?> |
<link><?=$item['lien']?></link> |
<? endif; ?> |
<description><?=$item['description_encodee']?></description> |
<category><?= $item['categorie'] ?></category> |
<author><?=$item['modifier_par']?></author> |
<pubDate><?=$item['date_maj_RSS']?></pubDate> |
</item> |
<?php endforeach; ?> |
<?php endif; ?> |
</channel> |
</rss> |
/branches/v1.1-helium/services/modules/0.1/syndication/squelettes/atom.tpl.xml |
---|
New file |
0,0 → 1,36 |
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?> |
<feed xmlns="http://www.w3.org/2005/Atom"> |
<title><?=$titre?></title> |
<link href="<?=$lien_service?>" rel="alternate" type="text/html" hreflang="fr" /> |
<link href="<?=$lien_service?>" rel="self" type="application/atom+xml"/> |
<updated><?=$date_maj_ATOM?></updated> |
<author> |
<name><?=$editeur?></name> |
</author> |
<id><?=$guid?></id> |
<rights>Copyright (c) <?=$annee_courante?>, <?=$editeur?></rights> |
<generator uri="<?=$lien_service?>" version="<?=$generateur_version?>"><?=$generateur?></generator> |
<?php if (isset($items)) : ?> |
<?php foreach ($items as $item) : ?> |
<entry> |
<id><?=$item['guid']?></id> |
<title><?=$item['titre']?></title> |
<? if (isset($item['lien'])) : ?> |
<link href="<?=$item['lien']?>"/> |
<? endif; ?> |
<updated><?=$item['date_maj_ATOM']?></updated> |
<published><?=$item['date_maj_ATOM']?></published> |
<author><name><?=$item['modifier_par']?></name></author> |
<content type="xhtml" xml:lang="fr"> |
<div xmlns="http://www.w3.org/1999/xhtml"> |
<?=$item['description'];?> |
</div> |
</content> |
</entry> |
<?php endforeach; ?> |
<?php endif; ?> |
</feed> |
/branches/v1.1-helium/services/modules/0.1/syndication/SyndicationCommentaires.php |
---|
New file |
0,0 → 1,315 |
<?php |
/** |
* Service fournissant des informations concernant les commentaire de DEL au format RSS1, RSS2 ou ATOM. |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* |
* @author Aurélien 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> |
* @version $Id$ |
* @copyright 2010 |
*/ |
class SyndicationCommentaires { |
private $ressources = null; |
private $parametres = null; |
private $format = null; |
private $service = null; |
private $squelette = null; |
private $squelette_dossier = null; |
private $masque = array(); |
private $mappingFiltre = array(); |
private $conteneur = null; |
private $gestionBdd = null; |
private $navigation = null; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_syndication_commentaires.ini'); |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->navigation = $conteneur->getNavigation(); |
} |
public function consulter($params = array()) { |
$this->verifierConfiguration(); |
if ($this->fluxAdminDemande()) { |
$this->demanderAutorisationAdmin(); |
} |
$donnees_brutes = $this->getDerniersCommentaires(); |
$commentaires_formates = $this->formaterPourRss($donnees_brutes) ; |
return $commentaires_formates; |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
if (empty($this->mappingFiltre)) { |
$erreurs[] = 'Le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide.'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Verifier si le flux admin est demande |
*/ |
private function fluxAdminDemande() { |
return $this->conteneur->getParametre('admin') != null && $this->conteneur->getParametre('admin') == 1; |
} |
private function demanderAutorisationAdmin() { |
$verification = new ControleAcces($this->conteneur); |
$verification->demanderAuthentificationAdmin(); |
} |
private function formaterPourRss($elements) { |
$donnees = $this->construireDonneesCommunesAuFlux($elements); |
foreach ($elements as $element) { |
$identifiants[$element['id_commentaire']] = $element['id_commentaire']; |
} |
foreach ($elements as $element) { |
$donnees['items'][] = $this->construireDonneesCommunesAuxItems($element); |
} |
return $donnees; |
} |
private function construireDonneesCommunesAuFlux($infos) { |
$donnees = array(); |
$donnees['guid'] = htmlspecialchars($this->creerUrlService()); |
$donnees['titre'] = 'identiPlante : commentaires et propositions'; |
$donnees['description'] = 'Ce flux regroupe les dernières déterminations et commentaires rédigés dans l\'application identiPlante'; |
$donnees['lien_service'] = htmlspecialchars($this->creerUrlService()); |
$donnees['lien_del'] = $this->conteneur->getParametre('delAppliLien'); |
$donnees['editeur'] = $this->conteneur->getParametre('editeur'); |
$derniere_info_en_date = reset($infos); |
$date_modification_timestamp = $this->convertirDateHeureMysqlEnTimestamp($derniere_info_en_date['date']); |
$donnees['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$donnees['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$donnees['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$donnees['annee_courante'] = date('Y'); |
$donnees['generateur'] = 'DEL - SyndicationCommentaire'; |
$donnees['generateur_version'] = (preg_match('/([0-9]+)/', '$Revision$', $match)) ? $match[1] : '0'; |
return $donnees; |
} |
private function creerUrlService() { |
$url_service = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; |
return $url_service; |
} |
private function construireDonneesCommunesAuxItems($info) { |
$item = array(); |
$date_modification_timestamp = $this->convertirDateHeureMysqlEnTimestamp($info['date']); |
$item['date_maj_simple'] = strftime('%A %d %B %Y à %H:%M', $date_modification_timestamp); |
$item['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$item['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$item['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$item['titre'] = $this->creerTitre($info); |
$item['guid'] = $this->creerGuidItem($info); |
$item['lien'] = $this->creerLienItem($info); |
$item['categorie'] = $this->creerCategorie($item); |
$item['description'] = $this->creerDescription($info, $item); |
$item['description_encodee'] = htmlspecialchars($this->creerDescription($info, $item)); |
$item['modifier_par'] = $this->creerAuteur($info); |
return $item; |
} |
protected function convertirDateHeureMysqlEnTimestamp($date_heure_mysql){ |
$timestamp = 0; |
// Le date de 1970-01-01 pose problème dans certains lecteur de Flux, on met donc la date de création de Tela |
$date_heure_mysql = ($date_heure_mysql == '0000-00-00 00:00:00') ? '1999-12-14 00:00:00' : $date_heure_mysql; |
if ($date_heure_mysql != '0000-00-00 00:00:00') { |
$val = explode(' ', $date_heure_mysql); |
$date = explode('-', $val[0]); |
$heure = explode(':', $val[1]); |
$timestamp = mktime((int) $heure[0], (int) $heure[1], (int) $heure[2], (int) $date[1], (int) $date[2], (int) $date[0]); |
} |
return $timestamp; |
} |
private function creerTitre($element) { |
$nomPropose = htmlspecialchars($element['nom_sel']); |
$intitule = ($element['nom_sel'] != '') ? "Proposition $nomPropose" : 'Commentaire'; |
$auteur = htmlspecialchars($this->creerAuteur($element)); |
$nomSelActuel = htmlspecialchars($element['dob_nom_sel']); |
$zoneGeo = htmlspecialchars((($element['dob_zone_geo'] != '') ? $element['dob_zone_geo'] : '?')); |
$dateObs = htmlspecialchars(strftime('%d %B %Y', strtotime($element['dob_date_observation']))); |
$titre = "$intitule par $auteur pour $nomSelActuel à $zoneGeo le $dateObs"; |
return $titre; |
} |
private function creerAuteur($info) { |
$auteur = 'Anonyme'; |
if ($info['utilisateur_prenom'] != '' && $info['utilisateur_nom'] != '') { |
$auteur = $info['utilisateur_prenom'].' '.$info['utilisateur_nom']; |
} |
return $auteur; |
} |
private function creerGuidItem($element) { |
$guid = sprintf($this->conteneur->getParametre('guidObsTpl'), $element['id_commentaire']); |
return $guid; |
} |
private function creerLienItem($element) { |
$lien = sprintf($this->conteneur->getParametre('delFicheObsTpl'), $element['dob_id_observation']); |
return $lien; |
} |
private function creerCategorie($element) { |
$categorie = 'Commentaires'; |
$categorie = htmlentities($categorie); |
return $categorie; |
} |
private function creerDescription($donnees, $item) { |
$idCommentaire = $donnees['id_commentaire']; |
$idObs = $donnees['dob_id_observation']; |
$nomPropose = ($donnees['nom_sel'] != '') ? htmlspecialchars($donnees['nom_sel']) : ''; |
$dateCommentaire = htmlspecialchars(strftime('%A %d %B %Y à %H:%M', $this->convertirDateHeureMysqlEnTimestamp($donnees['date']))); |
$nomSelActuel = htmlspecialchars($donnees['dob_nom_sel']); |
$etreProposition = ($nomPropose != '') ? true : false; |
$intitule = ($etreProposition) ? 'Proposition' : 'Commentaire'; |
$txt = ($donnees['texte'] != '') ? htmlspecialchars($donnees['texte']) : ''; |
$auteur = htmlspecialchars($this->creerAuteur($donnees)). |
($this->fluxAdminDemande() ? ' ('.$donnees['utilisateur_courriel'].')' : ''); |
$lieuObs = htmlspecialchars((($donnees['dob_zone_geo'] != '') ? $donnees['dob_zone_geo'] : '?')); |
$dateObs = htmlspecialchars(str_replace(' 00:00:00', '', $donnees['dob_date_observation'])); |
$observateur = htmlspecialchars($this->creerObservateur($donnees)); |
$contenuCommentaire = ''; |
if ($etreProposition) { |
$contenuCommentaire = |
'<li><span class="champ">'."Nom proposé :</span> <em>$nomPropose</em></li>". |
((!empty($txt)) ? '<li><span class="champ">'."Argumentaire :</span> $txt</li>" : ''). |
'<li><span class="champ">'."Auteur de la proposition :</span> $auteur</li>". |
'<li><span class="champ">'."Proposé le :</span> $dateCommentaire</li>"; |
} else { |
$contenuCommentaire = |
'<li><span class="champ">'."Commentaire #$idCommentaire :</span> <pre>$txt</pre></li>". |
'<li><span class="champ">'."Auteur du commentaire :</span> $auteur</li>". |
'<li><span class="champ">'."Commenté le :</span> $dateCommentaire</li>"; |
} |
$description = '<style>.champ{color:grey} .gauche{float:left;padding:0 20px 0 0;} ul{list-style-type:none;padding:0;}</style>'. |
'<h2>'."$intitule identiPlante #$idCommentaire pour l'observation #$idObs".'</h2>'. |
'<div class="gauche">'. |
" <h3>Observation #$idObs</h3>". |
' <ul>'. |
' <li><span class="champ">'."Nom saisi actuel :</span> <em>$nomSelActuel</em></li>". |
' <li><span class="champ">'."Lieu :</span> $lieuObs</li>". |
' <li><span class="champ">'."Date :</span> $dateObs</li>". |
' <li><span class="champ">'."Auteur :</span> $observateur</li>". |
' </ul>'. |
'</div>'. |
'<div class="gauche">'. |
" <h3>$intitule #$idCommentaire</h3>". |
" <ul>$contenuCommentaire</ul>". |
'</div>'; |
return $description; |
} |
private function creerObservateur($info) { |
$observateur = 'Anonyme'; |
if ($info['observateur_prenom'] != '' && $info['observateur_nom'] != '') { |
$observateur = $info['observateur_prenom'].' '.$info['observateur_nom']; |
} |
return $observateur; |
} |
private function getDerniersCommentaires() { |
$requete = 'SELECT DISTINCT dc.*, '. |
' dob.id_observation AS dob_id_observation, dob.ce_zone_geo AS dob_ce_zone_geo, '. |
' dob.zone_geo AS dob_zone_geo, dob.date_observation AS dob_date_observation, dob.nom_sel AS dob_nom_sel, '. |
' duo.prenom AS observateur_prenom, duo.nom AS observateur_nom, duo.courriel AS observateur_courriel '. |
'FROM del_commentaire AS dc '. |
' INNER JOIN del_observation AS dob '. |
' ON dob.id_observation = dc.ce_observation '. |
' LEFT JOIN del_utilisateur AS duo '. |
' ON dob.ce_utilisateur = duo.id_utilisateur '. |
'WHERE proposition_initiale != 1 '. |
$this->chargerClauseWhere().' '. |
'ORDER BY dc.date DESC '. |
'LIMIT '.$this->navigation->getDepart().','.$this->navigation->getLimite().' '; |
$elements = $this->gestionBdd->getBdd()->recupererTous($requete); |
return $elements; |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach ($tableauMasque as $idMasque => $valeurMasque) { |
$idMasque = str_replace('masque.', '', $idMasque); |
$champ = $this->mappingFiltre[$idMasque]; |
$valeurMasquePattern = $this->gestionBdd->getBdd()->proteger($valeurMasque.'%'); |
$valeurMasqueProtegee = $this->gestionBdd->getBdd()->proteger($valeurMasque); |
switch ($idMasque) { |
case 'espece': |
$where[] = " dob.$champ LIKE $valeurMasquePattern OR dc.$champ LIKE $valeurMasquePattern "; |
break; |
case 'auteur': |
$where[] = $this->creerFiltreAuteur($valeurMasque); |
break; |
default: |
$where[] = " $champ = $valeurMasqueProtegee "; |
} |
} |
} |
$whereSql = ''; |
if (!empty($where)) { |
$whereSql = ' AND '.implode('AND', $where); |
} |
return $whereSql; |
} |
private function creerFiltreAuteur($auteurId) { |
$whereAuteur = ''; |
if (is_numeric($auteurId)) { |
$whereAuteur = " dc.ce_utilisateur = $auteurId "; |
} else { |
$auteurIdMotif = $this->gestionBdd->getBdd()->proteger($auteurId.'%'); |
if (strpos($auteurId, '@') === false) { |
$tableauNomPrenom = explode(' ', $auteurId, 2); |
if (count($tableauNomPrenom) == 2) { |
// on teste potentiellement un nom prenom ou bien un prénom nom |
$nomMotif = $this->gestionBdd->getBdd()->proteger($tableauNomPrenom[0].'%'); |
$prenomMotif = $this->gestionBdd->getBdd()->proteger($tableauNomPrenom[1].'%'); |
$whereAuteur = ' ('. |
"(dc.utilisateur_nom LIKE $nomMotif AND dc.utilisateur_prenom LIKE $prenomMotif) ". |
'OR '. |
"(dc.utilisateur_nom LIKE $nomMotif AND dc.utilisateur_prenom LIKE $prenomMotif) ". |
') '; |
} else { |
$whereAuteur = "(dc.utilisateur_nom LIKE $auteurIdMotif OR dc.utilisateur_prenom LIKE $auteurIdMotif) "; |
} |
} else { |
$whereAuteur = " dob.utilisateur_courriel LIKE $auteurIdMotif "; |
} |
} |
return $whereAuteur; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/syndication/SyndicationTagsParProtocole.php |
---|
New file |
0,0 → 1,318 |
<?php |
/** |
* Service fournissant des informations concernant les tags sur les images de DEL en fonction d'un protocole |
* au format RSS1, RSS2 ou ATOM. |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* |
* @author Grégoire DUCHE <gregoire@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 $Id$ |
* @copyright 2010 |
*/ |
class SyndicationTagsParProtocole { |
/** |
* Paramètres du service |
* */ |
private $ressources = null; |
private $parametres = null; |
private $format = null; |
private $service = null; |
private $squelette = null; |
private $squelette_dossier = null; |
private $masque = array(); |
private $mappingFiltre = array(); |
private $conteneur = null; |
private $gestionBdd = null; |
private $navigation = null; |
private $type_rss = null; |
/** |
* Constructeur |
* Initialiser les configurations |
* */ |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_syndication_tagsparprotocole.ini'); |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->navigation = $conteneur->getNavigation(); |
} |
/** |
* Consulter |
* Méthode par défaut pour récupérer l'ensemble des tags. |
* Vérifie la configuration et retourne les derniers tags formatés |
* */ |
public function consulter($params = array()) { |
$this->verifierConfiguration(); |
$this->type_rss = $params[1]; |
if ($this->fluxAdminDemande()) { |
$this->demanderAutorisationAdmin(); |
} |
$donnees_brutes = $this->getDerniersVotesImage(); |
$commentaires_formates = $this->formaterPourRss($donnees_brutes) ; |
return $commentaires_formates; |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
if (empty($this->mappingFiltre)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide ;'; |
} else { |
$champsMappingFiltre = array('image', 'protocole'); |
foreach ($champsMappingFiltre as $champ) { |
if (!isset($this->mappingFiltre[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour le commentaire est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Verifier si le flux admin est demandé |
*/ |
private function fluxAdminDemande() { |
return $this->conteneur->getParametre('admin') != null && $this->conteneur->getParametre('admin') == 1; |
} |
/** |
* Si le flux est un flux admin, demander un mot de passe |
* */ |
private function demanderAutorisationAdmin() { |
$verification = new ControleAcces($this->conteneur); |
$verification->demanderAuthentificationAdmin(); |
} |
/** |
* Formater les données pour mettre en page le RSS |
* */ |
private function formaterPourRss($elements) { |
$donnees = $this->construireDonneesCommunesAuFlux($elements); |
foreach ($elements as $element) { |
$identifiants[$element['id_tag']] = $element['id_tag']; |
} |
foreach ($elements as $element) { |
$donnees['items'][] = $this->construireDonneesCommunesAuxItems($element); |
} |
return $donnees; |
} |
/** |
* Générer les métadonnées du flux (titre, dates, editeur etc.) |
* */ |
private function construireDonneesCommunesAuFlux($infos) { |
$donnees = array(); |
$donnees['guid'] = htmlspecialchars($this->creerUrlService()); |
$donnees['titre'] = 'pictoFlora : tags'; |
$donnees['description'] = 'Ce flux regroupe les derniers tags des images de pictoFlora'; |
$donnees['lien_service'] = htmlspecialchars($this->creerUrlService()); |
$donnees['lien_del'] = $this->conteneur->getParametre('pictoAppliLien'); |
$donnees['editeur'] = $this->conteneur->getParametre('editeur'); |
$derniere_info_en_date = reset($infos); |
$date_modification_timestamp = strtotime($derniere_info_en_date['date']); |
$donnees['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$donnees['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$donnees['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$donnees['annee_courante'] = date('Y'); |
$donnees['generateur'] = 'DEL - SyndicationCommentaire'; |
$donnees['generateur_version'] = (preg_match('/([0-9]+)/', '$Revision$', $match)) ? $match[1] : '0'; |
return $donnees; |
} |
/** |
* Générer le lien du flux RSS |
* */ |
private function creerUrlService() { |
$url_service = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; |
return $url_service; |
} |
/** |
* Générer les données communes & spécifiques à chaque item |
* */ |
private function construireDonneesCommunesAuxItems($info) { |
$item = array(); |
$date_modification_timestamp = strtotime($info['date']); |
$item['date_maj_simple'] = strftime('%A %d %B %Y à %H:%M', $date_modification_timestamp); |
$item['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$item['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$item['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$item['titre'] = $this->creerTitre($info); |
$item['guid'] = $this->creerGuidItem($info); |
$item['lien'] = $this->creerLienItem($info); |
$item['categorie'] = $this->creerCategorie($item); |
$item['description'] = $this->creerDescription($info, $item); |
$item['description_encodee'] = htmlspecialchars($this->creerDescription($info, $item)); |
$item['modifier_par'] = $this->formaterNomTagueur($info); |
return $item; |
} |
private function creerCategorie($element) { |
$categorie = 'Tag protocole'; |
$categorie = htmlentities($categorie); |
return $categorie; |
} |
private function creerGuidItem($element) { |
$guid = sprintf($this->conteneur->getParametre('tagParProtocole'), $element['id_tag']); |
return $guid; |
} |
private function creerLienItem($element) { |
// TODO : ajouter un lien vers la plateforme validation de picto lorsqu'elle sera dispo |
$lien = $this->conteneur->getParametre('pictofloraFicheObsTpl'); |
return $lien; |
} |
private function creerTitre($element) { |
$tag = $element['tag']; |
$nomSel = htmlspecialchars($element['nom_sel']); |
$tagueur = htmlspecialchars($this->formaterNomTagueur($element)); |
$auteurImg = $this->formaterNomAuteurImg($element); |
$titre = "Tag «{$tag}» par $tagueur pour $nomSel de $auteurImg"; |
return $titre; |
} |
private function creerDescription($donnees, $item) { |
$idTag = htmlspecialchars($donnees['id_tag']); |
$idObs = htmlspecialchars($donnees['id_observation']); |
$idImg = htmlspecialchars($donnees['id_image']); |
$urlImg = $this->getUrlImage($donnees['id_image']); |
$miniatureUrl = $this->getUrlImage($donnees['id_image'], 'CRS'); |
$nomSelActuel = htmlspecialchars($donnees['nom_sel']); |
$dateObs = htmlspecialchars(str_replace(' 00:00:00', '', $donnees['date_observation'])); |
$lieuObs = htmlspecialchars($donnees['zone_geo']); |
$tag = htmlspecialchars($donnees['tag']); |
$dateTag = htmlspecialchars(strftime('%A %d %B %Y à %H:%M', strtotime($donnees['date']))); |
$auteurImg = htmlspecialchars($this->creerAuteurImg($donnees)); |
$tagueur = htmlspecialchars($this->creerTagueur($donnees)); |
$description = '<style>.champ{color:grey} .gauche{float:left;padding:0 20px 0 0;} ul{list-style-type:none;padding:0;}</style>'. |
'<h2>'."Tag pictoFlora #$idTag pour l'image #$idImg de l'observation #$idObs".'</h2>'. |
'<div class="gauche">'. |
' <a href="'.$urlImg.'">'. |
' <img src="'.$miniatureUrl.'" alt="Img #'.$idImg.'"/>'. |
' </a>'. |
'</div>'. |
'<div class="gauche">'. |
" <h3>Image #$idImg de l'observation #$idObs</h3>". |
' <ul>'. |
' <li><span class="champ">'."Auteur de l'image :</span> $auteurImg</li>". |
' <li><span class="champ">'."Nom saisi actuel :</span> <em>$nomSelActuel</em></li>". |
' <li><span class="champ">'."Lieu :</span> $lieuObs</li>". |
' <li><span class="champ">'."Date :</span> $dateObs</li>". |
' </ul>'. |
'</div>'. |
'<div class="gauche">'. |
" <h3>Tag #$idTag</h3>". |
' <ul>'. |
' <li><span class="champ">'."Tag :</span> <strong>$tag</strong></li>". |
' <li><span class="champ">'."Auteur :</span> $tagueur</li>". |
' <li><span class="champ">'."Taguée le :</span> $dateTag</li>". |
' </ul>'. |
'</div>'; |
return $description; |
} |
private function getUrlImage($id, $format = 'L') { |
$url_tpl = $this->conteneur->getParametre('celImgUrlTpl'); |
$id = sprintf('%09s', $id).$format; |
$url = sprintf($url_tpl, $id); |
return $url; |
} |
private function creerAuteurImg($info) { |
$auteur = $this->formaterNomAuteurImg($info). |
($this->fluxAdminDemande() ? ' ('.$info['auteur_courriel'].')' : ''); |
return $auteur; |
} |
private function formaterNomAuteurImg($info) { |
$auteur = 'Anonyme'; |
if ($info['auteur_prenom'] != '' && $info['auteur_nom'] != '') { |
$auteur = $info['auteur_prenom'].' '.$info['auteur_nom']; |
} |
return $auteur; |
} |
private function creerTagueur($info) { |
$tagueur = $this->formaterNomTagueur($info). |
($this->fluxAdminDemande() ? ' ('.$info['tagueur_courriel'].')' : ''); |
return $tagueur; |
} |
private function formaterNomTagueur($info) { |
$tagueur = 'Anonyme'; |
if ($info['tagueur_prenom'] != '' && $info['tagueur_nom'] != '') { |
$tagueur = $info['tagueur_prenom'].' '.$info['tagueur_nom']; |
} |
return $tagueur; |
} |
/** |
* Retrouver les derniers votes image |
* */ |
private function getDerniersVotesImage() { |
$requete = 'SELECT DISTINCT id_tag, tag, date, '. |
' do.id_observation, do.nom_sel, do.zone_geo, do.date_observation, doi.id_image, '. |
' duo.prenom AS auteur_prenom, duo.nom AS auteur_nom, duo.courriel AS auteur_courriel, '. |
' du.prenom AS tagueur_prenom, du.nom AS tagueur_nom, du.courriel AS tagueur_courriel '. |
'FROM del_image_tag AS dit '. |
' INNER JOIN del_obs_image AS doi '. |
' ON ce_image = id_image '. |
' INNER JOIN del_observation AS do '. |
' ON doi.id_observation = do.id_observation '. |
' LEFT JOIN del_utilisateur AS duo '. |
' ON do.ce_utilisateur = duo.id_utilisateur '. |
' LEFT JOIN del_utilisateur AS du '. |
' ON if((CHAR_LENGTH(dit.ce_utilisateur) <> 32),CAST(dit.ce_utilisateur AS unsigned),0) '. |
' = du.id_utilisateur '. |
'WHERE actif = 1 '. |
$this->chargerClauseWhere().' '. |
'ORDER BY date DESC '. |
'LIMIT '.$this->navigation->getDepart().','.$this->navigation->getLimite(); |
$elements = $this->gestionBdd->getBdd()->recupererTous($requete); |
return $elements; |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach ($tableauMasque as $idMasque => $valeurMasque) { |
$idMasque = str_replace('masque.', '', $idMasque); |
$champMasque = $this->mappingFiltre[$idMasque]; |
$masqueMotif = $this->gestionBdd->getBdd()->proteger($valeurMasque); |
switch ($idMasque) { |
case 'image': |
//TODO : ajouter le protocole ? case 'protocole': |
default: |
$where[] = " $champMasque = $masqueMotif "; |
} |
} |
} |
$conditionsTxt = (!empty($where)) ? ' AND '.implode('AND', $where) : ''; |
return $conditionsTxt; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/syndication/SyndicationVotesParProtocole.php |
---|
New file |
0,0 → 1,341 |
<?php |
/** |
* Service fournissant des informations concernant les votes sur les images de DEL en fonction d'un protocole |
* au format RSS1, RSS2 ou ATOM. |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* |
* @author Grégoire DUCHE <gregoire@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 $Id$ |
* @copyright 2010 |
*/ |
class SyndicationVotesParProtocole { |
/** |
* Paramètres du service |
* */ |
private $ressources = null; |
private $parametres = null; |
private $format = null; |
private $service = null; |
private $squelette = null; |
private $squelette_dossier = null; |
private $masque = array(); |
private $mappingFiltre = array(); |
private $conteneur = null; |
private $gestionBdd = null; |
private $navigation = null; |
private $type_rss = null; |
/** |
* Constructeur |
* Initialiser les configurations |
* */ |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_syndication_votesparprotocole.ini'); |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->navigation = $conteneur->getNavigation(); |
} |
/** |
* Consulter |
* Méthode par défaut pour récupérer l'ensemble des votes. |
* Vérifie la configuration et retourne les derniers votes formatés |
* */ |
public function consulter($params = array()) { |
$this->verifierConfiguration(); |
$this->type_rss = $params[1]; |
if ($this->fluxAdminDemande()) { |
$this->demanderAutorisationAdmin(); |
} |
$donnees_brutes = $this->getDerniersVotesImage(); |
$commentaires_formates = $this->formaterPourRss($donnees_brutes) ; |
return $commentaires_formates; |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
if (empty($this->mappingFiltre)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide ;'; |
} else { |
$champsMappingFiltre = array('image', 'protocole'); |
foreach ($champsMappingFiltre as $champ) { |
if (!isset($this->mappingFiltre[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour le commentaire est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Verifier si le flux admin est demandé |
*/ |
private function fluxAdminDemande() { |
return $this->conteneur->getParametre('admin') != null && $this->conteneur->getParametre('admin') == 1; |
} |
/** |
* Si le flux est un flux admin, demander un mot de passe |
* */ |
private function demanderAutorisationAdmin() { |
$verification = new ControleAcces($this->conteneur); |
$verification->demanderAuthentificationAdmin(); |
} |
/** |
* Formater les données pour mettre en page le RSS |
* */ |
private function formaterPourRss($elements) { |
$donnees = $this->construireDonneesCommunesAuFlux($elements); |
foreach ($elements as $element) { |
$identifiants[$element['id_vote']] = $element['id_vote']; |
} |
foreach ($elements as $element) { |
$donnees['items'][] = $this->construireDonneesCommunesAuxItems($element); |
} |
return $donnees; |
} |
/** |
* Générer les métadonnées du flux (titre, dates, editeur etc.) |
* */ |
private function construireDonneesCommunesAuFlux($infos) { |
$donnees = array(); |
$donnees['guid'] = htmlspecialchars($this->creerUrlService()); |
$donnees['titre'] = 'pictoFlora : votes'; |
$donnees['description'] = 'Ce flux regroupe les derniers votes sur les images de pictoFlora'; |
$donnees['lien_service'] = htmlspecialchars($this->creerUrlService()); |
$donnees['lien_del'] = $this->conteneur->getParametre('pictoAppliLien'); |
$donnees['editeur'] = $this->conteneur->getParametre('editeur'); |
$derniere_info_en_date = reset($infos); |
$date_modification_timestamp = strtotime($derniere_info_en_date['date_vote']); |
$donnees['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$donnees['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$donnees['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$donnees['annee_courante'] = date('Y'); |
$donnees['generateur'] = 'DEL - SyndicationCommentaire'; |
$donnees['generateur_version'] = (preg_match('/([0-9]+)/', '$Revision$', $match)) ? $match[1] : '0'; |
return $donnees; |
} |
/** |
* Générer le lien du flux RSS |
* */ |
private function creerUrlService() { |
$url_service = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; |
return $url_service; |
} |
/** |
* Générer les données communes & spécifiques à chaque item |
* */ |
private function construireDonneesCommunesAuxItems($info) { |
$item = array(); |
$date_modification_timestamp = strtotime($info['date_vote']); |
$item['date_maj_simple'] = strftime('%A %d %B %Y à %H:%M', $date_modification_timestamp); |
$item['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$item['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$item['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$item['titre'] = $this->creerTitre($info); |
$item['guid'] = $this->creerGuidItem($info); |
$item['lien'] = $this->creerLienItem($info); |
$item['categorie'] = $this->creerCategorie($item); |
$item['description'] = $this->creerDescription($info, $item); |
$item['description_encodee'] = htmlspecialchars($this->creerDescription($info, $item)); |
$item['modifier_par'] = $this->creerVotant($info); |
return $item; |
} |
private function creerCategorie($element) { |
$categorie = 'Vote protocole'; |
$categorie = htmlentities($categorie); |
return $categorie; |
} |
private function creerGuidItem($element) { |
$guid = sprintf($this->conteneur->getParametre('voteParProtocole'), $element['id_vote']); |
return $guid; |
} |
private function creerLienItem($element) { |
$lien = sprintf($this->conteneur->getParametre('pictofloraFicheObsTpl'), $element['id_observation']); |
return $lien; |
} |
private function creerTitre($element) { |
$noteVote = $element['valeur']; |
$nomSci = htmlspecialchars($element['nom_sel']); |
$votant = htmlspecialchars($this->creerVotant($element)); |
$observateur = htmlspecialchars($this->creerObservateur($element)); |
$titre = "Vote $noteVote par $votant pour $nomSci de $observateur"; |
return $titre; |
} |
private function creerDescription($donnees, $item) { |
$idVote = htmlspecialchars($donnees['id_vote']); |
$idObs = htmlspecialchars($donnees['id_observation']); |
$idImg = htmlspecialchars($donnees['ce_image']); |
$urlImg = $this->getUrlImage($donnees['ce_image']); |
$miniatureUrl = $this->getUrlImage($donnees['ce_image'], 'CRS'); |
$nomSelActuel = htmlspecialchars($donnees['nom_sel']); |
$dateObs = htmlspecialchars(str_replace(' 00:00:00', '', $donnees['date_observation'])); |
$lieuObs = htmlspecialchars($donnees['zone_geo']); |
$protocole = htmlspecialchars($donnees['intitule']); |
$votant = htmlspecialchars($this->creerVotant($donnees)); |
$dateVote = htmlspecialchars(strftime('%A %d %B %Y à %H:%M', strtotime($donnees['date_vote']))); |
$observateur = htmlspecialchars($this->creerObservateur($donnees)); |
$description = '<style>.champ{color:grey} .gauche{float:left;padding:0 20px 0 0;} ul{list-style-type:none;padding:0;}</style>'. |
'<h2>'."Vote pictoFlora #$idVote pour l'image #$idImg de l'observation #$idObs".'</h2>'. |
'<div class="gauche">'. |
' <a href="'.$urlImg.'">'. |
' <img src="'.$miniatureUrl.'" alt="Img #'.$idImg.'"/>'. |
' </a>'. |
'</div>'. |
'<div class="gauche">'. |
" <h3>Image #$idImg de l'observation #$idObs</h3>". |
' <ul>'. |
' <li><span class="champ">'."Auteur de l'image :</span> $observateur</li>". |
' <li><span class="champ">'."Nom saisi actuel :</span> <em>$nomSelActuel</em></li>". |
' <li><span class="champ">'."Lieu :</span> $lieuObs</li>". |
' <li><span class="champ">'."Date :</span> $dateObs</li>". |
' </ul>'. |
'</div>'. |
'<div class="gauche">'. |
" <h3>Vote #$idVote</h3>". |
' <ul>'. |
' <li><span class="champ">'."Protocole :</span> <strong>$protocole</strong></li>". |
' <li><span class="champ">'."Valeur :</span> <strong>{$donnees['valeur']}</strong>/5</li>". |
' <li><span class="champ">'."Votant :</span> $votant</li>". |
' <li><span class="champ">'."À voté le :</span> $dateVote</li>". |
' </ul>'. |
'</div>'; |
return $description; |
} |
private function getUrlImage($id, $format = 'L') { |
$url_tpl = $this->conteneur->getParametre('celImgUrlTpl'); |
$id = sprintf('%09s', $id).$format; |
$url = sprintf($url_tpl, $id); |
return $url; |
} |
private function creerVotant($info) { |
$votant = 'Anonyme'; |
if (isset($info['votant_prenom']) && isset($info['votant_nom'])) { |
$votant = $info['votant_prenom'].' '.$info['votant_nom']; |
} |
return $votant; |
} |
private function creerObservateur($info) { |
$observateur = 'Anonyme'; |
if ($info['observateur_prenom'] != '' && $info['observateur_nom'] != '') { |
$observateur = $info['observateur_prenom'].' '.$info['observateur_nom']; |
} |
return $observateur; |
} |
/** |
* Retrouver les derniers votes image |
* */ |
private function getDerniersVotesImage() { |
$requete = 'SELECT DISTINCT id_vote, ce_image, valeur, divo.date AS date_vote, '. |
' duo.prenom AS observateur_prenom, duo.nom AS observateur_nom, '. |
' duv.prenom AS votant_prenom, duv.nom AS votant_nom, '. |
' do.id_observation, do.nom_sel, do.zone_geo, do.date_observation, dip.intitule '. |
'FROM del_image_vote AS divo '. |
' INNER JOIN del_obs_image AS doi '. |
' ON divo.ce_image = doi.id_image '. |
' INNER JOIN del_observation AS do '. |
' ON do.id_observation = doi.id_observation '. |
' INNER JOIN del_image_protocole AS dip '. |
' ON ce_protocole = id_protocole '. |
' LEFT JOIN del_utilisateur AS duo '. |
' ON do.ce_utilisateur = duo.id_utilisateur '. |
' LEFT JOIN del_utilisateur AS duv '. |
' ON if((CHAR_LENGTH(divo.ce_utilisateur) <> 32),CAST(divo.ce_utilisateur AS unsigned),0) '. |
' = duv.id_utilisateur '. |
$this->chargerClauseWhere().' '. |
'ORDER BY divo.date DESC '. |
'LIMIT '.$this->navigation->getDepart().','.$this->navigation->getLimite(); |
$elements = $this->gestionBdd->getBdd()->recupererTous($requete); |
return $elements; |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach($tableauMasque as $idMasque => $valeurMasque) { |
$idMasque = str_replace('masque.', '', $idMasque); |
switch ($idMasque) { |
case 'image': |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->gestionBdd->getBdd()->proteger($valeurMasque); |
break; |
case 'protocole': |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->gestionBdd->getBdd()->proteger($valeurMasque).' '; |
break; |
default: |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->gestionBdd->getBdd()->proteger($valeurMasque); |
break; |
} |
} |
} |
if (!empty($where)) { |
return ' WHERE '.implode('AND', $where); |
} else { |
return; |
} |
} |
private function creerFiltreAuteur($valeurMasque) { |
$masque = ''; |
$auteurId = $valeurMasque; |
if (is_numeric($auteurId)) { |
$masque = ' dc.ce_utilisateur = '.$auteurId; |
} else { |
if (strpos($auteurId, '@') === false) { |
$tableauNomPrenom = explode(' ',$auteurId, 2); |
if(count($tableauNomPrenom) == 2) { |
// on teste potentiellement un nom prenom ou bien un prénom nom |
$masque = '('. |
'(dc.utilisateur_nom LIKE '.$this->gestionBdd->getBdd()->proteger($tableauNomPrenom[0].'%').' AND '. |
'dc.utilisateur_prenom LIKE '.$this->gestionBdd->getBdd()->proteger($tableauNomPrenom[1].'%').') OR '. |
'(dc.utilisateur_nom LIKE '.$this->gestionBdd->getBdd()->proteger($tableauNomPrenom[1].'%').' AND '. |
'dc.utilisateur_prenom LIKE '.$this->gestionBdd->getBdd()->proteger($tableauNomPrenom[0].'%').')'. |
')'; |
} else { |
$masque = '( |
(dc.utilisateur_nom LIKE '.$this->gestionBdd->getBdd()->proteger($auteurId.'%').' OR '. |
'dc.utilisateur_prenom LIKE '.$this->gestionBdd->getBdd()->proteger($auteurId.'%').')'. |
')'; |
} |
} else { |
$masque = " do.utilisateur_courriel LIKE ".$this->gestionBdd->getBdd()->proteger($valeurMasque.'%')." "; |
} |
} |
return $masque; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/determinations/ValiderDetermination.php |
---|
New file |
0,0 → 1,125 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service récupére un identifiant de proposition et appelle un service web externe |
* (du cel) afin de modifier le nom de l'observation associée par celui de la proposition |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Aurélien Peronnet <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2013, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id$ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class ValiderDetermination { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_determinations.ini'); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
public function modifier($ressources, $parametres) { |
$this->verifierParametres($ressources, $parametres); |
$id_proposition = $ressources[1]; |
$e = $this->modifierObservationParDetermination($id_proposition, $parametres['auteur.id']); |
if($e == 'ok' || $e == 'OK' || $e == 'Not Modified') { |
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_OK); |
return; |
} |
throw new Exception("error: Cel returned \"$e\"", RestServeur::HTTP_CODE_ERREUR); |
} |
public function verifierParametres($ressources, $parametres) { |
$erreurs = array(); |
if (!is_numeric($ressources[1])) { |
$erreurs[] = '- le paramètre indiquant l\'identifiant de la proposition doit être numérique ;'; |
} |
//Le paramètre auteur.id (id de l'auteur de la détermination) |
// est là pour éviter que le $_POST ne soit vide |
if (!isset($parametres['auteur.id'])) { |
$erreurs[] = '- paramètre "auteur.id" manquant ;'; |
} |
if ($erreurs) { |
throw new Exception("Erreur lors de la configuration :\n" . implode("\n", $erreurs), |
RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/* |
* 1) récupère l'observation, autrement échec |
* 2) récupère et l'auteur officiel et valide l'authentification (match sur $_POST['auteur.id'] et $_SESSION), autrement échec |
* 3) prépare les nouvelles valeurs à mettre à jour dans cel_obs depuis del_commentaire |
* 4) effectue la mise à jour |
* 5) si tout s'est passé comme convenu, marque la proposition comme "retenue" |
*/ |
private function modifierObservationParDetermination($id_proposition, $auteurId) { |
$champs_a_modifier = array('nom_sel', 'nom_sel_nn', 'nom_ret', 'nom_ret_nn', 'nom_referentiel'); |
// obtenirInformationDetermination() |
// TODO: else { LIMIT 1 ? } |
$proposition = $this->bdd->recuperer(sprintf('SELECT ce_observation, id_commentaire, %s FROM del_commentaire WHERE id_commentaire = %d AND %s', |
implode(',', $champs_a_modifier), |
intval($id_proposition), |
$auteurId ? 'ce_utilisateur = ' . $this->bdd->proteger($auteurId) : 1)); |
if(! $proposition) { |
throw new Exception("Cette proposition est invalide.", RestServeur::HTTP_CODE_ERREUR); |
} |
$obsId = $proposition['ce_observation']; |
// obtenirInformationsObservation() |
$realAuteurId = $this->bdd->recuperer(sprintf('SELECT ce_utilisateur FROM del_observation WHERE id_observation = %d', |
intval($obsId))); |
$realAuteurId = $realAuteurId['ce_utilisateur']; // XXX: PHP-5.3 |
if(! $this->validationReqOriginMatchObsAuthor($realAuteurId)) { |
throw new Exception("Seul l'utilisateur ayant saisi l'observation peut la valider : veuillez vous identifier.\n", |
RestServeur::HTTP_CODE_ERREUR); |
} |
$parametres_formates = array_intersect_key($proposition, |
array_flip($champs_a_modifier)); |
$parametres_formates = array_merge($parametres_formates, |
array('id_observation' => $obsId, |
'ce_utilisateur' => $realAuteurId, |
// on change la "certitude" de l'observation correspondante |
'certitude' => 'Certaine', |
'obsKeywordDelete' => 'adeterminer')); |
$ret = $this->conteneur->getRestClient()->modifier($this->conteneur->getParametre('url_service_validation_base') . $obsId, |
$parametres_formates); |
// cf cel/jrest/services/CelValidationObservation.php::updateElement() |
// TODO: check sur HTTP code == 200, plutôt que sur texte |
if($ret == 'ok' || $ret == 'OK') { |
// remet à 0 le status "proposition_retenue" pour toutes les propositions faites sur cette |
// observation à l'exception de celle désormais validée |
$this->bdd->requeter(sprintf('UPDATE del_commentaire SET proposition_retenue = IF(id_commentaire = %d, 1, 0)' . |
' WHERE ce_observation = %d -- %s', |
$proposition['id_commentaire'], $obsId, __FILE__ . ':' . __LINE__)); |
} |
return $ret; |
} |
private function validationReqOriginMatchObsAuthor($ce_utilisateur) { |
$controle_utilisateur = new ControleAcces($this->conteneur); |
$utilisateur_connecte = $controle_utilisateur->getInfosUtilisateurConnecte(); |
return $ce_utilisateur == $utilisateur_connecte['id_utilisateur']; |
} |
} |
/branches/v1.1-helium/services/modules/0.1/determinations/ListeImagesDeterminationsProbables.php |
---|
New file |
0,0 → 1,312 |
<?php |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à la détermination la plus probable |
* avec la possibilité de ne renvoyer que les images les mieux notées pour un protocole donné |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @author Aurélien Peronnet <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @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 ListeImagesDeterminationsProbables { |
private $indexImagesIds = array(); |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $tri = 'date_transmission'; |
private $directionTri = 'desc'; |
private $protocole_defaut = null; |
private $valeur_vote_min_defaut = null; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_determinations.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['masque.protocole'])) { |
$this->parametres['masque.protocole'] = $this->protocole_defaut; |
} |
if(!isset($parametres['masque.valeur_vote_min'])) { |
$this->parametres['masque.valeur_vote_min'] = $this->valeur_vote_min_defaut; |
} |
// Gestion des configuration du script |
// configurer(); |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingObservation = $this->conteneur->getParametre('mapping_observation'); |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
// verifierConfiguration() |
if(! $this->conteneur->getParametre('protocoles_possibles')) { |
throw new Exception("Erreur lors de la configuration : \n- le fichier de configuration ne contient pas le parametre protocoles_possibles ou celui-ci est vide ;", RestServeur::HTTP_CODE_ERREUR); |
} |
$this->verifierParametres(); |
// initialiserTri() |
$this->tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : $this->tri; |
$this->directionTri = isset($this->parametres['ordre']) ? $this->parametres['ordre'] : $this->directionTri; |
// 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']; |
$images = $this->chargerImage($liaisons); |
$images = $this->chargerPropositionPlusProbable($images); |
} |
$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); |
return $resultat; |
} |
private function verifierParametres() { |
$erreurs = array(); |
$tableau_protocoles = explode(',',$this->conteneur->getParametre('protocoles_possibles')); |
if(isset($this->parametres['masque.protocole']) && |
(!is_numeric($this->parametres['masque.protocole']) || |
!in_array($this->parametres['masque.protocole'], $tableau_protocoles) |
)) { |
$erreurs[] = '- la valeur pour le protocole doit être un entier compris dans les numéros de protocole existants '.$this->conteneur->getParametre('protocoles_possibles'); |
} |
if(isset($this->parametres['masque.valeur_min_vote']) && |
(!is_numeric($this->parametres['masque.valeur_min_vote']) || |
$this->parametres['masque.valeur_min_vote'] < 0 || |
$this->parametres['masque.valeur_min_vote'] > 5 |
)) { |
$erreurs[] = '- la valeur minimum de valeur des votes doit être un entier compris entre 0 et 5 '; |
} |
if (!empty($erreurs)) { |
throw new Exception("Erreur lors de l\'analyse des parametres du service : \n" . implode("\n", $erreurs), RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES IMAGES |
--------------------------------------------------------------------------------*/ |
private function chargerLiaisons() { |
$champs = array('di.id_observation as id_observation', 'nom_referentiel', 'nom_ret', 'nom_ret_nn', 'nt', 'famille', 'ce_zone_geo', 'zone_geo', |
'lieudit', 'station', 'milieu', 'date_observation', 'di.mots_cles_texte as mots_cles_texte', 'di.commentaire as commentaire', |
'di.i_mots_cles_texte AS mots_cles_texte_image ', 'date_transmission', 'di.id_image as id_image', 'di.ce_utilisateur as ce_utilisateur', |
'prenom', 'nom', 'courriel', 'di.nom_utilisateur', 'di.prenom_utilisateur', 'di.courriel_utilisateur', 'nom_original'); |
$where = array(); |
if(@$this->parametres['masque.protocole']) $where[] = 'ds.ce_protocole = ' . intval($this->parametres['masque.protocole']); |
if(@intval($this->parametres['masque.valeur_vote_min'])) $where[] = 'moyenne >= ' . intval($this->parametres['masque.valeur_vote_min']); |
$limite = @min(intval($this->parametres['navigation.limite']), 1000); |
$limite = $limite ? $limite : 10; // 0 => 10 |
$requeteLiaisons = sprintf( |
'SELECT SQL_CALC_FOUND_ROWS %s ce_protocole, moyenne, nb_votes, nb_tags' |
// IF(LENGTH()) workaround pour la jointure sur tela_annuaire depuis un hash md5 casté |
. ' FROM v_del_image di LEFT JOIN del_utilisateur du ON du.id_utilisateur = IF(LENGTH(di.ce_utilisateur) > 5, 0, di.ce_utilisateur)' |
. ' LEFT JOIN del_image_stat ds ON di.id_image = ds.ce_image' |
. ' WHERE %s GROUP BY id_image /* car plusieurs image pour obs, see PHP */ ORDER BY moyenne LIMIT %d, %d -- %s:%d', |
implode(', ',$champs), |
implode(' AND ', $where), |
intval(@$this->parametres['navigation.depart']), |
$limite, |
__FILE__, __LINE__); |
// GROUP BY (très couteux) car multiples observations associées à une image |
// eg: 16150,16185,16245,16246,118995,129989 |
return $this->bdd->recupererTous($requeteLiaisons); |
} |
/** |
* Retourner un tableau d'images formaté en fonction des liaisons trouvées |
* @param $liaisons les liaisons de la table del_obs_images |
* */ |
private function chargerImage($liaisons) { |
$images = array(); |
foreach ($liaisons as $liaison) { |
if($liaison['ce_utilisateur'] == 0) { |
$liaison['prenom'] = $liaison['prenom_utilisateur']; |
$liaison['nom'] = $liaison['nom_utilisateur']; |
} |
$idObs = $liaison['id_observation']; |
$idImage = $liaison['id_image']; |
// On enregistre l'ID de l'obs pour n'effectuer qu'une seule requête par la suite |
$this->obsIds[] = $idObs; |
$index = $liaison['id_image'].'-'.$liaison['id_observation']; |
$this->indexImagesIds[$idImage] = $index; |
$images[$index] = array( |
'id_image' => $idImage, |
'id_observation' => $idObs, |
'auteur.intitule' => $liaison['prenom'].' '.$liaison['nom'], |
'binaire.href' => sprintf($this->conteneur->getParametre('url_images'), $idImage), |
'determination.famille' => $liaison['famille'], |
'determination.referentiel' => $liaison['nom_referentiel'], |
'determination.ns' => $liaison['nom_ret'], |
'determination.nn' => $liaison['nom_ret_nn'], |
'determination.nt' => $liaison['nt'], |
'date_observation' => $liaison['date_observation'], |
'localite' => $this->formaterLieu($liaison), |
'mots_cles_image_cel' => $this->formaterMotsClesCel($liaison['mots_cles_texte_image']), |
'mots_cles_image_del' => "" |
); |
} |
return $images; |
} |
/** |
* Charger les votes pour chaque image |
**/ |
private function chargerPropositionPlusProbable($images) { |
$resultatsPropositions = $this->bdd->recupererTous(sprintf( |
'SELECT * FROM del_commentaire WHERE ce_observation IN (%s) AND nom_sel IS NOT NULL', |
implode(',', $this->obsIds))); |
$resultatsVotes = $this->bdd->recupererTous(sprintf( |
'SELECT ce_proposition, valeur, ce_utilisateur FROM del_commentaire_vote WHERE ce_proposition IN'. |
' ( SELECT id_commentaire FROM del_commentaire WHERE ce_observation IN (%s) AND nom_sel IS NOT NULL )'. |
' ORDER BY ce_proposition', |
implode(',', $this->obsIds))); |
$resultatsMotsCles = $this->bdd->recupererTous(sprintf( |
'SELECT tag, ce_image FROM del_image_tag WHERE ce_image IN (%s) AND actif = 1', |
implode(',', array_keys($this->indexImagesIds)))); |
$propositions = array(); |
$votes = array(); |
foreach($resultatsVotes as $vote) { |
if(!isset($votes[$vote['ce_proposition']])) { |
$votes[$vote['ce_proposition']] = 0; |
} |
$valeur = ($vote['valeur'] == 1) ? 1 : -1; |
$votes[$vote['ce_proposition']] += is_numeric($vote['ce_utilisateur']) ? 3*$valeur : $valeur; |
} |
foreach($resultatsPropositions as $proposition) { |
$id_proposition = $proposition['id_commentaire']; |
$id_obs = $proposition['ce_observation']; |
if(isset($votes[$id_proposition])) { |
$score = $votes[$id_proposition]; |
} else { |
$score = -1; |
} |
$proposition['valeur'] = $score; |
if(!isset($propositions[$id_obs])) { |
$propositions[$id_obs] = $proposition; |
} else { |
$score_ancienne_proposition = $propositions[$id_obs]['valeur']; |
$propositions[$id_obs] = ($score >= $score_ancienne_proposition) ? |
$proposition : $propositions[$id_obs]; |
} |
} |
foreach ($resultatsMotsCles as $motCle) { |
$tag = $motCle['tag']; |
$index = $this->indexImagesIds[$motCle['ce_image']]; |
if($images[$index]['mots_cles_image_del'] != "") { |
$tag = ",".$tag; |
} |
$images[$index]['mots_cles_image_del'] .= $tag ; |
} |
foreach ($images as $id => $image) { |
if ($this->doitRemplacerObservationParProposition($propositions, $image)) { |
$id_obs = $image['id_observation']; |
$images[$id]['determination.famille'] = $propositions[$id_obs]['famille']; |
$images[$id]['determination.ns'] = $propositions[$id_obs]['nom_sel']; |
$images[$id]['determination.nn'] = $propositions[$id_obs]['nom_sel_nn']; |
$images[$id]['determination.nt'] = $propositions[$id_obs]['nt']; |
} |
if(isset($images[$id]['determination.nn'])) { |
$images[$id]['url_fiche_eflore'] = sprintf($this->conteneur->getParametre('url_fiche_eflore'), $images[$id]['determination.nn']); // formaterUrlFicheEflore |
} |
} |
return $images; |
} |
private function doitRemplacerObservationParProposition($propositions, $image) { |
return ((isset($propositions[$image['id_observation']]) && |
$propositions[$image['id_observation']] != null && |
$propositions[$image['id_observation']]['nom_sel_nn'] != 0) && |
($propositions[$image['id_observation']]['valeur'] > 0 || |
$image['determination.nn'] == 0) |
); |
} |
/*------------------------------------------------------------------------------- |
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) { |
return implode(',', array_intersect( |
explode(',', $this->conteneur->getParametre('mots_cles_cel_affiches')), // $tabMotsClesAffiches |
explode(',', $chaineMotCleCel))); // $tabMotsClesCel |
} |
private function formaterLieu($image) { |
if(! $image['ce_zone_geo']) return ''; |
$lieu = $image['zone_geo']; |
$id_zone_geo = $image['ce_zone_geo']; |
if(strpos($image['ce_zone_geo'], 'INSEE-C:') === 0) { |
$id_zone_geo = str_replace('INSEE-C:', '', $image['ce_zone_geo']); |
$id_zone_geo = strlen($id_zone_geo) >= 5 ? substr($id_zone_geo, 0, 2) : $id_zone_geo; |
} |
return $lieu . ' ('.$id_zone_geo.')'; |
} |
} |
/branches/v1.1-helium/services/modules/0.1/commentaires/AjouterCommentaire.php |
---|
New file |
0,0 → 1,261 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class AjouterCommentaire { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $commentaire; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_commentaires.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_commentaires.ini'); |
$this->navigation = $conteneur->getNavigation(); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
/** |
* Ajoute un commentaire/determination si les objets fournis en paramètres sont valides |
* 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 ajouter($ressources, $parametres) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
$this->verifierConfiguration(); |
$utilisateur = $this->chercherUtilisateur(); |
$proposition_initiale = $this->verifierEtCreerPropositionDeterminationInitiale(); |
$insertion = $this->insererCommentaire($utilisateur); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = array('id_commentaire' => $insertion); |
return $resultat; |
} |
//ce_observation=728176&texte=ABC&auteur.id=11623&auteur.prenom=grégoire&auteur.nom=duché&auteur.courriel=gregoire@tela-botanica.org |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Initialiser les attributs de la classe avec les parametres |
* */ |
public function configurer() { |
$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire'); |
//TODO : Gérer le cas d'une proposition |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
if (empty($this->mappingCommentaire)) { |
$erreurs[] = "Le fichier de configuration ne contient pas le tableau [mapping_commentaire] ou celui-ci est vide."; |
} |
$parametresPossibles = array_values($this->mappingCommentaire); |
foreach ($this->parametres as $nomParam => $valeur) { |
if (!in_array($nomParam, $parametresPossibles)) { |
$erreurs[] = "Paramètre « {$nomParam} » non autorisé."; |
} |
} |
if (!isset($this->parametres['observation'])) { |
$erreurs[] = "Impossible d'ajouter un commentaire sans observation."; |
} |
if (!isset($this->parametres['auteur.id'])) { |
if (!isset($this->parametres['auteur.nom'])) { |
$erreurs[] = "Pas de nom d'utilisateur donné."; |
} |
if (!isset($this->parametres['auteur.prenom'])) { |
$erreurs[] = "Pas de prenom d'utilisateur donné."; |
} |
if (!isset($this->parametres['auteur.courriel'])) { |
$erreurs[] = "Pas de courriel d'utilisateur donné."; |
} |
} |
if (isset($this->parametres['nom_sel']) &&trim($this->parametres['nom_sel']) == '') { |
$erreurs[] = "S'il est présent le paramètre «nom_sel» ne peut pas être vide."; |
} |
//TODO : Gérer le cas d'une proposition |
if (!empty($erreurs)) { |
$e = implode("\n", $erreurs); |
$msg = "Erreur de configuration :\n $e"; |
echo $msg; |
throw new Exception($msg, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/*------------------------------------------------------------------------------- |
INSERTION DES COMMENTAIRES |
--------------------------------------------------------------------------------*/ |
/** |
* Trouver l'utilisateur en fonction des paramètres ou de la base de données si le nom, prénom et courriel ne sont pas donnés |
* @return le tableau utilisateur |
* */ |
private function chercherUtilisateur() { |
$utilisateur = array(); |
// Si l'id est fournit, on récupère les informations de l'utilisateur dans la base de données |
// Sinon, on récupère les informations depuis le tableau Commentaire et on vérifie leur cohérence |
if (isset($this->parametres['auteur.id'])) { |
$requete = "SELECT id_utilisateur as 'auteur.id', nom as 'auteur.nom', prenom as 'auteur.prenom', courriel as 'auteur.courriel' ". |
'FROM '.$this->gestionBdd->formaterTable('del_utilisateur'). |
'WHERE id_utilisateur = '.$this->bdd->proteger($this->parametres['auteur.id']); |
$utilisateur = $this->bdd->recuperer($requete); |
} else { |
if (isset($this->parametres['auteur.nom']) && isset($this->parametres['auteur.prenom']) && isset($this->parametres['auteur.courriel'])) { |
$utilisateur['auteur.nom'] = $this->parametres['auteur.nom']; |
$utilisateur['auteur.prenom'] = $this->parametres['auteur.prenom']; |
$utilisateur['auteur.courriel'] = $this->parametres['auteur.courriel']; |
if ($utilisateur_recherche = $this->estValideDansBdd($utilisateur)) { |
// si l'utilisateur est trouvé, on affecte son id au lieu du numéro temporaire |
$utilisateur = $utilisateur_recherche; |
$this->parametres['auteur.id'] = $utilisateur_recherche['auteur.id']; |
} |
// sinon pas d'erreur, on considere simplement que l'utilisateur |
// est un homonyme ou bien qu'il a décidé d'utiliser un autre mail |
} |
} |
return $utilisateur; |
} |
/** |
* Vérifier que les informations saisies pour un utilisateur sont valides pour la bdd |
* @param $utilisateur array le tableau de l'utilisateur |
* */ |
private function estValideDansBdd($utilisateur) { |
$nom = $this->bdd->proteger($utilisateur['auteur.nom']); |
$prenom = $this->bdd->proteger($utilisateur['auteur.prenom']); |
$courriel = $this->bdd->proteger($utilisateur['auteur.courriel']); |
$requete = "SELECT id_utilisateur AS 'auteur.id', nom AS 'auteur.nom', prenom AS 'auteur.prenom', ". |
" courriel AS 'auteur.courriel' ". |
'FROM del_utilisateur '. |
"WHERE courriel = $courriel ". |
" AND nom = $nom ". |
" AND prenom = $prenom "; |
$utilisateurBdd = $this->bdd->recuperer($requete); |
return $utilisateurBdd; |
} |
/** |
* Insère un commentaire dans la table |
* @param $utilisateur array la liste des paramètres utilisateur |
* */ |
private function insererCommentaire($utilisateur) { |
$requete = 'INSERT INTO del_commentaire '. |
'('.$this->genererEntete($utilisateur).') '. |
'VALUES ('.$this->genererValues().')'; |
$retour = $this->bdd->requeter($requete); |
if ($retour == null) { |
$e = "Erreur inopinée lors de l'insertion"; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
$retour = $this->bdd->recupererIdDernierAjout(); |
return $retour; |
} |
private function verifierEtCreerPropositionDeterminationInitiale() { |
$id_observation = $this->parametres['observation']; |
$proposition_existe = $this->propositionInitialeExiste($id_observation); |
if (!$proposition_existe) { |
$this->creerPropositionAPartirObservation($id_observation); |
} |
} |
private function propositionInitialeExiste($id_observation) { |
$requete = 'SELECT COUNT(*) >= 1 AS existe '. |
'FROM del_commentaire '. |
"WHERE ce_observation = $id_observation ". |
' AND proposition_initiale = 1'; |
$resultat = $this->bdd->recuperer($requete); |
return $resultat['existe'] == 1; |
} |
private function creerPropositionAPartirObservation($id_observation) { |
$idObs = $this->bdd->proteger($id_observation); |
$insertion = '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, nom, '. |
' courriel, nom_sel, nom_sel_nn, nom_ret, nom_ret_nn, '. |
" nt, famille, nom_referentiel, NOW(), '1' ". |
'FROM del_observation AS do '. |
' LEFT JOIN del_utilisateur AS du '. |
' ON do.ce_utilisateur = du.id_utilisateur '. |
"WHERE id_observation = $idObs "; |
$resultat = $this->bdd->requeter($insertion); |
return $resultat; |
} |
private function genererEntete($utilisateur) { |
$this->parametres = array_merge($this->parametres, $utilisateur); |
$entete = array('date'); |
foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) { |
if (isset($this->parametres[$nomFinal]) && $this->parametres[$nomFinal] != null) { |
$entete[] = $nomOriginal; |
} |
} |
return implode(', ', $entete); |
} |
private function genererValues() { |
$valeurs = array('NOW()'); |
foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) { |
if (isset($this->parametres[$nomFinal]) && $this->parametres[$nomFinal] != null) { |
$valeurs[] = $this->bdd->proteger($this->parametres[$nomFinal]); |
} |
} |
return implode(', ', $valeurs); |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/commentaires/ConsulterCommentaire.php |
---|
New file |
0,0 → 1,221 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class ConsulterCommentaire { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $idCommentaire; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_commentaires.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_commentaires.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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
$this->verifierConfiguration(); |
// Lancement du service |
$commentaires = $this->chargerCommentaires(); |
$commentaires = $this->formaterCommentaires($commentaires); |
$total = $this->compterCommentaires(); |
$this->navigation->setTotal($total); |
/*$images = $this->chargerImage($liaisons); |
$images = $this->chargerVotes($images); |
// Mettre en forme le résultat et l'envoyer pour affichage*/ |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $commentaires); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
if (sizeof($this->ressources) == 1 && (is_numeric($this->ressources[0]))) { |
$this->idCommentaire = $ressources[0]; |
} else { |
$e = 'L\identifiant d\un commentaire est numérique'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
public function configurer() { |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
$tableauCommentaires = $this->conteneur->getParametre('commentaires'); |
if (empty($tableauCommentaires)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [commentaires] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
} |
if (empty($this->mappingCommentaire)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_commentaire] ou celui-ci est vide ;'; |
} else { |
$champsMappingCom = array('id_commentaire', 'texte', 'ce_utilisateur', 'utilisateur_nom', 'utilisateur_prenom', 'utilisateur_courriel', 'date'); |
foreach ($champsMappingCom as $champ) { |
if (!isset($this->mappingCommentaire[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour le commentaire est manquant ;'; |
} |
} |
} |
if (empty($this->mappingFiltre)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide ;'; |
} else { |
$champsMappingFiltre = array('observation'); |
foreach ($champsMappingFiltre as $champ) { |
if (!isset($this->mappingFiltre[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour l\'observation est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
if (isset($this->idCommentaire)) { |
$where[] = 'id_commentaire = '.$this->idCommentaire; |
} |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach($tableauMasque as $idMasque => $valeurMasque) { |
//TODO: scinder ceci en fonctions réutilisables ? |
// voir si c'est interessant par rapport à la recherche générale |
$idMasque = str_replace('masque.', '', $idMasque); |
switch ($idMasque) { |
default: |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->proteger($valeurMasque); |
break; |
} |
} |
} |
if (!empty($where)) { |
return ' WHERE '.implode('AND', $where); |
} else { |
return; |
} |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES COMMENTAIRES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis la bdd de tous les commentaires |
* */ |
private function chargerCommentaires() { |
$requeteLiaisons = 'SELECT DISTINCT SQL_CALC_FOUND_ROWS * '. |
'FROM '.$this->gestionBdd->formaterTable('del_commentaire', 'dc'); |
$requeteLiaisons .= $this->chargerClauseWhere(); |
$requeteLiaisons .= $this->gestionBdd->getLimitSql(); |
return $this->bdd->recupererTous($requeteLiaisons); |
} |
/** |
* Compter le nombre total de commentaires dans la base pour affichage dans entete. |
* */ |
private function compterCommentaires() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater les commentaires |
* @param $commentaires les commentaires à mettre à jour |
* @return $commentaires les commentaires mis à jour |
* */ |
private function formaterCommentaires($commentaires) { |
$retourCommentaires = array(); |
foreach ($commentaires as $id => $commentaire) { |
foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) { |
$retourCommentaires[$nomFinal] = $commentaire[$nomOriginal]; |
} |
} |
return $retourCommentaires; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/commentaires/ListeCommentaires.php |
---|
New file |
0,0 → 1,205 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class ListeCommentaires { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_commentaires.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_commentaires.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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
$this->verifierConfiguration(); |
// Lancement du service |
$commentaires = $this->chargerCommentaires(); |
$commentaires = $this->formaterCommentaires($commentaires); |
$total = $this->compterCommentaires(); |
$this->navigation->setTotal($total); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $commentaires); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
public function configurer() { |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
$tableauCommentaires = $this->conteneur->getParametre('commentaires'); |
if (empty($tableauCommentaires)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [commentaires] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
} |
if (empty($this->mappingCommentaire)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_commentaire] ou celui-ci est vide ;'; |
} else { |
$champsMappingCom = array('id_commentaire', 'texte', 'ce_utilisateur', 'utilisateur_nom', 'utilisateur_prenom', 'utilisateur_courriel', 'date'); |
foreach ($champsMappingCom as $champ) { |
if (!isset($this->mappingCommentaire[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour le commentaire est manquant ;'; |
} |
} |
} |
if (empty($this->mappingFiltre)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide ;'; |
} else { |
$champsMappingFiltre = array('observation'); |
foreach ($champsMappingFiltre as $champ) { |
if (!isset($this->mappingFiltre[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour l\'observation est manquant ;'; |
} |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach($tableauMasque as $idMasque => $valeurMasque) { |
//TODO: scinder ceci en fonctions réutilisables ? |
// voir si c'est interessant par rapport à la recherche générale |
$idMasque = str_replace('masque.', '', $idMasque); |
switch ($idMasque) { |
default: |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->proteger($valeurMasque); |
break; |
} |
} |
} |
if (!empty($where)) { |
return ' WHERE '.implode('AND', $where); |
} else { |
return; |
} |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES COMMENTAIRES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis la bdd de tous les commentaires |
* */ |
private function chargerCommentaires() { |
$requeteLiaisons = 'SELECT DISTINCT SQL_CALC_FOUND_ROWS * '. |
'FROM '.$this->gestionBdd->formaterTable('del_commentaire', 'dc'); |
$requeteLiaisons .= $this->chargerClauseWhere(); |
$requeteLiaisons .= $this->gestionBdd->getLimitSql(); |
return $this->bdd->recupererTous($requeteLiaisons); |
} |
/** |
* Compter le nombre total de commentaires dans la base pour affichage dans entete. |
* */ |
private function compterCommentaires() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater les commentaires |
* @param $commentaires les commentaires à mettre à jour |
* @return $commentaires les commentaires mis à jour |
* */ |
private function formaterCommentaires($commentaires) { |
$retourCommentaires = array(); |
foreach ($commentaires as $id => $commentaire) { |
$nouveauCommentaire = array(); |
foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) { |
$nouveauCommentaire[$nomFinal] = $commentaire[$nomOriginal]; |
} |
$retourCommentaires[$nouveauCommentaire['id_commentaire']] = $nouveauCommentaire; |
} |
return $retourCommentaires; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/commentaires/SupprimerCommentaire.php |
---|
New file |
0,0 → 1,199 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class SupprimerCommentaire { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $commentaireId; |
private $utilisateurId; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_commentaires.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_commentaires.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 supprimer($ressources, $parametres) { |
$resultat = new ResultatService(); |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
// la suppression est autorisée pour le propriétaire et l'admin sur un commentaire ou une proposition |
// qui n'a jamais été commentée en retour |
if ($this->sansEnfant() && $this->utilisateurEstAutorise()) { |
$this->supprimerCommentaire(); |
$this->supprimerVotesAssocies(); |
} else { |
$e = 'Impossible de supprimer le commentaire car il a des réponses ou ce n\'est pas le vôtre.'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** sansEnfant permet de vérifier que le commentaire que l'on veut supprimer |
* n'a aucune réponse |
* */ |
public function sansEnfant() { |
$requete = 'SELECT * FROM '.$this->gestionBdd->formaterTable('del_commentaire'). |
'WHERE (ce_proposition = '.$this->commentaireId.' '. |
'OR ce_commentaire_parent = '.$this->commentaireId.')'; |
$resultats = $this->bdd->recupererTous($requete); |
if (!empty($resultats)) { |
$e = 'Impossible de supprimer le commentaire car il a des réponses'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
return true; |
} |
private function utilisateurEstAutorise() { |
$autorise = true; |
if(!$this->estProprietaire() && !$this->utilisateurEstAdmin()) { |
$e = 'Impossible de supprimer le commentaire car l\'utilisateur n\'a pas les droits requis'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
$autorise = false; |
} |
return $autorise; |
} |
/** |
* estProprietaire permet de vérifier que le commentaire appartient à l'utilisateur |
* |
* */ |
public function estProprietaire() { |
$requete = 'SELECT * FROM '.$this->gestionBdd->formaterTable('del_commentaire'). |
'WHERE id_commentaire = '.$this->commentaireId.' '. |
'AND ce_utilisateur = '.$this->utilisateurId; |
$resultats = $this->bdd->recupererTous($requete); |
return !empty($resultats); |
} |
/** |
* Obtient l'utilisateur par le cookie |
*/ |
public function getUtilisateurParCookie() { |
//TODO: utiliser le cookie n'est pas très sécurisé |
// ceci aussi devrait être dans une classe utilitaire |
if(isset($_COOKIE['del_courriel']) && $_COOKIE['del_courriel'] != '') { |
$courriel = $_COOKIE['del_courriel']; |
$requete = 'SELECT id_utilisateur FROM '.$this->gestionBdd->formaterTable('del_utilisateur', 'du'). |
'WHERE courriel = '.$this->bdd->proteger($courriel); |
$utilisateur = $this->bdd->recuperer($requete); |
$this->utilisateurId = $utilisateur['id_utilisateur']; |
} |
} |
/** |
* Renvoie vrai si l'utilisateur existe dans la base de données et si son champ admin est à 1 |
*/ |
private function utilisateurEstAdmin() { |
//TODO: déplacer ceci dans une classe utilitaire |
$requete = 'SELECT admin FROM '.$this->gestionBdd->formaterTable('del_utilisateur_infos', 'dui'). |
'WHERE id_utilisateur = '.$this->bdd->proteger($this->utilisateurId); |
$resultat = $this->bdd->recuperer($requete); |
return ($resultat && $resultat['admin'] == 1); |
} |
/** |
* Initialiser les attributs de la classe avec les parametres |
* */ |
public function configurer() { |
$erreurs= array(); |
if (isset($this->ressources[0]) && is_numeric($this->ressources[0])) { |
$this->commentaireId = $this->ressources[0]; |
} else { |
$erreurs[] = ' - l\identifiant du commentaire doit être un entier; '; |
} |
if(isset($_COOKIE['del_courriel']) && $_COOKIE['del_courriel'] != '') { |
$this->getUtilisateurParCookie(); |
} else { |
$erreurs[] = ' - Ce service nécessite d\'être identifié; '; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur de configuration :'; |
$e = implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/*------------------------------------------------------------------------------- |
SUPPRESSION DES COMMENTAIRES |
--------------------------------------------------------------------------------*/ |
/** |
* Requete effective de suppression |
* */ |
public function supprimerCommentaire() { |
$requete = 'DELETE FROM '.$this->gestionBdd->formaterTable('del_commentaire').' '. |
'WHERE id_commentaire = '.$this->bdd->proteger($this->commentaireId).' '. |
'AND ce_utilisateur = '.$this->bdd->proteger($this->utilisateurId); |
$retour = $this->bdd->requeter($requete); |
if (!$retour) { |
$e = 'Erreur lors de la suppression'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Requete de suppression de votes associés au commentaire |
*/ |
public function supprimerVotesAssocies() { |
$requete = 'DELETE FROM '.$this->gestionBdd->formaterTable('del_commentaire_vote').' '. |
'WHERE ce_proposition = '.$this->bdd->proteger($this->commentaireId); |
$retour = $this->bdd->requeter($requete); |
if (!$retour) { |
$e = 'Erreur lors de la suppression des votes associés'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/communes/ListeCommunes.php |
---|
New file |
0,0 → 1,81 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère toutes les données de la table del_obs_images |
* pour retourner une liste d'images associée à une observation |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class ListeCommunes { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $requete = null; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_communes.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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Lancement du service |
$communes = $this->chargerCommunes($this->masque->getMasque('nom')); |
$total = $this->compterCommunes($communes); |
$this->navigation->setTotal($total); |
$this->conteneur->setSansLimite(); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $communes); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES COMMENTAIRES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis le serveur de toutes les communes |
* */ |
private function chargerCommunes($requete) { |
return json_decode(file_get_contents("http://www.tela-botanica.org/eflore/cel2/jrest/LocationSearch/".$requete)); |
} |
/** |
* Compter le nombre total de communes pour affichage dans entete. |
* */ |
private function compterCommunes($communes) { |
return sizeof($communes); |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/DelTk.php |
---|
New file |
0,0 → 1,448 |
<?php |
/** |
* DEL (Détermination en ligne [Pictoflora/Identiplante]) Toolkit |
* Quelques fonctions utiles, utilisées et/ou utilisables aussi bien par images/*, observations/* |
* et probablement d'autres, comme determination/*. |
* |
* Les domaines des fonctions tournent autour de 4 aspects: |
* - gestions des paramètres d'entrée utilisateurs, valeurs par défaut et sanitization |
* - génération de SQL |
* - processing de tableau de pattern d'utilisation SQL assez commun |
* - formattage basique de sortie (JSON) |
* + quelques helpers basiques |
* |
* @category php 5.2 |
* @package del |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @copyright Copyright (c) 2013 Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
*/ |
define('_LISTE_OBS_MAX_RESULT_LIMIT', 1000); |
define('_LISTE_OBS_MAX_ID_OBS', 10e7); |
// SELECT MAX(num_taxonomique) FROM bdtfx_v2_00; |
define('_LISTE_OBS_MAX_BDTFX_NT', 1000000); // 44378 + 1000 |
// SELECT MAX(num_nom) FROM bdtfx_v2_00; |
define('_LISTE_OBS_MAX_BDTFX_NN', 1000000); // 120816 + 10000 |
class DelTk { |
static $parametres_autorises = array( |
'masque', 'masque.famille', 'masque.nn', 'masque.referentiel', // taxon |
'masque.genre', 'masque.espece', 'masque.ns', // nom_sel |
'masque.commune', 'masque.departement', 'masque.id_zone_geo', // loc |
'masque.auteur', 'masque.date', 'masque.tag', 'masque.type', // autres |
// tri, offset |
'navigation.depart', 'navigation.limite', |
'tri', 'ordre', // TODO: 'total=[yes]', 'fields=[x,y,...]' |
// TODO: masque.annee, masque.insee (!= departement) |
); |
static $default_params = array( |
'navigation.depart' => 0, 'navigation.limite' => 10, |
'tri' => 'date_transmission', 'ordre' => 'desc'); |
// input filtering |
/* Construit un (vulgaire) abstract syntax tree: |
"AND" => [ "tag1", "tag2" ] |
Idéalement (avec un parser simple comme proposé par http://hoa-project.net/Literature/Hack/Compiler.html#Langage_PP) |
nous aurions: |
"AND" => [ "tag1", "tag2", "OR" => [ "tag3", "tag4" ] ] |
Ici nous devons traiter les cas suivants: |
tags séparés par des "ET/AND OU/OR", séparés par des espaces ou des virgules. |
Mais la chaîne peut aussi avoir été issue du "masque général" (la barre de recherche générique). |
ce qui implique des comportement par défaut différents afin de préserver la compatibilité. |
Théorie: |
1) tags passés par "champ tag": |
- support du ET/OU, et explode par virgule. |
- si pas d'opérande détectée: "OU" |
2) tags passés par "recherche générale": |
- support du ET/OU, et explode par whitespace. |
- si pas d'opérande détectée: "ET" |
La présence de $additional_sep s'explique car ET/OU sous-entendent une séparation par des espaces. |
Mais ce n'est pas toujours pertinent car: 1) la compatibilité suggère de considérer parfois |
la virgule comme séparateur et 2) les tags *peuvent* contenir des espaces. Par conséquent: |
* a,b,c => "a" $default_op "b" $default_op "c" |
* a,b AND c => "a" AND "b" AND "c" |
* a OR b AND c,d => "a" AND "b" AND "c" AND "d" |
C'est à dire par ordre décroissant de priorité: |
1) opérande contenu dans la chaîne |
2) opérande par défaut |
3) les séparateurs présents sont substitués par l'opérande déterminée par 1) ou 2) |
// TODO: support des parenthèses, imbrications & co: "(", ")" |
// http://codehackit.blogspot.fr/2011/08/expression-parser-in-php.html |
// http://blog.angeloff.name/post/2012/08/05/php-recursive-patterns/ |
@param $str: la chaîne à "parser" |
@param $default_op: "AND" ou "OR" |
@param $additional_sep: séparateur de mots: |
*/ |
static function buildTagsAST($str = NULL, $default_op, $additional_sep = ',') { |
if(!$str) return; |
$words = preg_split('/ (OR|AND|ET|OU) /', $str, -1, PREG_SPLIT_NO_EMPTY); |
if(preg_match('/\b(ET|AND)\b/', $str)) $op = 'AND'; |
elseif(preg_match('/\b(OU|OR)\b/', $str)) $op = 'OR'; |
else $op = $default_op; |
if($additional_sep) { |
array_walk($words, |
create_function('&$v, $k, $sep', '$v = preg_split("/".$sep."/", $v, -1, PREG_SPLIT_NO_EMPTY);'), |
$additional_sep); |
} |
$words = DelTk::array_flatten($words); |
$words = array_map('trim', $words); |
return array($op => array_filter($words)); |
} |
static function array_flatten($arr) { |
$arr = array_values($arr); |
while (list($k,$v)=each($arr)) { |
if (is_array($v)) { |
array_splice($arr,$k,1,$v); |
next($arr); |
} |
} |
return $arr; |
} |
// supprime l'index du tableau des paramètres si sa valeur ne correspond pas |
// au spectre passé par $values. |
static function unsetIfInvalid(&$var, $index, $values) { |
if(array_key_exists($index, $var)) { |
if(!in_array($var[$index], $values)) unset($var[$index]); |
else return $var[$index]; |
} |
return NULL; |
} |
/* Filtre et valide les paramètres reconnus. Effectue *toute* la sanitization *sauf* l'escape-string |
Cette fonction est appelée: |
- une fois sur les champs de recherche avancées |
- une fois sur le masque général si celui-ci à été spécifié. Dans ce cas, |
la chaîne générale saisie est utilisée comme valeur pour chacun des champs particuliers |
avec les traitements particuliers qui s'imposent |
Par exemple: si l'on cherche "Languedoc", cela impliquera: |
WHERE (nom_sel like "Languedoc" OR nom_ret ... OR ...) mais pas masque.date ou masque.departement |
qui s'assure d'un pattern particulier */ |
static function requestFilterParams(Array $params, $parametres_autorises = NULL, Conteneur $c = NULL /* pour la récup des départements */ ) { |
if($parametres_autorises) { // filtrage de toute clef inconnue |
$params = array_intersect_key($params, array_flip($parametres_autorises)); |
} |
$p['tri'] = DelTK::unsetIfInvalid($params, 'tri', array('date_observation')); |
$p['ordre'] = DelTK::unsetIfInvalid($params, 'ordre', array('asc','desc')); |
$p['masque.referentiel'] = DelTK::unsetIfInvalid($params, 'masque.referentiel', array('bdtfx','bdtxa','isfan')); |
// TODO: use filter_input(INPUT_GET); |
// renvoie FALSE ou NULL si absent ou invalide |
$p['navigation.limite'] = filter_var(@$params['navigation.limite'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 1, |
'max_range' => _LISTE_OBS_MAX_RESULT_LIMIT))); |
$p['navigation.depart'] = filter_var(@$params['navigation.depart'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_ID_OBS))); |
if(isset($params['masque.departement'])) { |
// STRING: 0 -> 95, 971 -> 976, 2A + 2B (./services/configurations/config_departements_bruts.ini) |
// accept leading 0 ? |
// TODO; filter patterns like 555. |
if(preg_match(';^(\d{2}|\d{3}|2a|2b)$;i', $params['masque.departement'])) { |
$p['masque.departement'] = $params['masque.departement']; |
} |
// cf configurations/config_departements_bruts.ini |
elseif( !is_null($c) && ( $x = $c->getParametre( |
strtolower(str_replace(' ','-',iconv("UTF-8", "ASCII//TRANSLIT", $params['masque.departement']))) |
))) { |
$p['masque.departement'] = sprintf("INSEE-C:%02d___", $x); |
} |
} |
if(isset($params['masque.date'])) { |
// une année, TODO: masque.annee |
if(is_numeric($params['masque.date'])) { |
$p['masque.date'] = $params['masque.date']; |
} |
elseif(strpos($params['masque.date'], '/' !== false) && |
($x = strtotime(str_replace('/','-',$params['masque.date'])))) { |
$p['masque.date'] = $x; |
} |
elseif(strpos($params['masque.date'], '-' !== false) && |
($x = strtotime($params['masque.date'])) ) { |
$p['masque.date'] = $x; |
} |
} |
$p['masque.nn'] = filter_var(@$params['masque.nn'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_BDTFX_NN))); |
$p['masque.nt'] = filter_var(@$params['masque.nt'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_BDTFX_NT))); |
// TODO: should we really trim() ? |
if(isset($params['masque.ns'])) $p['masque.ns'] = trim($params['masque.ns']); |
// if(isset($params['masque.texte'])) $p['masque.texte'] = trim($params['masque.texte']); |
if(isset($params['masque.famille'])) { |
// mysql -N<<<"SELECT DISTINCT famille FROM bdtfx_v1_02;"|sed -r "s/(.)/\1\n/g"|sort -u|tr -d "\n" |
$p['masque.famille'] = preg_replace('/[^a-zA-Z %_]/', '', iconv("UTF-8", |
"ASCII//TRANSLIT", |
$params['masque.famille'])); |
} |
// masque.genre est un alias pour masque.ns (nom_sel), mais permet de rajouter une clause supplémentaire |
// sur nom_sel. Précédemment: WHERE nom_sel LIKE '%<masque.genre>% %'. |
// Désormais masque.genre doit être intégralement spécifié, les caractères '%' et '_' seront interprétés. |
// Attention toutefois car la table del_observation intègre des nom_sel contenant '_' |
if(isset($params['masque.genre'])) $p['masque.genre'] = trim($params['masque.genre']); |
if(isset($params['masque.ns'])) $p['masque.ns'] = trim($params['masque.ns']); |
// masque.espece n'était pas déclaré dans la "where" mais utilisé via config + switch//default |
if(isset($params['masque.espece'])) $p['masque.espece'] = trim($params['masque.espece']); |
// idem pour id_zone_geo qui mappait à ce_zone_geo: |
if(isset($params['masque.id_zone_geo']) && preg_match(';^(INSEE-C:\d{5}|\d{2})$;', $params['masque.id_zone_geo'])) { |
$p['masque.id_zone_geo'] = $params['masque.id_zone_geo']; |
} |
// masque.commune (zone_geo) |
// TODO: que faire avec des '%' en INPUT ? |
// Le masque doit *permettre* une regexp et non l'imposer. Charge au client de faire son travail |
if(isset($params['masque.commune'])) $p['masque.commune'] = str_replace(array('-',' '), '_', $params['masque.commune']); |
// masque.auteur: peut-être un id, un courriel, ou un nom ou prénom, ... |
if(isset($params['masque.auteur'])) $p['masque.auteur'] = trim($params['masque.auteur']); |
// sera trimmé plus tard, cf sqlAddConstraint |
if(isset($params['masque'])) $p['masque'] = trim($params['masque']); |
// masque.tag, idem que pour masque.genre et masque.commune |
if(isset($params['masque.tag'])) { |
$x = explode(',',$params['masque.tag']); |
$x = array_map('trim', $x); |
$p['masque.tag'] = implode('|', array_filter($x)); |
} |
// masque.type: ['adeterminer', 'aconfirmer', 'endiscussion', 'validees'] |
if(isset($params['masque.type'])) { |
$p['masque.type'] = array_flip(array_intersect(array_filter(explode(';', $params['masque.type'])), |
array('adeterminer', 'aconfirmer', 'endiscussion', 'validees'))); |
} |
// TODO: masque (général) |
// on filtre les NULL, FALSE et '', mais pas les 0, d'où le callback() |
// TODO: PHP-5.3 |
return array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);')); |
} |
// SQL helpers |
/* Lorsque l'on concatène des champs, un seul NULL prend le dessus, |
Il faut donc utiliser la syntaxe IFNULL(%s, ""). |
(Cette fonction effectue aussi l'implode() "final" */ |
static function sqlAddIfNullPourConcat($tab) { |
// XXX: PHP-5.3 |
return implode(',',array_map(create_function('$a', 'return "IFNULL($a, \"\")";'), $tab)); |
} |
/* Converti un tableau associatif et un préfix optionnel en une chaîne de champs adéquate |
à un SELECT MySQL. |
$select (optionnel) restreint les champs mappés aux valeurs de $select. |
Si $select n'est pas fourni, toutes les clefs présentes dans $map seront présentes dans |
le SELECT en sortie */ |
static function sqlFieldsToAlias($map, $select = NULL, $prefix = NULL) { |
if($select) $arr = array_intersect_key($map, array_flip($select)); |
else $arr = $map; |
$keys = array_keys($arr); |
if($prefix) array_walk($keys, create_function('&$val, $k, $prefix', '$val = sprintf("%s.`%s`", $prefix, $val);'), $prefix); |
else array_walk($keys, create_function('&$val, $k', '$val = sprintf("`%s`", $val);')); |
return implode(', ', array_map(create_function('$v, $k', 'return sprintf("%s AS `%s`", $k, $v);'), $arr, $keys)); |
} |
/* |
Retourne une clause where du style: |
CONCAT(IF(du.prenom IS NULL, "", du.prenom), [...] vdi.i_nomutilisateur) REGEXP 'xxx' |
Note; i_(nom|prenom_utilisateur), alias pour cel_images.(nom|prenom), n'est pas traité |
car cette information est redondante dans cel_image et devrait être supprimée. |
*/ |
static function addAuteursConstraint($val, $db, &$where) { |
@list($a, $b) = explode(' ', $val, 2); |
// un seul terme |
$champs_n = array('du.prenom', // info user authentifié de l'obs depuis l'annuaire |
'vdi.prenom_utilisateur', // info user anonyme de l'obs |
/* 'vdi.i_prenom_utilisateur' */ ); // info user anonyme de l'image |
$champs_p = array('du.nom', // idem pour le nom |
'vdi.nom_utilisateur', |
/* 'vdi.i_nom_utilisateur' */ ); |
/* |
Note: pour l'heure, étant donnés: |
- les CONVERT() de la VIEW del_utilisateur |
- DEFAULT CHARSET=latin1 pour tela_prod_v4.annuaire_tela |
- DEFAULT CHARSET=utf8 pour tb_cel.cel_obs |
et l'âge du capitaine... |
- REGEXP est case-sensitive, et collate les caractères accentués |
- LIKE est case-insensitive, et collate les caractères accentués |
*/ |
if(! $b) { |
$where[] = sprintf('CONCAT(%s,%s) LIKE %s', |
DelTk::sqlAddIfNullPourConcat($champs_n), |
DelTk::sqlAddIfNullPourConcat($champs_p), |
$db->proteger("%".$val."%")); |
} |
else { |
$where[] = sprintf('(CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s)', |
DelTk::sqlAddIfNullPourConcat($champs_n), |
DelTk::sqlAddIfNullPourConcat($champs_p), |
$db->proteger("%" . $a . "%"), $db->proteger("%" . $b . "%")); |
} |
} |
/** |
* - Rempli le tableau des contraintes "where" et "join" nécessaire |
* à la *recherche* des observations demandées ($req) utilisées par self::getIdObs() |
* |
* Attention, cela signifie que toutes les tables ne sont pas *forcément* |
* join'ées, par exemple si aucune contrainte ne le nécessite. |
* $req tel qu'il est rempli ici est utile pour récupéré la seule liste des |
* id d'observation qui match. |
* Pour la récupération effective de "toutes" les données correspondante, il faut |
* réinitialiser $req["join"] afin d'y ajouter toutes les autres tables. |
* |
* Note: toujours rajouter les préfixes de table (vdi,du,doi ou di), en fonction de ce que défini |
* les JOIN qui sont utilisés. |
* le préfix de v_del_image est "vdi" (cf: "FROM" de self::getIdObs()) |
* le préfix de del_utilisateur sur id_utilisateur = vdi.ce_utilisateur est "du" |
* |
* @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes) |
* @param $req le tableau, passé par référence représentant les composants de la requête à bâtir |
*/ |
static function sqlAddConstraint($p, $db, &$req) { |
if(!empty($p['masque.auteur'])) { |
// id du poster de l'obs |
$req['join'][] = 'LEFT JOIN del_utilisateur AS du ON du.id_utilisateur = vdi.ce_utilisateur'; |
// id du poster de l'image... NON, c'est le même que le posteur de l'obs |
// Cette jointure de table est ignoré ci-dessous pour les recherches d'auteurs |
// $req['join'][] = 'LEFT JOIN del_utilisateur AS dui ON dui.id_utilisateur = vdi.i_ce_utilisateur'; |
if(is_numeric($p['masque.auteur'])) { |
$req['where'][] = sprintf('(du.id_utilisateur = %1$d OR vdi.id_utilisateur = %1$d)', $p['masque.auteur']); |
} |
elseif(preg_match(';^.{5,}@[a-z0-9-.]{5,}$;i', $p['masque.auteur'])) { |
$req['where'][] = sprintf('(du.courriel LIKE %1$s OR vdi.courriel LIKE %1$s )', |
$db->proteger($p['masque.auteur'] . '%')); |
} |
else { |
DelTk::addAuteursConstraint($p['masque.auteur'], $db, $req['where']); |
} |
} |
if(!empty($p['masque.date'])) { |
if(is_integer($p['masque.date']) && $p['masque.date'] < 2030 && $p['masque.date'] > 1600) { |
$req['where'][] = sprintf("YEAR(vdi.date_observation) = %d", $p['masque.date']); |
} |
else { |
$req['where'][] = sprintf("DATE_FORMAT(vdi.date_observation, '%%Y-%%m-%%d') = %s", |
$db->proteger(strftime('%Y-%m-%d', $p['masque.date']))); |
} |
} |
// TODO: avoir des champs d'entrée distinct |
if(!empty($p['masque.departement'])) { |
$req['where'][] = sprintf("vdi.ce_zone_geo = %s", $db->proteger('INSEE-C:'.$p['masque.departement'])); |
} |
if(!empty($p['masque.id_zone_geo'])) { |
$req['where'][] = sprintf("vdi.ce_zone_geo = %s", $db->proteger($p['masque.id_zone_geo'])); |
} |
if(!empty($p['masque.genre'])) { |
$req['where'][] = 'vdi.nom_sel LIKE '.$db->proteger('%' . $p['masque.genre'].'% %'); |
} |
if(!empty($p['masque.famille'])) { |
$req['where'][] = 'vdi.famille = '.$db->proteger($p['masque.famille']); |
} |
if(!empty($p['masque.ns'])) { |
$req['where'][] = 'vdi.nom_sel LIKE '.$db->proteger($p['masque.ns'].'%'); |
} |
if(!empty($p['masque.nn'])) { |
$req['where'][] = sprintf('(vdi.nom_sel_nn = %1$d OR vdi.nom_ret_nn = %1$d)', $p['masque.nn']); |
} |
if(!empty($p['masque.referentiel'])) { |
$req['where'][] = sprintf('vdi.nom_referentiel LIKE %s', $db->proteger($p['masque.referentiel'].'%')); |
} |
if(!empty($p['masque.commune'])) { |
$req['where'][] = 'vdi.zone_geo LIKE '.$db->proteger($p['masque.commune'].'%'); |
} |
} |
// formatage de réponse HTTP |
static function makeJSONHeader($total, $params, $url_service) { |
$prev_url = $next_url = NULL; |
$url_service_sans_slash = substr($url_service, 0, -1); |
// aplatissons les params! - une seule couche cela dit, après débrouillez-vous |
$params_a_plat = $params; |
foreach ($params_a_plat as $cle_plate => $pap) { |
if (is_array($pap)) { |
$params_a_plat[$cle_plate] = implode(array_keys($pap), ','); |
} |
} |
$next_offset = $params['navigation.depart'] + $params['navigation.limite']; |
if($next_offset < $total) { |
$next_url = $url_service_sans_slash . '?' . http_build_query(array_merge($params_a_plat, array('navigation.depart' => $next_offset))); |
} |
$prev_offset = $params['navigation.depart'] - $params['navigation.limite']; |
if($prev_offset >= 0) { |
$prev_url = $url_service_sans_slash . '?' . http_build_query(array_merge($params_a_plat, array('navigation.depart' => $prev_offset))); |
} |
return array( |
'masque' => http_build_query(array_diff_key($params, array_flip(array('navigation.depart', 'navigation.limite')))), |
'total' => $total, |
'depart' => $params['navigation.depart'], |
'limite' => $params['navigation.limite'], |
'href.precedent' => $prev_url, |
'href.suivant' => $next_url |
); |
} |
} |
/branches/v1.1-helium/services/modules/0.1/motscles/MotClePictoflora.php |
---|
New file |
0,0 → 1,37 |
<?php |
/** |
* @author Raphaël Droz <raphael@tela-botanica.org> |
* @author Aurélien PERONNET <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2013, Tela Botanica (accueil@tela-botanica.org) |
* @license Licence CECILL http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt |
* @license Licence GNU-GPL http://www.gnu.org/licenses/gpl.html |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class MotClePictoflora { |
// cf: images/VotesImage.php |
static function updateStats($db, $id_image) { |
$id_image = intval($id_image); |
if(!$id_image) throw new Exception("Ne peut mettre à jour les statistiques de vote", |
RestServeur::HTTP_CODE_ERREUR); |
// on utilise toujours cette table de stats (ListeImages) pour les mots-clef "actif". |
$db->requeter(sprintf('UPDATE del_image_stat SET nb_tags = (select COUNT(id_tag) FROM del_image_tag WHERE ce_image = %1$d AND actif = 1) WHERE ce_image = %1$d', $id_image)); |
} |
//TODO: déplacer les fonctions ci dessus et dessous dans une classe |
// utilitaire |
static function normaliserMotCle($str, $charset='utf-8') { |
$str = htmlentities($str, ENT_NOQUOTES, $charset); |
$str = preg_replace('#&([A-za-z])(?:acute|cedil|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str); |
$str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str); // pour les ligatures e.g. 'œ' |
$str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères |
// supprime les espaces, tirets et simple-quotes en underscores |
return str_replace(array(" ", "-", "'"), |
array('_', '_', '_'), |
$str); |
return mb_strtolower($str); |
} |
} |
/branches/v1.1-helium/services/modules/0.1/motscles/ListeMotsCles.php |
---|
New file |
0,0 → 1,184 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service image récupère des listes de mots clés associés aux images |
* |
* @category php 5.2 |
* @package del |
* @subpackage motscles |
* @author Aurélien PERONNET <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id$ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
class ListeMotsCles { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_mots_cles.ini'); |
$this->conteneur->chargerConfiguration('config_mapping_mots_cles.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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
$this->verifierConfiguration(); |
// Lancement du service |
$mots_cles = $this->chargerMotsCles(); |
$mots_cles = $this->formaterMotsCles($mots_cles); |
$total = $this->compterMotsCles(); |
$this->navigation->setTotal($total); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $mots_cles); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
public function configurer() { |
$this->mappingMotsCles = $this->conteneur->getParametre('mapping_mots_cles'); |
$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
$tableau_mots_cles = $this->conteneur->getParametre('motscles'); |
if (empty($tableau_mots_cles)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [motscles] ou celui-ci est vide ;'; |
} else { |
if ($this->conteneur->getParametre('url_service') == null) { |
$erreurs[] = '- paramètre "url_service" manquant ;'; |
} |
} |
if (empty($this->mappingFiltre)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_masque] ou celui-ci est vide ;'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/** |
* Charger la clause WHERE en fonction des paramètres de masque |
* */ |
private function chargerClauseWhere() { |
$where = array(); |
$where[] = ' actif = 1 '; |
$tableauMasque = $this->masque->getMasque(); |
if (!empty($tableauMasque)) { |
foreach($tableauMasque as $idMasque => $valeurMasque) { |
//TODO: scinder ceci en fonctions réutilisables ? |
// voir si c'est interessant par rapport à la recherche générale |
$idMasque = str_replace('masque.', '', $idMasque); |
switch ($idMasque) { |
default: |
$where[] = ' '.$this->mappingFiltre[$idMasque].' = '.$this->proteger($valeurMasque); |
break; |
} |
} |
} |
if (!empty($where)) { |
return ' WHERE '.implode('AND', $where); |
} else { |
return; |
} |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES MOTS CLES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis la bdd de tous les mots clés |
* */ |
private function chargerMotsCles() { |
$requeteLiaisons = 'SELECT DISTINCT SQL_CALC_FOUND_ROWS * '. |
'FROM '.$this->gestionBdd->formaterTable('del_image_tag', 'dit'); |
$requeteLiaisons .= $this->chargerClauseWhere(); |
return $this->bdd->recupererTous($requeteLiaisons); |
} |
/** |
* Compter le nombre total de mots clés dans la base pour affichage dans en tete. |
* */ |
private function compterMotsCles() { |
$requete = 'SELECT FOUND_ROWS() AS nbre '; |
$resultats = $this->bdd->recuperer($requete); |
return (int) $resultats['nbre']; |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater les mots clés |
* @param $mots clés les mots clés à mettre à jour |
* @return $mots clés les mots clés mis à jour |
* */ |
private function formaterMotsCles($mots_cles) { |
$retour = array(); |
foreach ($mots_cles as $id => $mot_cle) { |
$mapping = array(); |
foreach ($this->mappingMotsCles as $nomOriginal => $nomFinal) { |
$mapping[$nomFinal] = $mot_cle[$nomOriginal]; |
} |
$retour[$mot_cle['id_tag']] = $mapping; |
} |
return $retour; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/motscles/SupprimerMotCle.php |
---|
New file |
0,0 → 1,110 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Supprime un mot clé par son identifiant |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Aurélien PERONNET <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id$ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
require_once('MotClePictoflora.php'); |
class SupprimerMotCle { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $motCleId; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->navigation = $conteneur->getNavigation(); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
/** |
* Supprime un mot-clé si les objets fournis en paramètres sont valides |
* 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 supprimer($ressources, $parametres) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->verifierConfiguration(); |
$insertion = $this->supprimerMotCle($this->motCleId); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
if (!isset($this->ressources[0])) { |
$erreurs[] = ' - impossible de supprimer un mot clé sans l\'identifiant associé ;'; |
} else if(!is_numeric($this->ressources[0])) { |
$erreurs[] = ' - l\'identifiant de mot clé doit être un entier ;'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur de configuration :'; |
$e = implode("\n", $erreurs); |
echo var_dump($e); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} else { |
$this->motCleId = $this->ressources[0]; |
} |
} |
/*------------------------------------------------------------------------------- |
SUPPRESSION DES MOTS CLES |
--------------------------------------------------------------------------------*/ |
/** |
* Supprime un mot clé dans la table |
* @param $id_mot_cle string identifiant de mot clé |
* */ |
private function supprimerMotCle($id_mot_cle) { |
$retour = $this->bdd->requeter(sprintf('UPDATE del_image_tag '. |
'SET actif = 0, date_modification = NOW() '. |
'WHERE id_tag = %d', |
intval($id_mot_cle))); |
if ($retour == null) { |
$e = 'Erreur inopinée lors de la suppression'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
MotClePictoflora::updateStats($this->bdd, $id_mot_cle); |
return null; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/motscles/AjouterMotCle.php |
---|
New file |
0,0 → 1,134 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Ajoute un mot clé en l'associant à un identifiant d'image |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Aurélien PERONNET <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id$ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Images |
*/ |
require_once('MotClePictoflora.php'); |
class AjouterMotCle { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
private $bdd; |
private $parametres = array(); |
private $ressources = array(); |
private $commentaire; |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->navigation = $conteneur->getNavigation(); |
$this->masque = $conteneur->getMasque(); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
/** |
* Ajoute un mot-clé si les objets fournis en paramètres sont valides |
* 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 ajouter($ressources, $parametres) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->verifierConfiguration(); |
$insertion = $this->insererMotCle($this->parametres); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = array('id_mot_cle' => $insertion); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Vérifier que le service est bien configuré |
* */ |
public function verifierConfiguration() { |
$erreurs = array(); |
if (!isset($this->parametres['image'])) { |
$erreurs[] = ' - impossible d\'ajouter un mot clé sans image associée ;'; |
} else if(!is_numeric($this->parametres['image'])) { |
$erreurs[] = ' - l\'identifiant d\'image doit être un entier ;'; |
} |
if (!isset($this->parametres['mot_cle'])) { |
$erreurs[] = ' - impossible d\'ajouter un mot clé sans le mot clé ;'; |
} |
if (!isset($this->parametres['auteur.id'])) { |
$erreurs[] = ' - impossible d\'ajouter un mot clé sans auteur associé ;'; |
} |
if (!empty($erreurs)) { |
$e = 'Erreur de configuration :'; |
$e = implode("\n", $erreurs); |
echo var_dump($e); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/*------------------------------------------------------------------------------- |
INSERTION DES MOTS CLES |
--------------------------------------------------------------------------------*/ |
/** |
* Insère un mot clé dans la table |
* @param $mot_cle array la liste des paramètres |
* */ |
private function insererMotCle($mot_cle) { |
$id_image = intval($mot_cle['image']); |
$id_auteur = $mot_cle['auteur.id']; |
$mots_cles = explode(",", $mot_cle['mot_cle']); |
array_walk($mots_cles, create_function('&$val', '$val = trim($val);')); |
$valeurs_a_inserer = array(); |
foreach ($mots_cles as $mot_cle_a_inserer) { |
$mot_cle_normalise = MotClePictoflora::normaliserMotCle($mot_cle_a_inserer); |
$valeurs_a_inserer[] = sprintf('(%d, %s, %s, %s, NOW(), 1, NOW())', |
$id_image, |
$this->bdd->proteger($id_auteur), |
$this->bdd->proteger(trim($mot_cle_a_inserer)), |
$this->bdd->proteger($mot_cle_normalise)); |
} |
$retour = $this->bdd->requeter(sprintf( |
'INSERT INTO del_image_tag (ce_image, ce_utilisateur, tag, tag_normalise, date, actif, date_modification) VALUES %s ', |
implode(",", $valeurs_a_inserer))); |
if ($retour == null) { |
$e = 'Erreur inopinée lors de l\insertion'; |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
MotClePictoflora::updateStats($this->bdd, $mot_cle['image']); |
//TODO: voir si cela a vraiment du sens lors de l'ajout de plusieurs mots clés |
return null; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/protocoles/ListeProtocoles.php |
---|
New file |
0,0 → 1,144 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service observations récupère tous les protocoles avec leur id, nom et descriptif |
* |
* @category php 5.2 |
* @package del |
* @subpackage protocoles |
* @author Aurélien Peronnet <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Protocoles |
*/ |
class ListeProtocoles extends RestService { |
private $conteneur; |
private $navigation; |
private $masque; |
private $gestionBdd; |
protected $bdd; |
private $parametres = array(); |
private $ressources = array(); |
public function __construct(Conteneur $conteneur = null) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_mapping_votes.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 protocoles 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) { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
// Gestion des configuration du script |
$this->configurer(); |
$this->verifierConfiguration(); |
$protocoles = $this->chargerProtocoles(); |
$protocoles = $this->formaterProtocoles($protocoles); |
$this->navigation->setTotal(count($protocoles)); |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => $this->conteneur->getEntete(), 'resultats' => $protocoles); |
return $resultat; |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
/*------------------------------------------------------------------------------- |
CONFIGURATION DU SERVICE |
--------------------------------------------------------------------------------*/ |
/** |
* Configuration du service en fonction du fichier de config config_del.ini |
* */ |
private function configurer() { |
$this->mappingVotes = $this->conteneur->getParametre('mapping_votes'); |
} |
/** |
* Vérifier que le service est bien configuré |
* */ |
private function verifierConfiguration() { |
if (empty($this->mappingVotes)) { |
$erreurs[] = '- le fichier de configuration ne contient pas le tableau [mapping_votes] ou celui-ci est vide ;'; |
} else { |
$champsMappingVotes = array('id_protocole', 'intitule', 'descriptif'); |
foreach ($champsMappingVotes as $champ) { |
if (!isset($this->mappingVotes[$champ])) { |
$erreurs[] = '- le mapping du champ "'.$champ.'" pour les votes est manquant ;'; |
} |
} |
} |
$parametres_autorises = array('navigation.depart', 'navigation.limite'); |
foreach ($this->parametres as $cle => $valeur) { |
if($cle != 'navigation.depart' && $cle != 'navigation.limite') { |
$erreurs[] = '- aucun masque n\'est autorisé pour ce service ;'; |
break; |
} |
} |
if (!empty($erreurs)) { |
$e = 'Erreur lors de la configuration : '."\n"; |
$e .= implode("\n", $erreurs); |
throw new Exception($e, RestServeur::HTTP_CODE_ERREUR); |
} |
} |
/*------------------------------------------------------------------------------- |
CHARGEMENT DES PROTOCOLES |
--------------------------------------------------------------------------------*/ |
/** |
* Chargement depuis la bdd de tous les protocoles ainsi que leur descriptif |
* */ |
private function chargerProtocoles() { |
$requeteProtocoles = 'SELECT * FROM del_image_protocole'; |
return $this->bdd->recupererTous($requeteProtocoles); |
} |
/*------------------------------------------------------------------------------- |
FORMATER ET METTRE EN FORME |
--------------------------------------------------------------------------------*/ |
/** |
* Formater les protocoles |
* @param array $protocoles les protocoles |
* */ |
private function formaterProtocoles($protocoles) { |
$protocolesRetour = array(); |
foreach ($protocoles as $protocole) { |
$protocoleFormate = array(); |
$idProtocole = $protocole['id_protocole']; |
foreach($protocole as $champProtocole => $valeur) { |
$protocoleFormate[$this->mappingVotes[$champProtocole]] = $valeur; |
} |
$protocolesRetour[$idProtocole] = $protocoleFormate; |
} |
return $protocolesRetour; |
} |
private function proteger($valeur) { |
if (is_array($valeur)) { |
return $this->bdd->protegerTableau($valeur); |
} else { |
return $this->bdd->proteger($valeur); |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/Images.php |
---|
New file |
0,0 → 1,254 |
<?php |
/** |
* Description : |
* Classe principale de chargement des services d'eFlore. |
* |
* Encodage en entrée : utf8 |
* Encodage en sortie : utf8 |
* @package eflore-projets |
* @author Jennifer DHÉ <jennifer.dhe@tela-botanica.org> |
* @author Delphine CAUQUIL <delphine@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@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 0.1 |
* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org) |
*/ |
class Images extends RestService { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/images/ => toutes les images, appel à la classe ListeImages |
* http://localhost/del/services/0.1/images/#id => une image donnée => en test pour remplacer les appels à eflore/cel |
* http://localhost/del/services/0.1/images/#id/votes/ => tous les votes d'une image classés par protocole |
* http://localhost/del/services/0.1/images/#id/votes/protocole/#id => tous les votes d'une image et d'un protocole donné |
* http://localhost/del/services/0.1/images/#id/votes/#id => un vote donné pour une image donnée. |
* */ |
private $parametres = array(); |
private $ressources = array(); |
private $methode = null; |
private $projetNom = array(); |
private $serviceNom = array(); |
private $cheminCourant = null; |
private $conteneur; |
/** Indique si oui (true) ou non (false), on veut utiliser les paramètres bruts. */ |
protected $utilisationParametresBruts = true; |
public function __construct() { |
$this->cheminCourant = dirname(__FILE__).DS; |
} |
public function consulter($ressources, $parametres) { |
$this->methode = 'consulter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $parametres); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$reponseHttp->emettreLesEntetes(); |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function ajouter($ressources, $requeteDonnees) { |
$this->methode = 'ajouter'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
$reponseHttp->setResultatService($resultat); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
} |
$corps = $reponseHttp->getCorps(); |
return $corps; |
} |
public function modifier($ressources, $requeteDonnees) { |
$this->methode = 'modifier'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
echo $reponseHttp->getCorps(); |
} |
} |
public function supprimer($ressources) { |
$requeteDonnees = array(); |
$this->methode = 'supprimer'; |
$resultat = ''; |
$reponseHttp = new ReponseHttp(); |
try { |
$this->initialiserRessourcesEtParametres($ressources, $requeteDonnees); |
$this->conteneur = new Conteneur($this->parametres); |
$resultat = $this->traiterRessources(); |
} catch (Exception $e) { |
$reponseHttp->ajouterErreur($e); |
$reponseHttp->emettreLesEntetes(); |
echo $reponseHttp->getCorps(); |
} |
} |
private function initialiserRessourcesEtParametres($ressources, $parametres) { |
$this->ressources = $ressources; |
$this->parametres = $parametres; |
} |
private function traiterRessources() { |
$retour = ''; |
$this->initialiserProjet(); |
if ($this->avoirRessourceService()) { |
$retour = $this->initialiserService(); |
} |
return $retour; |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU PROJET |
------------------------------------------------------------------------------------------------------------------*/ |
private function initialiserProjet() { |
$this->chargerNomDuProjet(); |
$this->chargerConfigProjet(); |
} |
private function chargerNomDuProjet() { |
$this->projetNom = 'images'; |
} |
private function chargerConfigProjet() { |
$projet = $this->projetNom; |
$chemin = Config::get('chemin_configurations')."config_$projet.ini"; |
Config::charger($chemin); |
} |
/*------------------------------------------------------------------------------------------------------------------ |
CONFIGURATION DU SERVICE |
------------------------------------------------------------------------------------------------------------------*/ |
private function avoirRessourceService() { |
/* |
* url possibles : |
* http://localhost/del/services/0.1/images/ => toutes les images, appel à la classe ListeImages |
* http://localhost/del/services/0.1/images/#id => une image donnée => en test pour remplacer les appels à eflore/cel |
* http://localhost/del/services/0.1/images/#id/votes/ => tous les votes d'une image classés par protocole |
* http://localhost/del/services/0.1/images/#id/votes/protocole/#id => tous les votes d'une image et d'un protocole donné |
* http://localhost/del/services/0.1/images/#id/votes/#id => un vote donné pour une image donnée. |
* */ |
$presenceRessourceService = false; |
if (isset($this->ressources[0])) { |
if ($this->etreRessourceIdentifiant(0)) { |
if (isset($this->ressources[1])) { |
$presenceRessourceService = $this->avoirRessourceSousService(); |
} else { |
$presenceRessourceService = true; |
$this->serviceNom = 'liste-images'; |
} |
} |
} else { |
$presenceRessourceService = true; |
$this->serviceNom = 'liste-images'; |
} |
return $presenceRessourceService; |
} |
private function avoirRessourceSousService() { |
// TODO: utilité de votes-image et vote-image ? |
// TODO: cette fonction est ignoble, la simplifier |
$presenceRessourceService = false; |
if (sizeof($this->ressources) >= 2) { |
if ($this->ressources[1] == 'votes') { |
$presenceRessourceService = true; |
$this->serviceNom = 'votes-image'; |
} else { |
$this->editerMessageErreurRessource(); |
} |
} else { |
if (isset($this->ressources[2]) && $this->etreRessourceIdentifiant(2)) { |
$presenceRessourceService = true; |
$this->serviceNom = 'vote-image'; |
} else { |
$this->editerMessageErreurRessource(); |
} |
} |
return $presenceRessourceService; |
} |
private function editerMessageErreurRessource() { |
$message = "Le service demandé '".$this->projetNom.'/'.implode('/', $this->ressources). |
"' n'est pas disponible pour le projet ".$this->projetNom." !\n". |
"Les services disponibles sont : images, images/#id/votes, images/#id/vote/#id_vote"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
private function etreRessourceIdentifiant($num) { |
$presenceId = false; |
if (is_numeric($this->ressources[$num])) { |
$presenceId = true; |
} else { |
$message = "Le service demandé '$service' nécessite d'avoir un identifiant d'image valide"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $presenceId; |
} |
private function initialiserService() { |
//$this->chargerNomDuService(); |
$classe = $this->obtenirNomClasseService($this->serviceNom); |
$chemins = array(); |
$chemins[] = $this->cheminCourant.$this->projetNom.DS.$classe.'.php'; |
$chemins[] = $this->cheminCourant.'commun'.DS.$classe.'.php'; |
$retour = ''; |
$service = null; |
foreach ($chemins as $chemin) { |
if (file_exists($chemin)) { |
$this->conteneur->chargerConfiguration('config_'.$this->projetNom.'.ini'); |
require_once $chemin; |
$service = new $classe($this->conteneur); |
if ($this->methode == 'consulter') { |
$retour = $service->consulter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'ajouter') { |
$retour = $service->ajouter($this->ressources, $this->parametres); |
} elseif ($this->methode == 'modifier') { |
$retour = $service->modifier($this->ressources, $this->parametres); |
} elseif ($this->methode == 'supprimer') { |
$retour = $service->supprimer($this->ressources); |
} |
} |
} |
if (is_null($service)) { |
$message = "Le service demandé '{$this->serviceNom}' n'existe pas dans le projet {$this->projetNom} !"; |
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE; |
throw new Exception($message, $code); |
} |
return $retour; |
} |
private function obtenirNomClasseService($mot) { |
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot)))); |
return $classeNom; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/utilisateurs/Deconnecter.php |
---|
New file |
0,0 → 1,36 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service observations récupère toutes les observations et, pour chacune d'elle, les |
* images qui lui sont associées. |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations |
*/ |
class Deconnecter extends gestionUtilisateur { |
/** |
* 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) { |
// supprimer cookie & session |
$this->oublierUtilisateur(); |
// renvoyer identification anonyme |
$utilisateur = $this->getUtilisateurAnonyme(); |
return $utilisateur; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/utilisateurs/Connecter.php |
---|
New file |
0,0 → 1,50 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service observations récupère toutes les observations et, pour chacune d'elle, les |
* images qui lui sont associées. |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations |
*/ |
class Connecter extends gestionUtilisateur { |
/** |
* 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) { |
$login = $ressources[0]; |
$motDePasse = $ressources[1]; |
$utilisateur = $this->identifierUtilisateur($login, $motDePasse); |
$utilisateur = $this->verifierUtilisateur($utilisateur); |
$utilisateur = $this->setUtilisateur($utilisateur); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = $utilisateur; |
return $resultat; |
} |
private function verifierUtilisateur($utilisateur) { |
if ($utilisateur == null || sizeof($utilisateur) == 0 || sizeof($utilisateur) > 1) { |
$e = 'Accès non autorisé'; |
throw new Exception($e, RestServeur::HTTP_CODE_ACCES_NON_AUTORISE); |
} else { |
return $utilisateur[0]; |
} |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/utilisateurs/IdentificationAnonyme.php |
---|
New file |
0,0 → 1,42 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le web service observations récupère toutes les observations et, pour chacune d'elle, les |
* images qui lui sont associées. |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations |
*/ |
class IdentificationAnonyme extends gestionUtilisateur { |
/** |
* 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) { |
$utilisateur = $this->getUtilisateurAnonyme(); |
$utilisateurParCookie = $this->utilisateurEstIdentifie(); |
if ($utilisateurParCookie != null) { |
$utilisateurParCookie['connecte'] = true; |
$utilisateur = $utilisateurParCookie; |
} |
$resultat = new ResultatService(); |
$resultat->corps = $utilisateur; |
return $resultat; |
} |
} |
?> |
/branches/v1.1-helium/services/modules/0.1/utilisateurs/Preferences.php |
---|
New file |
0,0 → 1,112 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Web service de gestion des préférences utilisateur |
* |
* @category php 5.2 |
* @package del |
* @subpackage images |
* @author Aurélien PERONNET <aurelien@tela-botanica.org> |
* @copyright Copyright (c) 2012, Tela Botanica (accueil@tela-botanica.org) |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL |
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL |
* @version $Id: Bdd.php 403 2012-02-22 14:35:20Z gduche $ |
* @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations |
*/ |
class Preferences { |
private $conteneur; |
private $gestionBdd; |
private $bdd; |
public function __construct(Conteneur $conteneur = null) { |
session_start(); |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->conteneur->chargerConfiguration('config_utilisateurs.ini'); |
$this->gestionBdd = $conteneur->getGestionBdd(); |
$this->bdd = $this->gestionBdd->getBdd(); |
} |
/** |
* Renvoie les préférences utilisateurs |
* @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) { |
$id_utilisateur = $ressources[0]; |
$prefs = $this->obtenirPreferencesUtilisateur($id_utilisateur); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = $prefs; |
return $resultat; |
} |
/** |
* Méthode principale de la classe. |
* Modifie les préférences utilisateurs |
* @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 dans le post |
* */ |
public function modifier($ressources, $parametres) { |
$id_utilisateur = $ressources[0]; |
$prefs = $this->modifierPreferencesUtilisateur($id_utilisateur, $parametres); |
// Mettre en forme le résultat et l'envoyer pour affichage |
$resultat = new ResultatService(); |
$resultat->corps = $prefs; |
return $resultat; |
} |
private function obtenirPreferencesUtilisateur($id_utilisateur) { |
$requete = 'SELECT * FROM del_utilisateur_infos WHERE id_utilisateur = '.$this->bdd->proteger($id_utilisateur); |
$prefs_utilisateur = $this->bdd->recupererTous($requete); |
if(empty($prefs_utilisateur)) { |
$this->initialiserInfosUtilisateur($id_utilisateur); |
$prefs_utilisateur = $this->renvoyerInfosUtilisateurDefaut($id_utilisateur); |
} else { |
$prefs_utilisateur = $prefs_utilisateur[0]; |
$prefs_utilisateur['preferences'] = json_decode($prefs_utilisateur['preferences']); |
$prefs_utilisateur['admin'] = $prefs_utilisateur['admin']; |
} |
return $prefs_utilisateur; |
} |
private function modifierPreferencesUtilisateur($id_utilisateur, $prefs) { |
$requete = 'UPDATE del_utilisateur_infos '. |
'SET preferences = '.$this->bdd->proteger(json_encode($prefs)).' '. |
'WHERE id_utilisateur = '.$this->bdd->proteger($id_utilisateur); |
$resultat = $this->bdd->requeter($requete); |
return $resultat; |
} |
private function initialiserInfosUtilisateur($id_utilisateur) { |
$preferences_defaut = $this->obtenirTableauPreferenceDefaut(); |
$requete = 'INSERT INTO del_utilisateur_infos '. |
'(id_utilisateur, admin, preferences, date_premiere_utilisation )'. |
'VALUES '. |
"(".$this->bdd->proteger($id_utilisateur).", 0, ".$this->bdd->proteger(json_encode($preferences_defaut)).", NOW()) ". |
'ON DUPLICATE KEY UPDATE date_premiere_utilisation = NOW() '; |
$resultat = $this->bdd->requeter($requete); |
return $resultat; |
} |
private function renvoyerInfosUtilisateurDefaut($id_utilisateur) { |
return array('id_utilisateur' => $id_utilisateur, |
'admin' => "0", |
'preferences' => $this->obtenirTableauPreferenceDefaut(), |
'date_premiere_utilisation' => date('Y-m-d H:i:s')); |
} |
private function obtenirTableauPreferenceDefaut() { |
return array('mail_notification_mes_obs' => "1", |
'mail_notification_toutes_obs' => "0"); |
} |
} |
?> |