Subversion Repositories eFlore/Applications.del

Rev

Rev 1451 | Rev 1480 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1451 Rev 1452
1
<?php
1
<?php
2
/**
2
/**
3
 * Le web service observations récupère toutes les observations et, pour chacune d'elle, les
3
 * Le web service observations récupère toutes les observations et, pour chacune d'elle, les
4
 * images qui lui sont associées.
4
 * images qui lui sont associées.
5
 * Basée sur la classe antérieure dans ListeObservations.php de
5
 * Basée sur la classe antérieure dans ListeObservations.php de
6
 * Grégoire Duché et Aurélien Peronnet
6
 * Grégoire Duché et Aurélien Peronnet
7
 * (formaterVote, formaterDeterminations, chargerNombreCommentaire, chargerVotes, chargerDeterminations)
7
 * (formaterVote, formaterDeterminations, chargerNombreCommentaire, chargerVotes, chargerDeterminations)
8
 *
8
 *
9
 * @category	php 5.2
9
 * @category	php 5.2
10
 * @package		del
10
 * @package		del
11
 * @author		Raphaël Droz <raphael@tela-botanica.org>
11
 * @author		Raphaël Droz <raphael@tela-botanica.org>
12
 * @copyright	Copyright (c) 2013 Tela Botanica (accueil@tela-botanica.org)
12
 * @copyright	Copyright (c) 2013 Tela Botanica (accueil@tela-botanica.org)
13
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
13
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
14
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
14
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
15
 * @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations
15
 * @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations
16
 *
16
 *
17
 * TODO:
17
 * TODO:
18
 * PDO::prepare()
18
 * PDO::prepare()
19
 * Sphinx pour auteur, genre, ns, commune, tag et masque-général
19
 * Sphinx pour auteur, genre, ns, commune, tag et masque-général
20
 */
20
 */
21
 
21
 
22
define('_LISTE_OBS_MAX_RESULT_LIMIT', 1000);
22
define('_LISTE_OBS_MAX_RESULT_LIMIT', 1000);
23
define('_LISTE_OBS_MAX_ID_OBS', 10e7);
23
define('_LISTE_OBS_MAX_ID_OBS', 10e7);
24
// SELECT MAX(num_taxonomique) FROM bdtfx_v2_00;
24
// SELECT MAX(num_taxonomique) FROM bdtfx_v2_00;
25
define('_LISTE_OBS_MAX_BDTFX_NT', 44378 + 1000);
25
define('_LISTE_OBS_MAX_BDTFX_NT', 44378 + 1000);
26
// SELECT MAX(num_nom) FROM bdtfx_v2_00;
26
// SELECT MAX(num_nom) FROM bdtfx_v2_00;
27
define('_LISTE_OBS_MAX_BDTFX_NN', 103386 + 10000);
27
define('_LISTE_OBS_MAX_BDTFX_NN', 103386 + 10000);
28
 
28
 
29
restore_error_handler();
29
restore_error_handler();
30
restore_exception_handler();
30
restore_exception_handler();
31
error_reporting(E_ALL);
31
error_reporting(E_ALL);
32
 
32
 
33
class ListeObservations {
33
class ListeObservations {
34
 
34
 
35
	private $conteneur;
35
	private $conteneur;
36
	private $gestionBdd;
36
	private $gestionBdd;
37
	private $bdd;
37
	private $bdd;
38
	private $parametres = array();
38
	private $parametres = array();
39
	private $ressources = array();
39
	private $ressources = array();
40
 
40
 
41
	static $tris_possibles = array('date_observation');
41
	static $tris_possibles = array('date_observation');
42
	// paramètres autorisés
42
	// paramètres autorisés
43
	static $parametres_autorises = array('masque', 'masque.famille', 'masque.nn', 'masque.referentiel', // taxon
43
	static $parametres_autorises = array('masque', 'masque.famille', 'masque.nn', 'masque.referentiel', // taxon
44
										 'masque.genre', 'masque.espece', 'masque.ns', // nom_sel
44
										 'masque.genre', 'masque.espece', 'masque.ns', // nom_sel
45
										 'masque.commune', 'masque.departement', 'masque.id_zone_geo', // loc
45
										 'masque.commune', 'masque.departement', 'masque.id_zone_geo', // loc
46
										 'masque.auteur', 'masque.date', 'masque.tag', 'masque.type', // autres
46
										 'masque.auteur', 'masque.date', 'masque.tag', 'masque.type', // autres
47
										 // tri, offset
47
										 // tri, offset
48
										 'navigation.depart', 'navigation.limite',
48
										 'navigation.depart', 'navigation.limite',
49
										 'tri', 'ordre', // TODO: 'total=[yes]', 'fields=[x,y,...]'
49
										 'tri', 'ordre', // TODO: 'total=[yes]', 'fields=[x,y,...]'
50
										 // TODO: masque.annee, masque.insee (!= departement)
50
										 // TODO: masque.annee, masque.insee (!= departement)
51
	);
51
	);
52
 
52
 
53
	static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10,
53
	static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10,
54
								   'tri' => 'date_transmission', 'ordre' => 'desc');
54
								   'tri' => 'date_transmission', 'ordre' => 'desc');
55
 
55
 
56
	static $sql_fields_liaisons = array(
56
	static $sql_fields_liaisons = array(
57
		'dob' => array('id_observation', 'nom_sel AS `determination.ns`', 'nt AS `determination.nt`',
57
		'dob' => array('id_observation', 'nom_sel AS `determination.ns`', 'nt AS `determination.nt`',
58
					   'nom_sel_nn AS `determination.nn`', 'famille AS `determination.famille`',
58
					   'nom_sel_nn AS `determination.nn`', 'famille AS `determination.famille`',
59
					   'nom_referentiel AS `determination.referentiel`',
59
					   'nom_referentiel AS `determination.referentiel`',
60
					   'ce_zone_geo AS id_zone_geo', 'zone_geo', 'lieudit',
60
					   'ce_zone_geo AS id_zone_geo', 'zone_geo', 'lieudit',
61
					   'station', 'milieu', 'date_observation', 'mots_cles_texte', 'date_transmission',
61
					   'station', 'milieu', 'date_observation', 'mots_cles_texte', 'date_transmission',
62
					   'ce_utilisateur AS `auteur.id`', 'prenom_utilisateur AS `auteur.prenom`',
62
					   'ce_utilisateur AS `auteur.id`', 'prenom_utilisateur AS `auteur.prenom`',
63
					   'nom_utilisateur AS `auteur.nom`', 'courriel_utilisateur AS observateur',
63
					   'nom_utilisateur AS `auteur.nom`', 'courriel_utilisateur AS observateur',
64
					   'commentaire'),
64
					   'commentaire'),
65
		'di' => array('id_image', 'date_prise_de_vue AS `date`', 'hauteur',/* 'largeur','nom_original' // apparemment inutilisés */),
65
		'di' => array('id_image', 'date_prise_de_vue AS `date`', 'hauteur',/* 'largeur','nom_original' // apparemment inutilisés */),
66
		'du' => array('prenom', 'nom', 'courriel'),
66
		'du' => array('prenom', 'nom', 'courriel'),
67
		'dc' => array('commentaire')
67
		'dc' => array('commentaire')
68
	);
68
	);
69
 
69
 
70
 
70
 
71
	public function __construct(Conteneur $conteneur = null) {
71
	public function __construct(Conteneur $conteneur = null) {
72
		$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur;
72
		$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur;
73
		$this->conteneur->chargerConfiguration('config_departements_bruts.ini');
73
		$this->conteneur->chargerConfiguration('config_departements_bruts.ini');
74
		$this->conteneur->chargerConfiguration('config_observations.ini');
74
		$this->conteneur->chargerConfiguration('config_observations.ini');
75
		$this->conteneur->chargerConfiguration('config_mapping_votes.ini');
75
		$this->conteneur->chargerConfiguration('config_mapping_votes.ini');
76
		$this->conteneur->chargerConfiguration('config_mapping_commentaires.ini');
76
		$this->conteneur->chargerConfiguration('config_mapping_commentaires.ini');
77
		$this->navigation = $conteneur->getNavigation();
77
		$this->navigation = $conteneur->getNavigation();
78
		$this->masque = $conteneur->getMasque();
78
		$this->masque = $conteneur->getMasque();
79
		$this->gestionBdd = $conteneur->getGestionBdd();
79
		$this->gestionBdd = $conteneur->getGestionBdd();
80
		$this->bdd = $this->gestionBdd->getBdd();
80
		$this->bdd = $this->gestionBdd->getBdd();
81
	}
81
	}
82
 
82
 
83
	static function reformateObservation($obs, $url_pattern = '') {
83
	static function reformateObservation($obs, $url_pattern = '') {
84
		$obs = array_map('array_filter', $obs);
84
		$obs = array_map('array_filter', $obs);
85
		$obs_merged = array();
85
		$obs_merged = array();
86
		foreach($obs as $o) {
86
		foreach($obs as $o) {
87
			$id = $o['id_observation'];
87
			$id = $o['id_observation'];
88
 
88
 
89
			// car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID
89
			// car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID
90
			// mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaire
90
			// mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaire
91
			if(!is_numeric($o['auteur.id'])) $o['auteur.id'] = "0";
91
			if(!is_numeric($o['auteur.id'])) $o['auteur.id'] = "0";
92
			if(!isset($o['auteur.nom'])) $o['auteur.nom'] = '[inconnu]';
92
			if(!isset($o['auteur.nom'])) $o['auteur.nom'] = '[inconnu]';
93
 
93
 
94
			$image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original')));
94
			$image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original')));
95
			$image['binaire.href'] = sprintf($url_pattern, $image['id_image']);
95
			$image['binaire.href'] = sprintf($url_pattern, $image['id_image']);
96
			unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']);
96
			unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']);
97
			if(!isset($obs_merged['"' . $id . '"'])) $obs_merged['"' . $id . '"'] = $o;
97
			if(!isset($obs_merged['"' . $id . '"'])) $obs_merged['"' . $id . '"'] = $o;
98
			$obs_merged['"' . $id . '"']['images'][] = $image;
98
			$obs_merged['"' . $id . '"']['images'][] = $image;
99
		}
99
		}
100
		return $obs_merged;
100
		return $obs_merged;
101
	}
101
	}
