Rev 1721 | Rev 1754 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
/**
* Service fournissant des informations sur les collections et les structures répondant aux critères de recherche
* fournis en paramêtre.
*
* @author Raphaël Droz <raphael@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>
* @copyright 2009, 2013 Tela-Botanica
*/
class CoelRecherche extends Coel {
/**
* Méthode principale appelée avec une requête de type GET.
* Elle sert d'aiguilleur pour appeller la méthode correspondant au type de recherche passé en paramêtre.
*/
public function getElement($param = array()) {
// Initialisation des variables
$info = array();
// Nour recherchons le type de requête demandé
$type = $param[0];
$methode = 'getElement'.$type;
if (method_exists($this, $methode)) {
array_shift($param);
$info = $this->$methode($param);
} else {
$this->messages[] = "Le type de recherche demandé '$type' n'est pas disponible.";
}
// Envoie sur la sortie standard
if($this->formatRetour == 'text/plain') {
$this->envoyer($info, 'text/plain', 'utf-8', false);
exit;
}
$this->envoyer($info);
}
/* Méthode pour récupérer une liste d'information sur les collections et/ou structures en fonction de mots et de
* restrictions.
* Appelée avec les paramêtres d'url suivant :
* /CoelRecherche/ParDefaut/_
* ou les _ représentent dans l'ordre : mots
* Si un des paramêtres est absent, il prendre la valeur *
*/
public function getElementParDefaut($param) {
// Initialisation des variables
$info = array();
// Pré traitement des paramêtres
$p = $this->pretraiterParametresUrl($param, $_GET);
$fromClause = $whereClause = $joinClause = array();
self::construireFromEtWhere($p, $fromClause, $joinClause, $whereClause);
// Construction de la requête
$requete = sprintf(
'SELECT %s cs_id_structure, cs_ville, cs_nom, cs_code_postal, cs_latitude, cs_longitude, cc_id_collection, cc_nom'
. ' FROM %s %s'
. ' WHERE %s ORDER BY %s %s -- %s:%d',
$this->distinct ? 'DISTINCT' : '',
implode(',', $fromClause),
implode(' ', $joinClause),
$whereClause ? implode(" AND ", $whereClause) : TRUE,
is_null($this->orderby) ? 'cs_ville ASC, cs_nom ASC, cc_nom ASC' : $this->orderby,
$this->limit != -1 ? "LIMIT {$this->start}, {$this->limit}" : "",
__FILE__, __LINE__);
// Récupération des résultats
try {
$donnees = $this->bdd->query($requete)->fetchAll(PDO::FETCH_ASSOC);
if ($donnees === false) {
$this->messages[] = "La requête a retourné aucun résultat.";
} else {
$info = $donnees;
}
} catch (PDOException $e) {
$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
}
return $info;
}
/* Méthode pour récupérer une liste d'information sur les collections et/ou structures en fonction de mots et de
* restrictions.
* Appelée avec les paramêtres d'url suivant :
* /CoelRecherche/ParDefaut/_
* ou les _ représentent dans l'ordre : mots
* Si un des paramêtres est absent, il prendre la valeur *
*/
public function getElementNombre($param) {
// Initialisation des variables
$info = array();
// Pré traitement des paramêtres
$p = $this->pretraiterParametresUrl($param, $_GET);
$fromClause = $whereClause = $joinClause = array();
self::construireFromEtWhere($p, $fromClause, $joinClause, $whereClause);
// Construction de la requête
// Il est important de compter le nombre d'association structure-collection différentes pour obtenir le bon nombre
$requete = sprintf(
'SELECT %s COUNT(cs_id_structure) AS nbre, cc_id_collection '
. ' FROM %s %s'
. ' WHERE %s ORDER BY %s LIMIT %d, %d -- %s:%d',
$this->distinct ? 'DISTINCT' : '',
implode(',', $fromClause),
implode(' ', $joinClause),
$whereClause ? implode(" AND ", $whereClause) : TRUE,
is_null($this->orderby) ? 'cs_ville ASC, cs_nom ASC' : $this->orderby,
$this->start, $this->limit,
__FILE__, __LINE__);
// Récupération des résultats
try {
$donnees = $this->bdd->query($requete)->fetch(PDO::FETCH_ASSOC);
if ($donnees === false) {
$this->messages[] = "La requête a retourné aucun résultat.";
} else {
$info = $donnees['nbre'];
}
} catch (PDOException $e) {
$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
}
return $info;
}
private function pretraiterParametresUrl($param, $qs /* query-string */) {
// Tableau des paramêtres qui peuvent être passés dans l'url
$params_passes = array(
'mots' => 'str',
'sci' => 'bool',
'bot' => 'int',
'zg' => 'str',
'p' => 'str',
'pr' => 'int',
'str-d' => 'frdepliste',
'veg' => 'int',
'projets' => 'int');
$p = $this->traiterParametresUrl(array_keys($params_passes), $param, false);
$this->debug[] = $param;
foreach ($params_passes as $param_passe => $type) {
if (isset($p[$param_passe])) {
// Suppression des éventuels espaces en début et fin de chaine
$valeur = trim($p[$param_passe]);
// Type de paramêtre chaine
if ($type == 'str') {
// Suppression des slash
$valeur = stripslashes($valeur);
// Utilisation d'une recherche de chaîne exacte
if (preg_match('/^"(.*)"$/', $valeur, $match)) {
$valeur = '%'.$match[1].'%';
} else {
// Recherche de mots non liés
$mots = explode(' ', $valeur);
$valeur = '%'.implode ('%', $mots).'%';
}
// Mise en place des quotes pour l'intérogation dans la bdd
$valeur = $this->bdd->quote($valeur);
}
// Type de paramêtre booléen
if ($type == 'bool') {
if (preg_match('/^[0]$/', $valeur)) {
$valeur = false;
} else if (preg_match('/^[1]$/', $valeur)) {
$valeur = true;
} else {
$this->messages[] = "Le paramêtre '$param_passe' attend une valeur de type 0 ou 1 et non '$valeur'.";
$valeur = null;
}
}
// Type de paramêtre entier
if ($type == 'int') {
if (!preg_match('/^(?:[0-9]+,\s*)*[0-9]+$/', $valeur)) {
$this->messages[] = "Le paramêtre '$param_passe' attend une ou plusieurs valeurs de type entiers ".
"séparés par des virgules et non '$valeur'.";
$valeur = null;
}
}
if ($type == 'frdepliste') {
$valeur = array_filter(explode(',', $valeur), create_function('$val', 'return preg_match("/^(\d+|2A|2B)$/i", $val);'));
}
$p[$param_passe] = $valeur;
}
}
if(isset($qs['pays'])) {
$p['pays'] = array_filter(explode(',', $qs['pays']), create_function('$val', 'return preg_match("/^[A-Z][A-Z]$/", $val);'));
if(!$p['pays']) unset($p['pays']);
}
if(isset($qs['regions'])) {
$p['regions'] = array_filter(explode(',', $qs['regions']), create_function('$val', 'return preg_match("/^[A-Z][A-Z]\.\w\w$/", $val);'));
if(!$p['regions']) unset($p['regions']);
}
return $p;
}
static function construireFromEtWhere($p, &$from, &$join, &$where) {
$from = array('coel_collection');
$join = array('LEFT JOIN coel_structure ON (cc_ce_structure = cs_id_structure)');
$where = array();
// Gestion du from en fonction des paramêtres
if (isset($p['str-d'])) {// ATTENTION : Remplace $from, doit être situé en première position!
$from = array('coel_structure');
$join = array('LEFT JOIN coel_collection ON (cs_id_structure = cc_ce_structure)');
}
// Construire from et where en fonction des paramêtres
if (isset($p['mots'])) {
$where[] = '(' . implode(' OR ', array(
"cc_nom LIKE {$p['mots']}",
"cc_truk_nom_alternatif LIKE {$p['mots']}",
"cc_truk_code LIKE {$p['mots']}",
"cc_description LIKE {$p['mots']}",
"cc_description_specialiste LIKE {$p['mots']}",
"cc_historique LIKE {$p['mots']}",
"cs_nom LIKE {$p['mots']}",
"cs_truk_nom_alternatif LIKE {$p['mots']}",
"cs_description LIKE {$p['mots']}",
"cs_adresse_01 LIKE {$p['mots']}",
"cs_adresse_02 LIKE {$p['mots']}",
"cs_ville LIKE {$p['mots']}",
"cs_truk_identifiant_alternatif LIKE {$p['mots']}",
"cs_condition_acces LIKE {$p['mots']}",
"cs_condition_usage LIKE {$p['mots']}",
"cs_truk_telephone LIKE {$p['mots']}",
"cs_courriel LIKE {$p['mots']}",
"cs_truk_url LIKE {$p['mots']}")) . ')';
}
if (isset($p['sci'])) {
if ($p['sci'] === true) {
$where[] = 'csv_mark_visite_avec_motif = 1';
} else if ($p['sci'] === false) {
$where[] = 'csv_mark_acces_ss_motif = 1';
}
}
if (isset($p['bot'])) {
$where[] = "ccb_ce_truk_type IN ({$p['bot']})";
}
if (isset($p['zg'])) {
$where[] = "cc_truk_couverture_lieu LIKE {$p['zg']}";
}
if (isset($p['p'])) {
$where[] = "cp_fmt_nom_complet LIKE {$p['p']}";
}
if (isset($p['pr'])) {
$where[] = "ccap_id_role IN ({$p['pr']})";
}
// par défaut, spécifier un département restreint à la France
// TODO: INNER JOIN
if (isset($p['str-d'])) {
$join[] = 'LEFT JOIN coel_meta_liste_valeur cv ON cv.cmlv_id_valeur = cs_ce_truk_pays';
$where[] = "cv.cmlv_abreviation IN ('FR', 'RE', 'YT', 'GP', 'MQ', 'GF', 'NC')";
$where[] = sprintf("cs_code_postal REGEXP '^(%s).*'", implode('|', $p['str-d']));
}
// http://download.geonames.org/export/dump/admin1CodesASCII.txt
if (isset($p['regions'])) {
$join[] = 'LEFT JOIN coel_meta_liste_valeur cv ON cv.cmlv_id_valeur = cs_ce_truk_region';
$where[] = sprintf('cv.cmlv_abreviation IN ("%s")', implode('","', $p['regions']));
}
if (isset($p['pays'])) {
if(array_search('FR', $p['pays']) !== FALSE) $p['pays'] = array_merge($p['pays'], array('RE','YT','GP','MQ','GF','NC'));
$join[] = 'LEFT JOIN coel_meta_liste_valeur cv ON cv.cmlv_id_valeur = cs_ce_truk_pays';
$where[] = sprintf('cv.cmlv_abreviation IN ("%s")', implode('","', $p['pays']));
}
if (isset($p['veg'])) {
$veg = explode(',', $p['veg']);
$veg_nbre = count($veg);
if ($veg_nbre == 1) {
$where[] = "ccb_truk_nature LIKE '%{$p['veg']}%'";
} else {
$recherche = array();
foreach ($veg as $id) {
$recherche[] = "ccb_truk_nature LIKE '%$id%'";
}
$where[] = '('.implode(' OR ', $recherche).') ';
}
}
if (isset($p['projets'])) {
$where[] = "cc_ce_projet IN ({$p['projets']})";
$where[] = "cs_ce_projet IN ({$p['projets']})";
}
if (isset($p['sci'])) {
$join[] = 'LEFT JOIN coel_structure_valorisation ON (cs_id_structure = csv_id_structure)';
}
if (isset($p['bot']) || isset($p['veg'])) {
$join[] = 'LEFT JOIN coel_collection_botanique ON (cc_id_collection = ccb_id_collection)';
}
if (isset($p['p']) || isset($p['pr'])) {
$join[] = 'LEFT JOIN coel_collection_a_personne ON (cc_id_collection = ccap_id_collection)';
}
if (isset($p['p'])) {
$join[] = 'LEFT JOIN coel_personne ON (ccap_id_personne = cp_id_personne)';
}
$join = array_unique($join);
}
}