Subversion Repositories eFlore/Applications.coel

Rev

Rev 1704 | Rev 1730 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1497 jpm 1
<?php
2
/**
3
 * Service fournissant des informations sur les collections et les structures répondant aux critères de recherche
4
 * fournis en paramêtre.
1698 raphael 5
 *
6
 * @author Raphaël Droz <raphael@tela-botanica.org>
1497 jpm 7
 * @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
8
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
9
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
1698 raphael 10
 * @copyright 2009, 2013 Tela-Botanica
1497 jpm 11
 */
12
class CoelRecherche extends Coel {
13
 
14
	/**
15
	 * Méthode principale appelée avec une requête de type GET.
16
	 * Elle sert d'aiguilleur pour appeller la méthode correspondant au type de recherche passé en paramêtre.
17
	 */
18
	public function getElement($param = array()) {
19
		// Initialisation des variables
20
		$info = array();
21
 
22
		// Nour recherchons le type de requête demandé
23
		$type = $param[0];
24
 
25
		$methode = 'getElement'.$type;
26
		if (method_exists($this, $methode)) {
27
			array_shift($param);
28
			$info = $this->$methode($param);
29
		} else {
30
			$this->messages[] = "Le type de recherche demandé '$type' n'est pas disponible.";
31
		}
32
 
33
		// Envoie sur la sortie standard
1700 raphael 34
		if($this->formatRetour == 'text/plain') {
35
			$this->envoyer($info, 'text/plain', 'utf-8', false);
36
			exit;
37
		}
1497 jpm 38
		$this->envoyer($info);
39
	}
40
 
1700 raphael 41
	/* Méthode pour récupérer une liste d'information sur les collections et/ou structures en fonction de mots et de
42
	 * restrictions.
1497 jpm 43
	 * Appelée avec les paramêtres d'url suivant :
44
	 * /CoelRecherche/ParDefaut/_
45
	 * ou les _ représentent dans l'ordre : mots
1698 raphael 46
	 * Si un des paramêtres est absent, il prendre la valeur *
1497 jpm 47
	 */
48
	public function getElementParDefaut($param) {
49
		// Initialisation des variables
50
		$info = array();
51
 
52
		// Pré traitement des paramêtres
1702 raphael 53
		$p = $this->pretraiterParametresUrl($param, $_GET);
1698 raphael 54
 
1700 raphael 55
		$fromClause = $whereClause = $joinClause = array();
56
		self::construireFromEtWhere($p, $fromClause, $joinClause, $whereClause);
1699 raphael 57
 
1497 jpm 58
		// Construction de la requête
1698 raphael 59
		$requete = sprintf(
1700 raphael 60
			'SELECT %s cs_id_structure, cs_ville, cs_nom, cs_code_postal, cs_latitude, cs_longitude, cc_id_collection, cc_nom'
61
			. ' FROM %s %s'
62
			. ' WHERE %s ORDER BY %s %s -- %s:%d',
1698 raphael 63
 
1700 raphael 64
			$this->distinct ? 'DISTINCT' : '',
1698 raphael 65
 
1700 raphael 66
			implode(',', $fromClause),
67
			implode(' ', $joinClause),
1698 raphael 68
 
1700 raphael 69
			$whereClause ? implode(" AND ", $whereClause) : TRUE,
70
			is_null($this->orderby) ? 'cs_ville ASC, cs_nom ASC, cc_nom ASC' : $this->orderby,
1699 raphael 71
 
1700 raphael 72
			$this->limit != -1 ? "LIMIT {$this->start}, {$this->limit}" : "",
73
			__FILE__, __LINE__);
1698 raphael 74
 
1545 jpm 75
 
1497 jpm 76
		// Récupération des résultats
77
		try {
78
			$donnees = $this->bdd->query($requete)->fetchAll(PDO::FETCH_ASSOC);
79
			if ($donnees === false) {
80
				$this->messages[] = "La requête a retourné aucun résultat.";
81
			} else {
82
				$info = $donnees;
83
			}
84
		} catch (PDOException $e) {
85
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
86
		}
87
		return $info;
88
	}
89
 
90
	/* Méthode pour récupérer une liste d'information sur les collections et/ou structures en fonction de mots et de
1700 raphael 91
	 * restrictions.
1497 jpm 92
	 * Appelée avec les paramêtres d'url suivant :
93
	 * /CoelRecherche/ParDefaut/_
94
	 * ou les _ représentent dans l'ordre : mots
1698 raphael 95
	 * Si un des paramêtres est absent, il prendre la valeur *
1497 jpm 96
	 */
97
	public function getElementNombre($param) {
98
		// Initialisation des variables
99
		$info = array();
100
 
101
		// Pré traitement des paramêtres
1702 raphael 102
		$p = $this->pretraiterParametresUrl($param, $_GET);
1497 jpm 103
 
1700 raphael 104
		$fromClause = $whereClause = $joinClause = array();
105
		self::construireFromEtWhere($p, $fromClause, $joinClause, $whereClause);
1698 raphael 106
 
1497 jpm 107
		// Construction de la requête
1545 jpm 108
		// Il est important de compter le nombre d'association structure-collection différentes pour obtenir le bon nombre
1698 raphael 109
		$requete = sprintf(
1700 raphael 110
			'SELECT %s COUNT(cs_id_structure) AS nbre, cc_id_collection '
111
			. ' FROM %s %s'
112
			. ' WHERE %s ORDER BY %s LIMIT %d, %d -- %s:%d',
1497 jpm 113
 
1700 raphael 114
			$this->distinct ? 'DISTINCT' : '',
1698 raphael 115
 
1700 raphael 116
			implode(',', $fromClause),
117
			implode(' ', $joinClause),
1698 raphael 118
 
1700 raphael 119
			$whereClause ? implode(" AND ", $whereClause) : TRUE,
120
			is_null($this->orderby) ? 'cs_ville ASC, cs_nom ASC' : $this->orderby,
121
			$this->start, $this->limit,
122
			__FILE__, __LINE__);
1698 raphael 123
 
124
 
1497 jpm 125
		// Récupération des résultats
126
		try {
127
			$donnees = $this->bdd->query($requete)->fetch(PDO::FETCH_ASSOC);
128
			if ($donnees === false) {
129
				$this->messages[] = "La requête a retourné aucun résultat.";
130
			} else {
131
				$info = $donnees['nbre'];
132
			}
133
		} catch (PDOException $e) {
134
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
135
		}
136
 
137
		return $info;
138
	}
139
 
1702 raphael 140
	private function pretraiterParametresUrl($param, $qs /* query-string */) {
1497 jpm 141
		// Tableau des paramêtres qui peuvent être passés dans l'url
1700 raphael 142
		$params_passes = array(
143
			'mots' => 'str',
1497 jpm 144
			'sci' => 'bool',
145
			'bot' => 'int',
146
			'zg' => 'str',
147
			'p' => 'str',
148
			'pr' => 'int',
1700 raphael 149
			'str-d' => 'frdepliste',
1581 jpm 150
			'veg' => 'int',
151
			'projets' => 'int');
1497 jpm 152
 
153
		$p = $this->traiterParametresUrl(array_keys($params_passes), $param, false);
1506 jpm 154
		$this->debug[] = $param;
1497 jpm 155
		foreach ($params_passes as $param_passe => $type) {
156
			if (isset($p[$param_passe])) {
157
				// Suppression des éventuels espaces en début et fin de chaine
158
				$valeur = trim($p[$param_passe]);
159
 
160
				// Type de paramêtre chaine
161
				if ($type == 'str') {
162
					// Suppression des slash
163
					$valeur = stripslashes($valeur);
164
 
165
					// Utilisation d'une recherche de chaîne exacte
166
					if (preg_match('/^"(.*)"$/', $valeur, $match)) {
167
						$valeur = '%'.$match[1].'%';
168
					} else {
169
						// Recherche de mots non liés
170
						$mots = explode(' ', $valeur);
171
						$valeur = '%'.implode ('%', $mots).'%';
172
					}
173
					// Mise en place des quotes pour l'intérogation dans la bdd
174
					$valeur = $this->bdd->quote($valeur);
175
				}
176
				// Type de paramêtre booléen
177
				if ($type == 'bool') {
178
					if (preg_match('/^[0]$/', $valeur)) {
179
						$valeur = false;
180
					} else if (preg_match('/^[1]$/', $valeur)) {
181
						$valeur = true;
182
					} else {
1506 jpm 183
						$this->messages[] = "Le paramêtre '$param_passe' attend une valeur de type 0 ou 1 et non '$valeur'.";
1497 jpm 184
						$valeur = null;
185
					}
186
 
187
				}
188
				// Type de paramêtre entier
189
				if ($type == 'int') {
190
					if (!preg_match('/^(?:[0-9]+,\s*)*[0-9]+$/', $valeur)) {
1506 jpm 191
						$this->messages[] = "Le paramêtre '$param_passe' attend une ou plusieurs valeurs de type entiers ".
1497 jpm 192
							"séparés par des virgules et non '$valeur'.";
193
						$valeur = null;
194
					}
195
				}
1700 raphael 196
 
197
				if ($type == 'frdepliste') {
198
					$valeur = array_filter(explode(',', $valeur), create_function('$val', 'return preg_match("/^(\d+|2A|2B)$/i", $val);'));
199
				}
200
 
1497 jpm 201
				$p[$param_passe] = $valeur;
202
			}
203
		}
1702 raphael 204
 
205
        if(isset($qs['pays'])) {
206
            $p['pays'] = array_filter(explode(',', $qs['pays']), create_function('$val', 'return preg_match("/^[A-Z][A-Z]$/", $val);'));
207
            if(!$p['pays']) unset($p['pays']);
208
        }
209
 
1704 raphael 210
        if(isset($qs['regions'])) {
211
            $p['regions'] = array_filter(explode(',', $qs['regions']), create_function('$val', 'return preg_match("/^[A-Z][A-Z]\.\w\w$/", $val);'));
212
            if(!$p['regions']) unset($p['regions']);
213
        }
214
 
1497 jpm 215
		return $p;
216
	}
217
 
1698 raphael 218
	static function construireFromEtWhere($p, &$from, &$join, &$where) {
1700 raphael 219
		$from = array('coel_collection');
220
		$join = array('LEFT JOIN coel_structure ON (cc_ce_structure = cs_id_structure)');
1698 raphael 221
		$where = array();
222
 
223
		// Gestion du from en fonction des paramêtres
224
		if (isset($p['str-d'])) {// ATTENTION : Remplace $from, doit être situé en première position!
225
			$from = array('coel_structure');
1700 raphael 226
			$join = array('LEFT JOIN coel_collection ON (cs_id_structure = cc_ce_structure)');
1698 raphael 227
		}
1497 jpm 228
 
229
		// Construire from et where en fonction des paramêtres
230
		if (isset($p['mots'])) {
1698 raphael 231
			$where[] = '(' . implode(' OR ', array(
232
				"cc_nom LIKE {$p['mots']}",
233
				"cc_truk_nom_alternatif LIKE {$p['mots']}",
234
				"cc_truk_code LIKE {$p['mots']}",
235
				"cc_description LIKE {$p['mots']}",
236
				"cc_description_specialiste LIKE {$p['mots']}",
237
				"cc_historique LIKE {$p['mots']}",
238
				"cs_nom LIKE {$p['mots']}",
239
				"cs_truk_nom_alternatif LIKE {$p['mots']}",
240
				"cs_description LIKE {$p['mots']}",
241
				"cs_adresse_01 LIKE {$p['mots']}",
242
				"cs_adresse_02 LIKE {$p['mots']}",
243
				"cs_ville LIKE {$p['mots']}",
244
				"cs_truk_identifiant_alternatif LIKE {$p['mots']}",
245
				"cs_condition_acces LIKE {$p['mots']}",
246
				"cs_condition_usage LIKE {$p['mots']}",
247
				"cs_truk_telephone LIKE {$p['mots']}",
248
				"cs_courriel LIKE {$p['mots']}",
249
				"cs_truk_url LIKE {$p['mots']}") . ')');
1497 jpm 250
		}
1698 raphael 251
 
1497 jpm 252
		if (isset($p['sci'])) {
253
			if ($p['sci'] === true) {
1698 raphael 254
				$where[] = 'csv_mark_visite_avec_motif = 1';
1502 jpm 255
			} else if ($p['sci'] === false) {
1698 raphael 256
				$where[] = 'csv_mark_acces_ss_motif = 1';
1497 jpm 257
			}
258
		}
1698 raphael 259
 
1497 jpm 260
		if (isset($p['bot'])) {
1698 raphael 261
			$where[] = "ccb_ce_truk_type IN ({$p['bot']})";
1497 jpm 262
		}
263
		if (isset($p['zg'])) {
1698 raphael 264
			$where[] = "cc_truk_couverture_lieu LIKE {$p['zg']}";
1497 jpm 265
		}
266
		if (isset($p['p'])) {
1698 raphael 267
			$where[] = "cp_fmt_nom_complet LIKE {$p['p']}";
1497 jpm 268
		}
269
		if (isset($p['pr'])) {
1698 raphael 270
			$where[] = "ccap_id_role IN ({$p['pr']})";
1497 jpm 271
		}
1702 raphael 272
 
273
        // par défaut, spécifier un département restreint à la France
1704 raphael 274
        // TODO: INNER JOIN
1497 jpm 275
		if (isset($p['str-d'])) {
1702 raphael 276
            $join[] = 'LEFT JOIN coel_meta_liste_valeur cv ON cv.cmlv_id_valeur = cs_ce_truk_pays';
1721 raphael 277
			$where[] = "cv.cmlv_abreviation IN ('FR', 'RE', 'YT', 'GP', 'MQ', 'GF', 'NC')";
1700 raphael 278
			$where[] = sprintf("cs_code_postal REGEXP '^(%s).*'", implode('|', $p['str-d']));
1497 jpm 279
		}
1698 raphael 280
 
1704 raphael 281
        // http://download.geonames.org/export/dump/admin1CodesASCII.txt
282
		if (isset($p['regions'])) {
283
            $join[] = 'LEFT JOIN coel_meta_liste_valeur cv ON cv.cmlv_id_valeur = cs_ce_truk_region';
284
			$where[] = sprintf('cv.cmlv_abreviation IN ("%s")', implode('","', $p['regions']));
285
		}
286
 
1702 raphael 287
		if (isset($p['pays'])) {
1721 raphael 288
            if(array_search('FR', $p['pays']) !== FALSE) $p['pays'] = array_merge($p['pays'], array('RE','YT','GP','MQ','GF','NC'));
1702 raphael 289
            $join[] = 'LEFT JOIN coel_meta_liste_valeur cv ON cv.cmlv_id_valeur = cs_ce_truk_pays';
290
			$where[] = sprintf('cv.cmlv_abreviation IN ("%s")', implode('","', $p['pays']));
291
		}
292
 
1506 jpm 293
		if (isset($p['veg'])) {
294
			$veg = explode(',', $p['veg']);
295
			$veg_nbre = count($veg);
296
 
297
			if ($veg_nbre == 1) {
1698 raphael 298
				$where[] = "ccb_truk_nature LIKE '%{$p['veg']}%'";
1506 jpm 299
			} else {
300
				$recherche = array();
301
				foreach ($veg as $id) {
302
					$recherche[] = "ccb_truk_nature LIKE '%$id%'";
303
				}
1698 raphael 304
				$where[] = '('.implode(' OR ', $recherche).') ';
1506 jpm 305
			}
1581 jpm 306
		}
1506 jpm 307
 
1581 jpm 308
		if (isset($p['projets'])) {
1698 raphael 309
			$where[] = "cc_ce_projet IN ({$p['projets']})";
1700 raphael 310
			$where[] = "cs_ce_projet IN ({$p['projets']})";
1581 jpm 311
		}
312
 
1698 raphael 313
 
1497 jpm 314
		if (isset($p['sci'])) {
1698 raphael 315
			$join[] = 'LEFT JOIN coel_structure_valorisation ON (cs_id_structure = csv_id_structure)';
1497 jpm 316
		}
1506 jpm 317
		if (isset($p['bot']) || isset($p['veg'])) {
1698 raphael 318
			$join[] = 'LEFT JOIN coel_collection_botanique ON (cc_id_collection = ccb_id_collection)';
1497 jpm 319
		}
320
		if (isset($p['p']) || isset($p['pr'])) {
1698 raphael 321
			$join[] = 'LEFT JOIN coel_collection_a_personne ON (cc_id_collection = ccap_id_collection)';
1497 jpm 322
		}
323
		if (isset($p['p'])) {
1698 raphael 324
			$join[] = 'LEFT JOIN coel_personne ON (ccap_id_personne = cp_id_personne)';
1497 jpm 325
		}
1702 raphael 326
 
327
 
328
        $join = array_unique($join);
329
 
1700 raphael 330
	}
1497 jpm 331
}