102
 
102
 
103
	// utilisée uniquement par Observation.php
103
	// utilisée uniquement par Observation.php
104
	static function reformateObservationSimpleIndex($obs, $url_pattern = '') {
104
	static function reformateObservationSimpleIndex($obs, $url_pattern = '') {
105
		// XXX: cf Observation.php::consulter(), nous pourriouns ici
105
		// XXX: cf Observation.php::consulter(), nous pourriouns ici
106
		// conserver les valeurs vides (pour les phptests notamment, ou non)
106
		// conserver les valeurs vides (pour les phptests notamment, ou non)
107
		$obs = array_map('array_filter', $obs);
107
		$obs = array_map('array_filter', $obs);
108
		$obs_merged = array();
108
		$obs_merged = array();
109
		foreach($obs as $o) {
109
		foreach($obs as $o) {
110
			$id = $o['id_observation'];
110
			$id = $o['id_observation'];
111
			$image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original')));
111
			$image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original')));
112
			$image['binaire.href'] = sprintf($url_pattern, $image['id_image']);
112
			$image['binaire.href'] = sprintf($url_pattern, $image['id_image']);
113
			unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']);
113
			unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']);
114
			if(!isset($obs_merged[$id])) $obs_merged[$id] = $o;
114
			if(!isset($obs_merged[$id])) $obs_merged[$id] = $o;
115
			$obs_merged[$id]['images'][$image['id_image']] = $image;
115
			$obs_merged[$id]['images'][$image['id_image']] = $image;
116
		}
116
		}
117
		return $obs_merged;
117
		return $obs_merged;
118
	}
118
	}
119
 
119
 
120
 
120
 
121
	// utilisée uniquement par ListeImages.php
121
	// utilisée uniquement par ListeImages.php
122
	static function reformateImagesDoubleIndex($obs, $url_pattern = '', $image_format = 'XL') {
122
	static function reformateImagesDoubleIndex($obs, $url_pattern = '', $image_format = 'XL') {
123
		// XXX: cf Observation.php::consulter(), nous pourriouns ici
123
		// XXX: cf Observation.php::consulter(), nous pourriouns ici
124
		// conserver les valeurs vides (pour les phptests notamment, ou non)
124
		// conserver les valeurs vides (pour les phptests notamment, ou non)
125
		// $obs = array_map('array_filter', $obs);
125
		// $obs = array_map('array_filter', $obs);
126
		$obs_merged = $obs_keyed_by_id_image = array();
126
		$obs_merged = $obs_keyed_by_id_image = array();
127
		foreach($obs as $o) {
127
		foreach($obs as $o) {
128
			// ceci nous complique la tâche pour le reste du processing...
128
			// ceci nous complique la tâche pour le reste du processing...
129
			$id = $o['jsonindex'];
129
			$id = $o['jsonindex'];
130
			// ainsi nous utilisons deux tableaux: le final, indexé par couple d'id(image-obs)
130
			// ainsi nous utilisons deux tableaux: le final, indexé par couple d'id(image-obs)
131
			// et celui indexé par simple id_image qui est fort utile pour mapVotesToImages()
131
			// et celui indexé par simple id_image qui est fort utile pour mapVotesToImages()
132
			// mais tout deux partage leur référence à "protocole"
132
			// mais tout deux partage leur référence à "protocole"
133
			$image = array(
133
			$image = array(
134
				'id_image' => $o['id_image'],
134
				'id_image' => $o['id_image'],
135
				'binaire.href' => sprintf($url_pattern, $o['id_image'], $image_format),
135
				'binaire.href' => sprintf($url_pattern, $o['id_image'], $image_format),
136
				'mots_cles_texte' => @$o['i_mots_cles_texte'], // @, peut avoir été filtré par array_map() ci-dessus
136
				'mots_cles_texte' => @$o['i_mots_cles_texte'], // @, peut avoir été filtré par array_map() ci-dessus
137
			);
137
			);
138
			unset($o['id_image'], $o['i_mots_cles_texte'], $o['jsonindex']);
138
			unset($o['id_image'], $o['i_mots_cles_texte'], $o['jsonindex']);
139
			if(!isset($obs_merged[$id])) $obs_merged[$id] = $image;
139
			if(!isset($obs_merged[$id])) $obs_merged[$id] = $image;
140
			$obs_merged[$id]['observation'] = $o;
140
			$obs_merged[$id]['observation'] = $o;
141
			$obs_merged[$id]['protocoles_votes'] = array();
141
			$obs_merged[$id]['protocoles_votes'] = array();
142
			
142
			
143
			$obs_keyed_by_id_image[$image['id_image']]['protocoles_votes'] = &$obs_merged[$id]['protocoles_votes'];
143
			$obs_keyed_by_id_image[$image['id_image']]['protocoles_votes'] = &$obs_merged[$id]['protocoles_votes'];
144
		}
144
		}
145
 
145
 
146
		return array($obs_merged,$obs_keyed_by_id_image);
146
		return array($obs_merged,$obs_keyed_by_id_image);
147
	}
147
	}
148
 
148
 
149
	/**
149
	/**
150
	 * Méthode principale de la classe.
150
	 * Méthode principale de la classe.
151
	 * Lance la récupération des images dans la base et les place dans un objet ResultatService
151
	 * Lance la récupération des images dans la base et les place dans un objet ResultatService
152
	 * pour l'afficher.
152
	 * pour l'afficher.
153
	 * @param array $ressources les ressources situées après l'url de base (ex : http://url/ressource1/ressource2)
153
	 * @param array $ressources les ressources situées après l'url de base (ex : http://url/ressource1/ressource2)
154
	 * @param array $parametres les paramètres situés après le ? dans l'url
154
	 * @param array $parametres les paramètres situés après le ? dans l'url
155
	 **/	
155
	 **/	
156
	public function consulter($ressources, $parametres) {
156
	public function consulter($ressources, $parametres) {
157
		// SELECT, à terme, pourrait affecter getInfos(), mais en aucune manière getIdObs()
157
		// SELECT, à terme, pourrait affecter getInfos(), mais en aucune manière getIdObs()
158
		$req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array());
158
		$req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array());
159
 
159
 
160
		// toujours nécessaire puisque nous tapons sur v_del_image qui INNER JOIN cel_images, or nous voulons certes
160
		// toujours nécessaire puisque nous tapons sur v_del_image qui INNER JOIN cel_images, or nous voulons certes
161
		// toutes les images, mais nous voulons $limite observations uniques.
161
		// toutes les images, mais nous voulons $limite observations uniques.
162
		$req['groupby'][] = 'vdi.id_observation';
162
		$req['groupby'][] = 'vdi.id_observation';
163
 
163
 
164
		$db = $this->bdd;
164
		$db = $this->bdd;
165
 
165
 
166
		// filtrage de l'INPUT
166
		// filtrage de l'INPUT
167
		$params = self::requestFilterParams($parametres, self::$parametres_autorises, $this->conteneur);
167
		$params = self::requestFilterParams($parametres, self::$parametres_autorises, $this->conteneur);
168
		// ... et paramètres par défaut
168
		// ... et paramètres par défaut
169
		$params = array_merge(self::$default_params, $params);
169
		$params = array_merge(self::$default_params, $params);
170
 
170
 
171
		// création des contraintes (masques)
171
		// création des contraintes (masques)
172
		self::sqlAddConstraint($params, $db, $req, $this->conteneur);
172
		self::sqlAddConstraint($params, $db, $req, $this->conteneur);
173
		self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur);
173
		self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur);
174
 
174
 
175
		// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS)
175
		// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS)
176
		$idobs_tab = self::getIdObs($params, $req, $db);
176
		$idobs_tab = self::getIdObs($params, $req, $db);
177
		// idobs est une liste (toujours ordonnée) des id d'observations recherchées
177
		// idobs est une liste (toujours ordonnée) des id d'observations recherchées
178
		$idobs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'), $idobs_tab));
178
		$idobs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'), $idobs_tab));
179
 
179
 
180
		if($idobs) {
180
		if($idobs) {
181
			$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']);
181
			$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']);
182
 
182
 
183
			// 2) récupération des données nécessaires pour ces observations (obs + images)
183
			// 2) récupération des données nécessaires pour ces observations (obs + images)
184
			// ici les champs récupérés sont issus de self::$sql_fields_liaisons mais sans préfixes
184
			// ici les champs récupérés sont issus de self::$sql_fields_liaisons mais sans préfixes
185
			// car tout provient de v_del_image
185
			// car tout provient de v_del_image
186
			$obs_unfmt = self::getInfos($idobs, $db);
186
			$obs_unfmt = self::getInfos($idobs, $db);
187
 
187
 
188
			// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output
188
			// 3) suppression, merge des données en tableau assez représentatif du futur JSON en output
189
			$observations = self::reformateObservation($obs_unfmt, $this->conteneur->getParametre('url_images'));
189
			$observations = self::reformateObservation($obs_unfmt, $this->conteneur->getParametre('url_images'));
190
 
190
 
191
			// 4) récupération des données nécessaires pour ces observations (commentaires + votes)
191
			// 4) récupération des données nécessaires pour ces observations (commentaires + votes)
192
			// modifie $observations
192
			// modifie $observations
193
			$this->configurer();
193
			$this->configurer();
194
			$this->chargerDeterminations($observations);
194
			$this->chargerDeterminations($observations);
195
 
195
 
196
			// 5) restauration de l'ordre souhaité initialement
196
			// 5) restauration de l'ordre souhaité initialement
197
			$observations = self::sortArrayByArray($observations, $idobs);
197
			$observations = self::sortArrayByArray($observations, $idobs);
198
		} else {
198
		} else {
199
			$observations = array();
199
			$observations = array();
200
			$total = 0;
200
			$total = 0;
201
		}
201
		}
