Subversion Repositories eFlore/Applications.del

Rev

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

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