202
 
202
 
203
		// 6) JSON output
203
		// 6) JSON output
204
		$resultat = new ResultatService();
204
		$resultat = new ResultatService();
205
		$resultat->corps = array('entete' => self::makeJSONHeader($total, $params, Config::get('url_service')),
205
		$resultat->corps = array('entete' => self::makeJSONHeader($total, $params, Config::get('url_service')),
206
								 'resultats' => $observations);
206
								 'resultats' => $observations);
207
		
207
		
208
		return $resultat;
208
		return $resultat;
209
	}
209
	}
210
 
210
 
211
	static function sortArrayByArray($array, $orderArray) {
211
	static function sortArrayByArray($array, $orderArray) {
212
		$ordered = array();
212
		$ordered = array();
213
		foreach($orderArray as $key) {
213
		foreach($orderArray as $key) {
214
			if(array_key_exists('"' . $key . '"', $array)) {
214
			if(array_key_exists('"' . $key . '"', $array)) {
215
				$ordered['"' . $key . '"'] = $array['"' . $key . '"'];
215
				$ordered['"' . $key . '"'] = $array['"' . $key . '"'];
216
				unset($array['"' . $key . '"']);
216
				unset($array['"' . $key . '"']);
217
			}
217
			}
218
		}
218
		}
219
		return $ordered + $array;
219
		return $ordered + $array;
220
	}
220
	}
221
 
221
 
222
	// SQL helpers
222
	// SQL helpers
223
	/*
223
	/*
224
	 * Retourne une liste ordonnée d'id d'observation correspondant aux critères
224
	 * Retourne une liste ordonnée d'id d'observation correspondant aux critères
225
	 * passés dans p et aux clauses where/join présentes dans le tableau $req
225
	 * passés dans p et aux clauses where/join présentes dans le tableau $req
226
	 *
226
	 *
227
	 * @param p: $params (filtrés sauf escape-string)
227
	 * @param p: $params (filtrés sauf escape-string)
228
	 * @param req: le tableau représentant les composants de la requete SQL
228
	 * @param req: le tableau représentant les composants de la requete SQL
229
	 * @param db: l'instance de db
229
	 * @param db: l'instance de db
230
	 */
230
	 */
231
	static function getIdObs($p, $req, $db) {
231
	static function getIdObs($p, $req, $db) {
232
		$req_s = sprintf('SELECT SQL_CALC_FOUND_ROWS id_observation' .
232
		$req_s = sprintf('SELECT SQL_CALC_FOUND_ROWS id_observation' .
233
						 ' FROM v_del_image vdi'.
233
						 ' FROM v_del_image vdi'.
234
						 ' %s' . // LEFT JOIN if any
234
						 ' %s' . // LEFT JOIN if any
235
						 ' WHERE %s'. // where-clause ou TRUE
235
						 ' WHERE %s'. // where-clause ou TRUE
236
						 ' %s'. // group-by
236
						 ' %s'. // group-by
237
						 ' %s'. // having (si commentaires)
237
						 ' %s'. // having (si commentaires)
238
						 ' ORDER BY %s %s %s'.
238
						 ' ORDER BY %s %s %s'.
239
						 ' LIMIT %d, %d -- %s',
239
						 ' LIMIT %d, %d -- %s',
240
						 
240
						 
241
						 $req['join'] ? implode(' ', $req['join']) : '',
241
						 $req['join'] ? implode(' ', $req['join']) : '',
242
						 $req['where'] ? implode(' AND ', $req['where']) : 'TRUE',
242
						 $req['where'] ? implode(' AND ', $req['where']) : 'TRUE',
243
 
243
 
244
						 $req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '',
244
						 $req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '',
245
						 $req['having'] ? ('HAVING ' . implode(' AND ', $req['having'])) : '',
245
						 $req['having'] ? ('HAVING ' . implode(' AND ', $req['having'])) : '',
246
 
246
 
247
						 $p['tri'], strtoupper($p['ordre']),
247
						 $p['tri'], strtoupper($p['ordre']),
248
						 // date_transmission peut-être NULL et nous voulons de la consistence
248
						 // date_transmission peut-être NULL et nous voulons de la consistence
249
						 // (sauf après r1860 de Cel)
249
						 // (sauf après r1860 de Cel)
250
						 $p['tri'] == 'date_transmission' ? ', id_observation' : '',
250
						 $p['tri'] == 'date_transmission' ? ', id_observation' : '',
251
 
251
 
252
						 $p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__);
252
						 $p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__);
253
 
253
 
254
		$res = $db->recupererTous($req_s);
254
		$res = $db->recupererTous($req_s);
255
		$err = mysql_error();
255
		$err = mysql_error();
256
		if(!$res && $err) {
256
		if(!$res && $err) {
257
			// http_response_code(400);
257
			// http_response_code(400);
258
			// if(defined('DEBUG') && DEBUG) header("X-Debug: $req_s");
258
			// if(defined('DEBUG') && DEBUG) header("X-Debug: $req_s");
259
			throw new Exception('not found', 400);
259
			throw new Exception('not found', 400);
260
		}
260
		}
261
		// ordre préservé, à partir d'ici c'est important.
261
		// ordre préservé, à partir d'ici c'est important.
262
		return $res;
262
		return $res;
263
	}
263
	}
264
 
264
 
265
	/*
265
	/*
266
	  Champs récupérés:
266
	  Champs récupérés:
267
	  Pour del_images, la vue retourne déjà ce que nous recherchons de cel_obs et cel_images
267
	  Pour del_images, la vue retourne déjà ce que nous recherchons de cel_obs et cel_images
268
	  (cel_obs.* et cel_[obs_]images.{id_observation, id_image, date_prise_de_vue AS date, hauteur, largeur})
268
	  (cel_obs.* et cel_[obs_]images.{id_observation, id_image, date_prise_de_vue AS date, hauteur, largeur})
269
	  Pour del_commentaires: nous voulons *
269
	  Pour del_commentaires: nous voulons *
270
	  Reste ensuite à formatter.
270
	  Reste ensuite à formatter.
271
	  Note: le préfixe de table utilisé ici (vdi) n'impacte *aucune* autre partie du code car rien
271
	  Note: le préfixe de table utilisé ici (vdi) n'impacte *aucune* autre partie du code car rien
272
	  n'en dépend pour l'heure. (inutilisation de $req['select'])
272
	  n'en dépend pour l'heure. (inutilisation de $req['select'])
273
	*/
273
	*/
274
	static function getInfos($idobs, $db) {
274
	static function getInfos($idobs, $db) {
275
		/*$select_fields = implode(',', array_merge(
275
		/*$select_fields = implode(',', array_merge(
276
			array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['dob']),
276
			array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['dob']),
277
			array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['di']),
277
			array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['di']),
278
			array_map(create_function('$a', 'return "du.".$a;'), self::$sql_fields_liaisons['du'])));*/
278
			array_map(create_function('$a', 'return "du.".$a;'), self::$sql_fields_liaisons['du'])));*/
279
		$select_fields = array_merge(self::$sql_fields_liaisons['dob'],
279
		$select_fields = array_merge(self::$sql_fields_liaisons['dob'],
280
									 self::$sql_fields_liaisons['di']);
280
									 self::$sql_fields_liaisons['di']);
281
		$req_s = sprintf('SELECT %s FROM v_del_image vdi'.
281
		$req_s = sprintf('SELECT %s FROM v_del_image vdi'.
282
						 // ' LEFT JOIN del_commentaire AS dc ON di.id_observation = dc.ce_observation AND dc.nom_sel IS NOT NULL'.
282
						 // ' LEFT JOIN del_commentaire AS dc ON di.id_observation = dc.ce_observation AND dc.nom_sel IS NOT NULL'.
283
						 ' WHERE id_observation IN (%s)',
283
						 ' WHERE id_observation IN (%s)',
284
						 implode(',', $select_fields),
284
						 implode(',', $select_fields),
285
						 implode(',', $idobs));
285
						 implode(',', $idobs));
286
		return $db->recupererTous($req_s);
286
		return $db->recupererTous($req_s);
287
	}
287
	}
288
 
288
 
289
 
289
 
290
	/**
290
	/**
291
	 * - Rempli le tableau des contraintes "where" et "join" nécessaire
291
	 * - Rempli le tableau des contraintes "where" et "join" nécessaire
292
	 * à la *recherche* des observations demandées ($req) utilisées par self::getIdObs()
292
	 * à la *recherche* des observations demandées ($req) utilisées par self::getIdObs()
293
	 *
293
	 *
294
	 * Attention, cela signifie que toutes les tables ne sont pas *forcément*
294
	 * Attention, cela signifie que toutes les tables ne sont pas *forcément*
295
	 * join'ées, par exemple si aucune contrainte ne le nécessite.
295
	 * join'ées, par exemple si aucune contrainte ne le nécessite.
296
	 * $req tel qu'il est rempli ici est utile pour récupéré la seule liste des
296
	 * $req tel qu'il est rempli ici est utile pour récupéré la seule liste des
297
	 * id d'observation qui match.
297
	 * id d'observation qui match.
298
	 * Pour la récupération effective de "toutes" les données correspondante, il faut
298
	 * Pour la récupération effective de "toutes" les données correspondante, il faut
299
	 * réinitialiser $req["join"] afin d'y ajouter toutes les autres tables.
299
	 * réinitialiser $req["join"] afin d'y ajouter toutes les autres tables.
300
	 *
300
	 *
301
	 * Note: toujours rajouter les préfixes de table (vdi,du,doi ou di), en fonction de ce que défini
301
	 * Note: toujours rajouter les préfixes de table (vdi,du,doi ou di), en fonction de ce que défini
302
	 * les JOIN qui sont utilisés.
302
	 * les JOIN qui sont utilisés.
303
	 * le préfix de v_del_image est "vdi" (cf: "FROM" de self::getIdObs())
303
	 * le préfix de v_del_image est "vdi" (cf: "FROM" de self::getIdObs())
304
	 * le préfix de del_utilisateur sur id_utilisateur = vdi.ce_utilisateur est "du"
304
	 * le préfix de del_utilisateur sur id_utilisateur = vdi.ce_utilisateur est "du"
305
	 *
305
	 *
306
	 * @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes)
306
	 * @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes)
307
	 * @param $req le tableau, passé par référence représentant les composants de la requête à bâtir
307
	 * @param $req le tableau, passé par référence représentant les composants de la requête à bâtir
308
	 * @param $c conteneur, utilisé soit pour l'appel récursif à requestFilterParams() en cas de param "masque"
308
	 * @param $c conteneur, utilisé soit pour l'appel récursif à requestFilterParams() en cas de param "masque"
309
	 *								soit pour la définition du type (qui utilise la variable nb_commentaires_discussion)
309
	 *								soit pour la définition du type (qui utilise la variable nb_commentaires_discussion)
310
	 */
310
	 */
311
	static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) {
311
	static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) {
312
		if(!empty($p['masque.auteur'])) {
312
		if(!empty($p['masque.auteur'])) {
313
			// id du poster de l'obs
313
			// id du poster de l'obs
314
			$req['join'][] = 'LEFT JOIN del_utilisateur AS du ON du.id_utilisateur = vdi.ce_utilisateur';
314
			$req['join'][] = 'LEFT JOIN del_utilisateur AS du ON du.id_utilisateur = vdi.ce_utilisateur';
315
			// id du poster de l'image... NON, c'est le même que le posteur de l'obs
315
			// id du poster de l'image... NON, c'est le même que le posteur de l'obs
316
			// Cette jointure de table est ignoré ci-dessous pour les recherches d'auteurs
316
			// Cette jointure de table est ignoré ci-dessous pour les recherches d'auteurs
317
			// $req['join'][] = 'LEFT JOIN del_utilisateur AS dui ON dui.id_utilisateur = vdi.i_ce_utilisateur';
317
			// $req['join'][] = 'LEFT JOIN del_utilisateur AS dui ON dui.id_utilisateur = vdi.i_ce_utilisateur';
318
 
318
 
319
			if(is_numeric($p['masque.auteur'])) {
319
			if(is_numeric($p['masque.auteur'])) {
320
				$req['where'][] = sprintf('(du.id_utilisateur = %1$d OR vdi.id_utilisateur = %1$d )', $p['masque.auteur']);
320
				$req['where'][] = sprintf('(du.id_utilisateur = %1$d OR vdi.id_utilisateur = %1$d )', $p['masque.auteur']);
321
			}
321
			}
322
			elseif(preg_match(';^.{5,}@[a-z0-9-.]{5,}$;i', $p['masque.auteur'])) {
322
			elseif(preg_match(';^.{5,}@[a-z0-9-.]{5,}$;i', $p['masque.auteur'])) {
323
				$req['where'][] = sprintf('(du.courriel LIKE %1$s OR vdi.courriel LIKE %1$s )',
323
				$req['where'][] = sprintf('(du.courriel LIKE %1$s OR vdi.courriel LIKE %1$s )',
324
										  $db->proteger($p['masque.auteur'] . '%'));
324
										  $db->proteger($p['masque.auteur'] . '%'));
325
			}
325
			}
326
			else {
326
			else {
327
				self::addAuteursConstraint($p['masque.auteur'], $db, $req['where']);
327
				self::addAuteursConstraint($p['masque.auteur'], $db, $req['where']);
328
			}
328
			}
329
		}
329
		}
330
 
330
 
331
		if(!empty($p['masque.date'])) {
331
		if(!empty($p['masque.date'])) {
332
			if(is_integer($p['masque.date']) && $p['masque.date'] < 2030 && $p['masque.date'] > 1600) {
332
			if(is_integer($p['masque.date']) && $p['masque.date'] < 2030 && $p['masque.date'] > 1600) {
333
				$req['where'][] = sprintf("YEAR(vdi.date_observation) = %d", $p['masque.date']);
333
				$req['where'][] = sprintf("YEAR(vdi.date_observation) = %d", $p['masque.date']);
334
			}
334
			}
335
			else {
335
			else {
336
				$req['where'][] = sprintf("DATE_FORMAT(vdi.date_observation, '%%Y-%%m-%%d') = %s",
336
				$req['where'][] = sprintf("DATE_FORMAT(vdi.date_observation, '%%Y-%%m-%%d') = %s",
337
										  $db->proteger(strftime('%Y-%m-%d', $p['masque.date'])));
337
										  $db->proteger(strftime('%Y-%m-%d', $p['masque.date'])));
338
			}
338
			}
339
		}
339
		}
340
 
340
 
341
		// TODO: avoir des champs d'entrée distinct
341
		// TODO: avoir des champs d'entrée distinct
342
		if(!empty($p['masque.departement'])) {
342
		if(!empty($p['masque.departement'])) {
343
			$req['where'][] = sprintf("vdi.ce_zone_geo = %s", $db->proteger('INSEE-C:'.$p['masque.departement']));
343
			$req['where'][] = sprintf("vdi.ce_zone_geo = %s", $db->proteger('INSEE-C:'.$p['masque.departement']));
344
		}
344
		}
345
		if(!empty($p['masque.id_zone_geo'])) {
345
		if(!empty($p['masque.id_zone_geo'])) {
346
			$req['where'][] = sprintf("vdi.ce_zone_geo = %s", $db->proteger($p['masque.id_zone_geo']));
346
			$req['where'][] = sprintf("vdi.ce_zone_geo = %s", $db->proteger($p['masque.id_zone_geo']));
347
		}
347
		}
348
		if(!empty($p['masque.genre'])) {
348
		if(!empty($p['masque.genre'])) {
349
			$req['where'][] = 'vdi.nom_sel LIKE '.$db->proteger('%' . $p['masque.genre'].'% %');
349
			$req['where'][] = 'vdi.nom_sel LIKE '.$db->proteger('%' . $p['masque.genre'].'% %');
350
		}
350
		}
351
		if(!empty($p['masque.famille'])) {
351
		if(!empty($p['masque.famille'])) {
352
			$req['where'][] = 'vdi.famille = '.$db->proteger($p['masque.famille']);
352
			$req['where'][] = 'vdi.famille = '.$db->proteger($p['masque.famille']);
353
		}
353
		}
354
		if(!empty($p['masque.ns'])) {
354
		if(!empty($p['masque.ns'])) {
355
			$req['where'][] = 'vdi.nom_sel LIKE '.$db->proteger($p['masque.ns'].'%');
355
			$req['where'][] = 'vdi.nom_sel LIKE '.$db->proteger($p['masque.ns'].'%');
356
		}
356
		}
357
		if(!empty($p['masque.nn'])) {
357
		if(!empty($p['masque.nn'])) {
358
			$req['where'][] = sprintf('vdi.nom_sel_nn = %1$d OR vdi.nom_ret_nn = %1$d', $p['masque.nn']);
358
			$req['where'][] = sprintf('vdi.nom_sel_nn = %1$d OR vdi.nom_ret_nn = %1$d', $p['masque.nn']);
359
		}
359
		}
360
		if(!empty($p['masque.referentiel'])) {
360
		if(!empty($p['masque.referentiel'])) {
361
			$req['where'][] = sprintf('vdi.nom_referentiel LIKE %s', $db->proteger($p['masque.referentiel'].'%'));
361
			$req['where'][] = sprintf('vdi.nom_referentiel LIKE %s', $db->proteger($p['masque.referentiel'].'%'));
362
		}
362
		}
363
		if(!empty($p['masque.commune'])) {
363
		if(!empty($p['masque.commune'])) {
364
			$req['where'][] = 'vdi.zone_geo LIKE '.$db->proteger($p['masque.commune'].'%');
364
			$req['where'][] = 'vdi.zone_geo LIKE '.$db->proteger($p['masque.commune'].'%');
365
		}
365
		}
366
		if(!empty($p['masque.tag'])) {
366
		if(!empty($p['masque.tag'])) {
367
			// i_mots_cles_texte provient de la VIEW v_del_image
367
			// i_mots_cles_texte provient de la VIEW v_del_image
368
			// TODO: remove LOWER() lorsqu'on est sur que les tags sont uniformés en minuscule
368
			// TODO: remove LOWER() lorsqu'on est sur que les tags sont uniformés en minuscule
369
			$req['where'][] = sprintf('LOWER(CONCAT(%s)) REGEXP %s',
369
			$req['where'][] = sprintf('LOWER(CONCAT(%s)) REGEXP %s',
370
									  self::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')),
370
									  self::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')),
371
									  $db->proteger(strtolower($p['masque.tag'])));
371
									  $db->proteger(strtolower($p['masque.tag'])));
372
		}
372
		}
373
 
373
 
374
		if(!empty($p['masque.type'])) {
374
		if(!empty($p['masque.type'])) {
375
			self::addTypeConstraints($p['masque.type'], $db, $req, $c);
375
			self::addTypeConstraints($p['masque.type'], $db, $req, $c);
376
		}
376
		}
377
	}
377
	}
378
 
378
 
379
	/* Le masque fait une recherche générique parmi de nombreux champs ci-dessus.
379
	/* Le masque fait une recherche générique parmi de nombreux champs ci-dessus.
380
	   Nous initialisons donc ces paramètres (excepté masque biensur), et nous rappelons
380
	   Nous initialisons donc ces paramètres (excepté masque biensur), et nous rappelons
381
	   récursivement. À la seule différence que nous n'utiliserons que $or_req['where']
381
	   récursivement. À la seule différence que nous n'utiliserons que $or_req['where']
382
	   imploded par des " OR ". */
382
	   imploded par des " OR ". */
383
	static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
383
	static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
384
		if(!empty($p['masque'])) {
384
		if(!empty($p['masque'])) {
385
			$or_params = array('masque.auteur' => $p['masque'],
385
			$or_params = array('masque.auteur' => $p['masque'],
386
							   'masque.departement' => $p['masque'],
386
							   'masque.departement' => $p['masque'],
387
							   'masque.id_zone_geo' => $p['masque'],
387
							   'masque.id_zone_geo' => $p['masque'],
388
							   'masque.tag' => $p['masque'],
388
							   'masque.tag' => $p['masque'],
389
							   'masque.ns' => $p['masque'],
389
							   'masque.ns' => $p['masque'],
390
							   'masque.famille' => $p['masque'],
390
							   'masque.famille' => $p['masque'],
391
							   'masque.date' => $p['masque'],
391
							   'masque.date' => $p['masque'],
392
							   'masque.genre' => $p['masque'],
392
							   'masque.genre' => $p['masque'],
393
							   /* milieu: TODO ? */ );
393
							   /* milieu: TODO ? */ );
394
			$or_masque = self::requestFilterParams($or_params, array_keys($or_params), $c);
394
			$or_masque = self::requestFilterParams($or_params, array_keys($or_params), $c);
395
			// $or_req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array());
395
			// $or_req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array());
396
			$or_req = array('join' => array(), 'where' => array());
396
			$or_req = array('join' => array(), 'where' => array());
397
			self::sqlAddConstraint($or_masque, $db, $or_req);
397
			self::sqlAddConstraint($or_masque, $db, $or_req);
398
 
398
 
399
			if($or_req['where']) {
399
			if($or_req['where']) {
400
				$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')';
400
				$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')';
401
				// utile au cas ou des jointures seraient rajoutées
401
				// utile au cas ou des jointures seraient rajoutées
402
				$req['join'] = array_unique(array_merge($req['join'], $or_req['join']));
402
				$req['join'] = array_unique(array_merge($req['join'], $or_req['join']));
403
			}
403
			}
404
		}
404
		}
405
	}
405
	}
406
 
406
 
407
 
407
 
408
	private function configurer() {
408
	private function configurer() {
409
		$this->mappingFiltre = $this->conteneur->getParametre('mapping_masque');
-
 
410
		$this->mappingObservation = $this->conteneur->getParametre('mapping_observation');
-
 
411
		$this->mappingVotes = $this->conteneur->getParametre('mapping_votes');
409
		$this->mappingVotes = $this->conteneur->getParametre('mapping_votes');
412
		$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire');
410
		$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire');
413
	}
411
	}
414
 
412
 
415
 
413
 
416
 
414
 
417
	/* Lorsque l'on concatène des champs, un seul NULL prend le dessus,
415
	/* Lorsque l'on concatène des champs, un seul NULL prend le dessus,
418
	   Il faut donc utiliser la syntaxe IFNULL(%s, "").
416
	   Il faut donc utiliser la syntaxe IFNULL(%s, "").
419
	   (Cette fonction effectue aussi l'implode() "final" */
417
	   (Cette fonction effectue aussi l'implode() "final" */
420
	static function sqlAddIfNullPourConcat($tab) {
418
	static function sqlAddIfNullPourConcat($tab) {
421
		// XXX: PHP-5.3
419
		// XXX: PHP-5.3
422
		return implode(',',array_map(create_function('$a', 'return "IFNULL($a, \"\")";'), $tab));
420
		return implode(',',array_map(create_function('$a', 'return "IFNULL($a, \"\")";'), $tab));
423
	}
421
	}
424
 
422
 
425
	/*
423
	/*
426
	  Retourne une clausse where du style:
424
	  Retourne une clausse where du style:
427
	  CONCAT(IF(du.prenom IS NULL, "", du.prenom), [...] vdi.i_nomutilisateur) REGEXP 'xxx'
425
	  CONCAT(IF(du.prenom IS NULL, "", du.prenom), [...] vdi.i_nomutilisateur) REGEXP 'xxx'
428
	  Note; i_(nom|prenom_utilisateur), alias pour cel_images.(nom|prenom), n'est pas traité
426
	  Note; i_(nom|prenom_utilisateur), alias pour cel_images.(nom|prenom), n'est pas traité
429
	  car cette information est redondante dans cel_image et devrait être supprimée.
427
	  car cette information est redondante dans cel_image et devrait être supprimée.
430
	*/
428
	*/
431
	static function addAuteursConstraint($val, $db, &$where) {
429
	static function addAuteursConstraint($val, $db, &$where) {
432
		@list($a, $b) = explode(' ', $val, 2);
430
		@list($a, $b) = explode(' ', $val, 2);
433
		// un seul terme
431
		// un seul terme
434
		$champs_n = array('du.prenom', // info user authentifié de l'obs depuis l'annuaire
432
		$champs_n = array('du.prenom', // info user authentifié de l'obs depuis l'annuaire
435
						  'vdi.prenom_utilisateur', // info user anonyme de l'obs
433
						  'vdi.prenom_utilisateur', // info user anonyme de l'obs
436
						  /* 'vdi.i_prenom_utilisateur' */ ); // info user anonyme de l'image
434
						  /* 'vdi.i_prenom_utilisateur' */ ); // info user anonyme de l'image
437
		$champs_p = array('du.nom', // idem pour le nom
435
		$champs_p = array('du.nom', // idem pour le nom
438
						  'vdi.nom_utilisateur',
436
						  'vdi.nom_utilisateur',
439
						  /* 'vdi.i_nom_utilisateur' */ );
437
						  /* 'vdi.i_nom_utilisateur' */ );
440
 
438
 
441
		/*
439
		/*
442
		  Note: pour l'heure, étant donnés:
440
		  Note: pour l'heure, étant donnés:
443
		  - les CONVERT() de la VIEW del_utilisateur
441
		  - les CONVERT() de la VIEW del_utilisateur
444
		  - DEFAULT CHARSET=latin1 pour tela_prod_v4.annuaire_tela
442
		  - DEFAULT CHARSET=latin1 pour tela_prod_v4.annuaire_tela
445
		  - DEFAULT CHARSET=utf8 pour tb_cel.cel_obs
443
		  - DEFAULT CHARSET=utf8 pour tb_cel.cel_obs
446
		  et l'âge du capitaine...
444
		  et l'âge du capitaine...
447
		  - REGEXP est case-sensitive, et collate les caractères accentués
445
		  - REGEXP est case-sensitive, et collate les caractères accentués
448
		  - LIKE est case-insensitive, et collate les caractères accentués
446
		  - LIKE est case-insensitive, et collate les caractères accentués
449
		 */
447
		 */
450
		if(! $b) {
448
		if(! $b) {
451
			$where[] = sprintf('CONCAT(%s,%s) LIKE %s',
449
			$where[] = sprintf('CONCAT(%s,%s) LIKE %s',
452
							   self::sqlAddIfNullPourConcat($champs_n),
450
							   self::sqlAddIfNullPourConcat($champs_n),
453
							   self::sqlAddIfNullPourConcat($champs_p),
451
							   self::sqlAddIfNullPourConcat($champs_p),
454
							   $db->proteger("%".$val."%"));
452
							   $db->proteger("%".$val."%"));
455
		}
453
		}
456
		else {
454
		else {
457
			$where[] = sprintf('CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s ',
455
			$where[] = sprintf('CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s ',
458
							   self::sqlAddIfNullPourConcat($champs_n),
456
							   self::sqlAddIfNullPourConcat($champs_n),
459
							   self::sqlAddIfNullPourConcat($champs_p),
457
							   self::sqlAddIfNullPourConcat($champs_p),
460
							   $db->proteger("%" . $a . "%"), $db->proteger("%" . $b . "%"));
458
							   $db->proteger("%" . $a . "%"), $db->proteger("%" . $b . "%"));
461
		}
459
		}
462
	}
460
	}
463
 
461
 
464
	/*
462
	/*
465
	 * @param $req: la représentation de la requête MySQL complète, à amender.
463
	 * @param $req: la représentation de la requête MySQL complète, à amender.
466
	 */
464
	 */
467
	static function addTypeConstraints($val, $db, &$req, Conteneur $c) {
465
	static function addTypeConstraints($val, $db, &$req, Conteneur $c) {
468
		if(array_key_exists('adeterminer', $val)) {
466
		if(array_key_exists('adeterminer', $val)) {
469
			//On récupère toutes les observations qui on le tag "aDeterminer" *ou* qui n'ont pas de nom d'espèce
467
			//On récupère toutes les observations qui on le tag "aDeterminer" *ou* qui n'ont pas de nom d'espèce
470
			$req['where'][] = '(' . implode(' OR ', array(
468
			$req['where'][] = '(' . implode(' OR ', array(
471
				'vdi.certitude = "aDeterminer"',
469
				'vdi.certitude = "aDeterminer"',
472
				'vdi.mots_cles_texte LIKE "%aDeterminer%"',
470
				'vdi.mots_cles_texte LIKE "%aDeterminer%"',
473
				'vdi.nom_sel_nn IS NULL', // TODO: ensure pas d'entrée à 0
471
				'vdi.nom_sel_nn IS NULL', // TODO: ensure pas d'entrée à 0
474
			)) . ')';
472
			)) . ')';
475
		}
473
		}
476
		if(array_key_exists('aconfirmer', $val)) {
474
		if(array_key_exists('aconfirmer', $val)) {
477
			//On récupère toutes les observations qui ne sont pas "aDeterminer" *et* qui ont un nom d'espèce
475
			//On récupère toutes les observations qui ne sont pas "aDeterminer" *et* qui ont un nom d'espèce
478
			$req['where'][] = '(' . implode(' AND ', array(
476
			$req['where'][] = '(' . implode(' AND ', array(
479
				'vdi.nom_sel IS NOT NULL',
477
				'vdi.nom_sel IS NOT NULL',
480
				'vdi.certitude != "aDeterminer"',
478
				'vdi.certitude != "aDeterminer"',
481
				'(vdi.mots_cles_texte IS NULL OR vdi.mots_cles_texte NOT LIKE "%aDeterminer%"',
479
				'(vdi.mots_cles_texte IS NULL OR vdi.mots_cles_texte NOT LIKE "%aDeterminer%"',
482
			)) . ')';
480
			)) . ')';
483
		}
481
		}
484
		if(array_key_exists('validees', $val)) {
482
		if(array_key_exists('validees', $val)) {
485
			//On récupère toutes les observations ayant un commentaire doté de proposition_retenue = 1
483
			//On récupère toutes les observations ayant un commentaire doté de proposition_retenue = 1
486
			$req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation AND dc.proposition_retenue = 1';
484
			$req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation AND dc.proposition_retenue = 1';
487
		}
485
		}
488
 
486
 
489
		// solution n°1: impraticable
487
		// solution n°1: impraticable
490
		if(false && array_key_exists('endiscussion', $val)) {
488
		if(false && array_key_exists('endiscussion', $val)) {
491
			//Si on veut les observations en discussion,
489
			//Si on veut les observations en discussion,
492
			// on va récupérer les ids des observations dont le nombre de commentaire est supérieur à N
490
			// on va récupérer les ids des observations dont le nombre de commentaire est supérieur à N
493
			$req['select'][] = 'COUNT(dc.id_commentaire) AS comm_count';
491
			$req['select'][] = 'COUNT(dc.id_commentaire) AS comm_count';
494
			$req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation';
492
			$req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation';
495
			$req['groupby'][] = 'vdi.id_observation';
493
			$req['groupby'][] = 'vdi.id_observation';
496
			$req['having'][] = "COUNT(id_commentaire) > " . $c->getParametre('nb_commentaires_discussion');
494
			$req['having'][] = "COUNT(id_commentaire) > " . $c->getParametre('nb_commentaires_discussion');
497
		}
495
		}
498
 
496
 
499
		if(array_key_exists('endiscussion', $val)) {
497
		if(array_key_exists('endiscussion', $val)) {
500
			$req['where'][] = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc'.
498
			$req['where'][] = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc'.
501
				' WHERE ce_observation = id_observation) > ' . intval($c->getParametre('nb_commentaires_discussion'));
499
				' WHERE ce_observation = id_observation) > ' . intval($c->getParametre('nb_commentaires_discussion'));
502
		}
500
		}
503
	}
501
	}
504
 
502
 
505
 
503
 
506
	/**
504
	/**
507
	* Récupérer toutes les déterminations et le nombre de commentaire au total
505
	* Récupérer toutes les déterminations et le nombre de commentaire au total
508
	* @param array $observations la liste des observations à mettre à jour
506
	* @param array $observations la liste des observations à mettre à jour
509
	* */
507
	* */
510
	private function chargerDeterminations(&$observations) {
508
	private function chargerDeterminations(&$observations) {
511
		$idObs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'),
509
		$idObs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'),
512
									$observations));
510
									$observations));
513
		$r = sprintf('SELECT * FROM del_commentaire AS dc WHERE dc.nom_sel IS NOT NULL AND ce_observation IN (%s) -- %s',
511
		$r = sprintf('SELECT * FROM del_commentaire AS dc WHERE dc.nom_sel IS NOT NULL AND ce_observation IN (%s) -- %s',
514
					 implode(',',$idObs),
512
					 implode(',',$idObs),
515
					 __FILE__ . ':' . __LINE__);
513
					 __FILE__ . ':' . __LINE__);
516
		$propositions = $this->bdd->recupererTous($r);
514
		$propositions = $this->bdd->recupererTous($r);
517
		if(!$propositions) return;
515
		if(!$propositions) return;
518
		foreach ($propositions as $proposition) {
516
		foreach ($propositions as $proposition) {
519
			$idObs = $proposition['ce_observation'];
517
			$idObs = $proposition['ce_observation'];
520
			$idComment = $proposition['id_commentaire'];
518
			$idComment = $proposition['id_commentaire'];
521
			$comment = $this->formaterDetermination($idComment, $proposition);
519
			$comment = $this->formaterDetermination($idComment, $proposition);
522
			if($comment) $observations['"' . $idObs . '"']['commentaires'][$idComment] = $comment;
520
			if($comment) $observations['"' . $idObs . '"']['commentaires'][$idComment] = $comment;
523
				
521
				
524
		}
522
		}
525
	}
523
	}
526
 
524
 
527
	private function formaterDetermination($commentId, $proposition) {
525
	private function formaterDetermination($commentId, $proposition) {
528
		if(!$proposition) return NULL;
526
		if(!$proposition) return NULL;
529
 
527
 
530
		$proposition_formatee = array('nb_commentaires' => '0');
528
		$proposition_formatee = array('nb_commentaires' => '0');
531
		foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) {
529
		foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) {
532
			if (isset($proposition[$nomOriginal])) {
530
			if (isset($proposition[$nomOriginal])) {
533
				$proposition_formatee[$nomFinal] = $proposition[$nomOriginal];
531
				$proposition_formatee[$nomFinal] = $proposition[$nomOriginal];
534
			}
532
			}
535
		}
533
		}
536
 
534
 
537
		// Charger les votes sur les déterminations
535
		// Charger les votes sur les déterminations
538
		$resultatsVotes = $this->bdd->recupererTous(
536
		$resultatsVotes = $this->bdd->recupererTous(
539
			sprintf('SELECT * FROM del_commentaire_vote WHERE ce_proposition = %d', $commentId));
537
			sprintf('SELECT * FROM del_commentaire_vote WHERE ce_proposition = %d', $commentId));
540
		
538
		
541
		foreach ($resultatsVotes as $vote) {
539
		foreach ($resultatsVotes as $vote) {
542
			$proposition_formatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);
540
			$proposition_formatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);
543
		}
541
		}
544
 
542
 
545
 
543
 
546
		// chargerNombreCommentaire()
544
		// chargerNombreCommentaire()
547
		// Charger le nombre de commentaires (sans détermination) associé à l'observation
545
		// Charger le nombre de commentaires (sans détermination) associé à l'observation
548
		$listeCommentaires = $this->bdd->recupererTous(sprintf(
546
		$listeCommentaires = $this->bdd->recupererTous(sprintf(
549
			'SELECT ce_commentaire_parent, ce_proposition, COUNT( id_commentaire ) AS nb '.
547
			'SELECT ce_commentaire_parent, ce_proposition, COUNT( id_commentaire ) AS nb '.
550
			'FROM del_commentaire WHERE ce_proposition = %d GROUP BY ce_proposition -- %s',
548
			'FROM del_commentaire WHERE ce_proposition = %d GROUP BY ce_proposition -- %s',
551
			$commentId, __FILE__ . ':' . __LINE__));
549
			$commentId, __FILE__ . ':' . __LINE__));
552
		foreach ($listeCommentaires as $ligneProposition) {
550
		foreach ($listeCommentaires as $ligneProposition) {
553
			// ce test sert à exclure les proposition de 1er niveau qui sont elles aussi des commentaires
551
			// ce test sert à exclure les proposition de 1er niveau qui sont elles aussi des commentaires
554
			if($ligneProposition['ce_commentaire_parent']) {
552
			if($ligneProposition['ce_commentaire_parent']) {
555
				// TODO/debug: id_commentaire_parent != $commentId ??
553
				// TODO/debug: id_commentaire_parent != $commentId ??
556
				// reprendre la "logique" du code... moins de boucles, moins de requêtes, ...
554
				// reprendre la "logique" du code... moins de boucles, moins de requêtes, ...
557
				if($ligneProposition['ce_commentaire_parent'] != $commentId) {
555
				if($ligneProposition['ce_commentaire_parent'] != $commentId) {
558
					// restore_error_handler();
556
					// restore_error_handler();
559
					error_log(sprintf("possible error: nb_commentaires = %s: comment = %d, parent = %d, %s",
557
					error_log(sprintf("possible error: nb_commentaires = %s: comment = %d, parent = %d, %s",
560
									  $ligneProposition['nb'], $commentId, $ligneProposition['ce_commentaire_parent'], __FILE__));
558
									  $ligneProposition['nb'], $commentId, $ligneProposition['ce_commentaire_parent'], __FILE__));
561
				}
559
				}
562
				$proposition_formatee['nb_commentaires'] = $ligneProposition['nb'];
560
				$proposition_formatee['nb_commentaires'] = $ligneProposition['nb'];
563
			} else {
561
			} else {
564
				$proposition_formatee['observation']['nb_commentaires'] = $ligneProposition['nb'];
562
				$proposition_formatee['observation']['nb_commentaires'] = $ligneProposition['nb'];
565
			}
563
			}
566
		}
564
		}
567
 
565
 
568
		return $proposition_formatee;
566
		return $proposition_formatee;
569
	}
567
	}
570
 
568
 
571
	/**
569
	/**
572
	*  Formater un vote en fonction du fichier de configuration config_votes.ini
570
	*  Formater un vote en fonction du fichier de configuration config_votes.ini
573
	*  @param $votes array()
571
	*  @param $votes array()
574
	* */
572
	* */
575
	private function formaterVote($vote) {
573
	private function formaterVote($vote) {
576
		$retour = array();
574
		$retour = array();
577
		foreach ($vote as $param=>$valeur) {
575
		foreach ($vote as $param=>$valeur) {
578
			$retour[$this->mappingVotes[$param]] = $valeur;
576
			$retour[$this->mappingVotes[$param]] = $valeur;
579
		}
577
		}
580
		return $retour;
578
		return $retour;
581
	}
579
	}
582
 
580
 
583
 
581
 
584
	// supprime l'index du tableau des paramètres si sa valeur ne correspond pas
582
	// supprime l'index du tableau des paramètres si sa valeur ne correspond pas
585
	// au spectre passé par $values.
583
	// au spectre passé par $values.
586
	static function unsetIfInvalid(&$var, $index, $values) {
584
	static function unsetIfInvalid(&$var, $index, $values) {
587
		if(array_key_exists($index, $var)) {
585
		if(array_key_exists($index, $var)) {
588
			if(!in_array($var[$index], $values)) unset($var[$index]);
586
			if(!in_array($var[$index], $values)) unset($var[$index]);
589
			else return $var[$index];
587
			else return $var[$index];
590
		}
588
		}
591
		return NULL;
589
		return NULL;
592
	}
590
	}
593
 
591
 
594
 
592
 
595
	/* Filtre et valide les paramètres reconnus. Effectue *toute* la sanitization *sauf* l'escape-string
593
	/* Filtre et valide les paramètres reconnus. Effectue *toute* la sanitization *sauf* l'escape-string
596
	   Cette fonction est appelée:
594
	   Cette fonction est appelée:
597
	   - une fois sur les champs de recherche avancées
595
	   - une fois sur les champs de recherche avancées
598
	   - une fois sur le masque général si celui-ci à été spécifié. Dans ce cas,
596
	   - une fois sur le masque général si celui-ci à été spécifié. Dans ce cas,
599
	   la chaîne générale saisie est utilisée comme valeur pour chacun des champs particuliers
597
	   la chaîne générale saisie est utilisée comme valeur pour chacun des champs particuliers
600
	   avec les traitements particuliers qui s'imposent
598
	   avec les traitements particuliers qui s'imposent
601
	   Par exemple: si l'on cherche "Languedoc", cela impliquera:
599
	   Par exemple: si l'on cherche "Languedoc", cela impliquera:
602
	   WHERE (nom_sel like "Languedoc" OR nom_ret ... OR ...) mais pas masque.date ou masque.departement
600
	   WHERE (nom_sel like "Languedoc" OR nom_ret ... OR ...) mais pas masque.date ou masque.departement
603
	   qui s'assure d'un pattern particulier */
601
	   qui s'assure d'un pattern particulier */
604
	static function requestFilterParams(Array $params, $parametres_autorises = NULL, Conteneur $c = NULL /* pour la récup des départements */ ) {
602
	static function requestFilterParams(Array $params, $parametres_autorises = NULL, Conteneur $c = NULL /* pour la récup des départements */ ) {
605
		if($parametres_autorises) { // filtrage de toute clef inconnue
603
		if($parametres_autorises) { // filtrage de toute clef inconnue
606
			$params = array_intersect_key($params, array_flip($parametres_autorises));
604
			$params = array_intersect_key($params, array_flip($parametres_autorises));
607
		}
605
		}
608
 
606
 
609
		$p['tri'] = self::unsetIfInvalid($params, 'tri', array('date_observation'));
607
		$p['tri'] = self::unsetIfInvalid($params, 'tri', array('date_observation'));
610
		$p['ordre'] = self::unsetIfInvalid($params, 'ordre', array('asc','desc'));
608
		$p['ordre'] = self::unsetIfInvalid($params, 'ordre', array('asc','desc'));
611
		$p['masque.referentiel'] = self::unsetIfInvalid($params, 'masque.referentiel', array('bdtfx','bdtxa','isfan'));
609
		$p['masque.referentiel'] = self::unsetIfInvalid($params, 'masque.referentiel', array('bdtfx','bdtxa','isfan'));
612
 
610
 
613
		// TODO: use filter_input(INPUT_GET);
611
		// TODO: use filter_input(INPUT_GET);
614
		// renvoie FALSE ou NULL si absent ou invalide
612
		// renvoie FALSE ou NULL si absent ou invalide
615
		$p['navigation.limite'] = filter_var(@$params['navigation.limite'],
613
		$p['navigation.limite'] = filter_var(@$params['navigation.limite'],
616
											 FILTER_VALIDATE_INT,
614
											 FILTER_VALIDATE_INT,
617
											 array('options' => array('default' => NULL,
615
											 array('options' => array('default' => NULL,
618
																	  'min_range' => 1,
616
																	  'min_range' => 1,
619
																	  'max_range' => _LISTE_OBS_MAX_RESULT_LIMIT)));
617
																	  'max_range' => _LISTE_OBS_MAX_RESULT_LIMIT)));
620
		$p['navigation.depart'] = filter_var(@$params['navigation.depart'],
618
		$p['navigation.depart'] = filter_var(@$params['navigation.depart'],
621
											 FILTER_VALIDATE_INT,
619
											 FILTER_VALIDATE_INT,
622
											 array('options' => array('default' => NULL,
620
											 array('options' => array('default' => NULL,
623
																	  'min_range' => 0,
621
																	  'min_range' => 0,
624
																	  'max_range' => _LISTE_OBS_MAX_ID_OBS)));
622
																	  'max_range' => _LISTE_OBS_MAX_ID_OBS)));
625
		if(isset($params['masque.departement'])) {
623
		if(isset($params['masque.departement'])) {
626
			// STRING: 0 -> 95, 971 -> 976, 2A + 2B (./services/configurations/config_departements_bruts.ini)
624
			// STRING: 0 -> 95, 971 -> 976, 2A + 2B (./services/configurations/config_departements_bruts.ini)
627
			// accept leading 0 ?
625
			// accept leading 0 ?
628
			// TODO; filter patterns like 555.
626
			// TODO; filter patterns like 555.
629
			if(preg_match(';^(\d{2}|\d{3}|2a|2b)$;i', $params['masque.departement'])) {
627
			if(preg_match(';^(\d{2}|\d{3}|2a|2b)$;i', $params['masque.departement'])) {
630
				$p['masque.departement'] = $params['masque.departement'];
628
				$p['masque.departement'] = $params['masque.departement'];
631
			}
629
			}
632
			// cf configurations/config_departements_bruts.ini
630
			// cf configurations/config_departements_bruts.ini
633
			elseif( !is_null($c) && ( $x = $c->getParametre(
631
			elseif( !is_null($c) && ( $x = $c->getParametre(
634
				strtolower(str_replace(' ','-',iconv("UTF-8", "ASCII//TRANSLIT", $params['masque.departement'])))
632
				strtolower(str_replace(' ','-',iconv("UTF-8", "ASCII//TRANSLIT", $params['masque.departement'])))
635
			))) {
633
			))) {
636
				$p['masque.departement'] = sprintf("INSEE-C:%02d___", $x);
634
				$p['masque.departement'] = sprintf("INSEE-C:%02d___", $x);
637
			}
635
			}
638
		}
636
		}
639
 
637
 
640
		if(isset($params['masque.date'])) {
638
		if(isset($params['masque.date'])) {
641
			// une année, TODO: masque.annee
639
			// une année, TODO: masque.annee
642
			if(is_numeric($params['masque.date'])) {
640
			if(is_numeric($params['masque.date'])) {
643
				$p['masque.date'] = $params['masque.date'];
641
				$p['masque.date'] = $params['masque.date'];
644
			}
642
			}
645
			elseif(strpos($params['masque.date'], '/' !== false) &&
643
			elseif(strpos($params['masque.date'], '/' !== false) &&
646
				   ($x = strtotime(str_replace('/','-',$params['masque.date'])))) {
644
				   ($x = strtotime(str_replace('/','-',$params['masque.date'])))) {
647
				$p['masque.date'] = $x;
645
				$p['masque.date'] = $x;
648
			}
646
			}
649
			elseif(strpos($params['masque.date'], '-' !== false) &&
647
			elseif(strpos($params['masque.date'], '-' !== false) &&
650
				   ($x = strtotime($params['masque.date'])) ) {
648
				   ($x = strtotime($params['masque.date'])) ) {
651
				$p['masque.date'] = $x;
649
				$p['masque.date'] = $x;
652
			}
650
			}
653
		}
651
		}
654
 
652
 
655
		$p['masque.nn'] = filter_var(@$params['masque.nn'],
653
		$p['masque.nn'] = filter_var(@$params['masque.nn'],
656
									 FILTER_VALIDATE_INT,
654
									 FILTER_VALIDATE_INT,
657
									 array('options' => array('default' => NULL,
655
									 array('options' => array('default' => NULL,
658
															  'min_range' => 0,
656
															  'min_range' => 0,
659
															  'max_range' => _LISTE_OBS_MAX_BDTFX_NN)));
657
															  'max_range' => _LISTE_OBS_MAX_BDTFX_NN)));
660
 
658
 
661
		$p['masque.nt'] = filter_var(@$params['masque.nt'],
659
		$p['masque.nt'] = filter_var(@$params['masque.nt'],
662
									 FILTER_VALIDATE_INT,
660
									 FILTER_VALIDATE_INT,
663
									 array('options' => array('default' => NULL,
661
									 array('options' => array('default' => NULL,
664
															  'min_range' => 0,
662
															  'min_range' => 0,
665
															  'max_range' => _LISTE_OBS_MAX_BDTFX_NT)));
663
															  'max_range' => _LISTE_OBS_MAX_BDTFX_NT)));
666
 
664
 
667
 
665
 
668
		// TODO: should we really trim() ?
666
		// TODO: should we really trim() ?
669
 
667
 
670
		if(isset($params['masque.ns'])) $p['masque.ns'] = trim($params['masque.ns']);
668
		if(isset($params['masque.ns'])) $p['masque.ns'] = trim($params['masque.ns']);
671
		// if(isset($params['masque.texte'])) $p['masque.texte'] = trim($params['masque.texte']);
669
		// if(isset($params['masque.texte'])) $p['masque.texte'] = trim($params['masque.texte']);
672
 
670
 
673
		if(isset($params['masque.famille'])) {
671
		if(isset($params['masque.famille'])) {
674
			// mysql -N<<<"SELECT DISTINCT famille FROM bdtfx_v1_02;"|sed -r "s/(.)/\1\n/g"|sort -u|tr -d "\n"
672
			// mysql -N<<<"SELECT DISTINCT famille FROM bdtfx_v1_02;"|sed -r "s/(.)/\1\n/g"|sort -u|tr -d "\n"
675
			$p['masque.famille'] = preg_replace('/[^a-zA-Z %_]/', '', iconv("UTF-8",
673
			$p['masque.famille'] = preg_replace('/[^a-zA-Z %_]/', '', iconv("UTF-8",
676
																			"ASCII//TRANSLIT",
674
																			"ASCII//TRANSLIT",
677
																			$params['masque.famille']));
675
																			$params['masque.famille']));
678
		}
676
		}
679
 
677
 
680
		// masque.genre est un alias pour masque.ns (nom_sel), mais permet de rajouter une clause supplémentaire
678
		// masque.genre est un alias pour masque.ns (nom_sel), mais permet de rajouter une clause supplémentaire
681
		// sur nom_sel. Précédemment: WHERE nom_sel LIKE '%<masque.genre>% %'.
679
		// sur nom_sel. Précédemment: WHERE nom_sel LIKE '%<masque.genre>% %'.
682
		// Désormais masque.genre doit être intégralement spécifié, les caractères '%' et '_' seront interprétés.
680
		// Désormais masque.genre doit être intégralement spécifié, les caractères '%' et '_' seront interprétés.
683
		// Attention toutefois car la table del_observation intègre des nom_sel contenant '_'
681
		// Attention toutefois car la table del_observation intègre des nom_sel contenant '_'
684
		if(isset($params['masque.genre'])) $p['masque.genre'] = trim($params['masque.genre']);
682
		if(isset($params['masque.genre'])) $p['masque.genre'] = trim($params['masque.genre']);
685
		if(isset($params['masque.ns'])) $p['masque.ns'] = trim($params['masque.ns']);
683
		if(isset($params['masque.ns'])) $p['masque.ns'] = trim($params['masque.ns']);
686
		// masque.espece n'était pas déclaré dans la "where" mais utilisé via config + switch//default
684
		// masque.espece n'était pas déclaré dans la "where" mais utilisé via config + switch//default
687
		if(isset($params['masque.espece'])) $p['masque.espece'] = trim($params['masque.espece']);
685
		if(isset($params['masque.espece'])) $p['masque.espece'] = trim($params['masque.espece']);
688
 
686
 
689
		// idem pour id_zone_geo qui mappait à ce_zone_geo:
687
		// idem pour id_zone_geo qui mappait à ce_zone_geo:
690
		if(isset($params['masque.id_zone_geo']) && preg_match(';^(INSEE-C:\d{5}|\d{2})$;', $params['masque.id_zone_geo'])) {
688
		if(isset($params['masque.id_zone_geo']) && preg_match(';^(INSEE-C:\d{5}|\d{2})$;', $params['masque.id_zone_geo'])) {
691
			$p['masque.id_zone_geo'] = $params['masque.id_zone_geo'];
689
			$p['masque.id_zone_geo'] = $params['masque.id_zone_geo'];
692
		}
690
		}
693
 
691
 
694
		// masque.commune (zone_geo)
692
		// masque.commune (zone_geo)
695
		// TODO: que faire avec des '%' en INPUT ?
693
		// TODO: que faire avec des '%' en INPUT ?
696
		// Le masque doit *permettre* une regexp et non l'imposer. Charge au client de faire son travail
694
		// Le masque doit *permettre* une regexp et non l'imposer. Charge au client de faire son travail
697
		if(isset($params['masque.commune'])) $p['masque.commune'] = str_replace(array('-',' '), '_', $params['masque.commune']);
695
		if(isset($params['masque.commune'])) $p['masque.commune'] = str_replace(array('-',' '), '_', $params['masque.commune']);
698
 
696
 
699
		// masque.auteur: peut-être un id, un courriel, ou un nom ou prénom, ...
697
		// masque.auteur: peut-être un id, un courriel, ou un nom ou prénom, ...
700
		if(isset($params['masque.auteur'])) $p['masque.auteur'] = trim($params['masque.auteur']);
698
		if(isset($params['masque.auteur'])) $p['masque.auteur'] = trim($params['masque.auteur']);
701
		// sera trimmé plus tard, cf sqlAddConstraint
699
		// sera trimmé plus tard, cf sqlAddConstraint
702
		if(isset($params['masque'])) $p['masque'] = trim($params['masque']);
700
		if(isset($params['masque'])) $p['masque'] = trim($params['masque']);
703
 
701
 
704
		// masque.tag, idem que pour masque.genre et masque.commune
702
		// masque.tag, idem que pour masque.genre et masque.commune
705
		if(isset($params['masque.tag'])) {
703
		if(isset($params['masque.tag'])) {
706
			$x = explode(',',$params['masque.tag']);
704
			$x = explode(',',$params['masque.tag']);
707
			$x = array_map('trim', $x);
705
			$x = array_map('trim', $x);
708
			$p['masque.tag'] = implode('|', array_filter($x));
706
			$p['masque.tag'] = implode('|', array_filter($x));
709
		}
707
		}
710
 
708
 
711
		// masque.type: ['adeterminer', 'aconfirmer', 'endiscussion', 'validees']
709
		// masque.type: ['adeterminer', 'aconfirmer', 'endiscussion', 'validees']
712
		if(isset($params['masque.type'])) {
710
		if(isset($params['masque.type'])) {
713
			$p['masque.type'] = array_flip(array_intersect(array_filter(explode(';', $params['masque.type'])),
711
			$p['masque.type'] = array_flip(array_intersect(array_filter(explode(';', $params['masque.type'])),
714
														   array('adeterminer', 'aconfirmer', 'endiscussion', 'validees')));
712
														   array('adeterminer', 'aconfirmer', 'endiscussion', 'validees')));
715
		}
713
		}
716
 
714
 
717
 
715
 
718
		// TODO: masque (général)
716
		// TODO: masque (général)
719
 
717
 
720
 
718
 
721
		// on filtre les NULL, FALSE et '', mais pas les 0, d'où le callback()
719
		// on filtre les NULL, FALSE et '', mais pas les 0, d'où le callback()
722
		// TODO: PHP-5.3
720
		// TODO: PHP-5.3
723
		return array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);'));
721
		return array_filter($p, create_function('$a','return !in_array($a, array("",false,null),true);'));
724
	}
722
	}
725
 
723
 
726
	static function makeJSONHeader($total, $params, $url_service) {
724
	static function makeJSONHeader($total, $params, $url_service) {
727
		$prev_url = $next_url = NULL;
725
		$prev_url = $next_url = NULL;
728
 
726
 
729
		$next_offset = $params['navigation.depart'] + $params['navigation.limite'];
727
		$next_offset = $params['navigation.depart'] + $params['navigation.limite'];
730
		if($next_offset < $total) {
728
		if($next_offset < $total) {
731
			$next_url = sprintf("http://%s?%s", isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $url_service,
729
			$next_url = sprintf("http://%s?%s", isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $url_service,
732
								http_build_query(array_merge($params, array('navigation.depart' => $next_offset))));
730
								http_build_query(array_merge($params, array('navigation.depart' => $next_offset))));
733
		}
731
		}
734
 
732
 
735
		$prev_offset = $params['navigation.depart'] - $params['navigation.limite'];
733
		$prev_offset = $params['navigation.depart'] - $params['navigation.limite'];
736
		if($prev_offset > 0) {
734
		if($prev_offset > 0) {
737
			$prev_url = sprintf("http://%s?%s", isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $url_service,
735
			$prev_url = sprintf("http://%s?%s", isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $url_service,
738
								http_build_query(array_merge($params, array('navigation.depart' => $prev_offset))));
736
								http_build_query(array_merge($params, array('navigation.depart' => $prev_offset))));
739
		}
737
		}
740
 
738
 
741
		return array(
739
		return array(
742
			'masque' => http_build_query(array_diff_key($params, array_flip(array('navigation.depart', 'navigation.limite')))),
740
			'masque' => http_build_query(array_diff_key($params, array_flip(array('navigation.depart', 'navigation.limite')))),
743
			'total' => $total,
741
			'total' => $total,
744
			'depart' => $params['navigation.depart'],
742
			'depart' => $params['navigation.depart'],
745
			'limite' => $params['navigation.limite'],
743
			'limite' => $params['navigation.limite'],
746
			'href.precedent' => $prev_url,
744
			'href.precedent' => $prev_url,
747
			'href.suivant' => $next_url
745
			'href.suivant' => $next_url
748
		);
746
		);
749
	}
747
	}
750
}
748
}