Subversion Repositories eFlore/Applications.del

Rev

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

Rev 2029 Rev 2031
1
<?php
1
<?php
2
// declare(encoding='UTF-8');
2
// declare(encoding='UTF-8');
3
/**
3
/**
4
 * Classe contenant des méthodes permettant de construire les requêtes SQL complexe concernant les images et obs.
4
 * Classe contenant des méthodes permettant de construire les requêtes SQL complexe concernant les images et obs.
5
 * Rempli un tableau des clauses "join", "where", "group by" et "oder by" nécessaire à la *recherche* des ids des
5
 * Rempli un tableau des clauses "join", "where", "group by" et "oder by" nécessaire à la *recherche* des ids des
6
 * observations/images correspondantes aux filtres passés dans l'url du web service de recherche
6
 * observations/images correspondantes aux filtres passés dans l'url du web service de recherche
7
 * (ListeImages et ListeObservations).
7
 * (ListeImages et ListeObservations).
8
 *
8
 *
9
 * Attention, cela signifie que toutes les tables ne sont pas *forcément* jointées, par exemple si aucune
9
 * Attention, cela signifie que toutes les tables ne sont pas *forcément* jointées, par exemple si aucune
10
 * contrainte ne le nécessite.
10
 * contrainte ne le nécessite.
11
 * La requête construite ici est utile pour récupérer la liste des ids d'observations/images qui match.
11
 * La requête construite ici est utile pour récupérer la liste des ids d'observations/images qui match.
12
 * Pour la récupération effective de "toutes" les données nécessaire au retour du web service en json, c'est une autre
12
 * Pour la récupération effective de "toutes" les données nécessaire au retour du web service en json, c'est une autre
13
 * requête directement dans le web service qui s'en charge. Cette technique en deux étapes est la plus rapide !
13
 * requête directement dans le web service qui s'en charge. Cette technique en deux étapes est la plus rapide !
14
 *
14
 *
15
 * Note: toujours rajouter les préfixes de table (di, do ou du), en fonction de ce que défini
15
 * Note: toujours rajouter les préfixes de table (di, do ou du), en fonction de ce que défini
16
 * les JOIN qui sont utilisés :
16
 * les JOIN qui sont utilisés :
17
 * - le préfix de del_image est "di"
17
 * - le préfix de del_image est "di"
18
 * - le préfix de del_observation est "do"
18
 * - le préfix de del_observation est "do"
19
 * - le préfix de del_utilisateur est "du"
19
 * - le préfix de del_utilisateur est "du"
20
 *
20
 *
21
 * @category  DEL
21
 * @category  DEL
22
 * @package   Services
22
 * @package   Services
23
 * @package   Bibliotheque
23
 * @package   Bibliotheque
24
 * @version   0.1
24
 * @version   0.1
25
 * @author    Mathias CHOUET <mathias@tela-botanica.org>
25
 * @author    Mathias CHOUET <mathias@tela-botanica.org>
26
 * @author    Jean-Pascal MILCENT <jpm@tela-botanica.org>
26
 * @author    Jean-Pascal MILCENT <jpm@tela-botanica.org>
27
 * @author    Aurelien PERONNET <aurelien@tela-botanica.org>
27
 * @author    Aurelien PERONNET <aurelien@tela-botanica.org>
28
 * @license   GPL v3 <http://www.gnu.org/licenses/gpl.txt>
28
 * @license   GPL v3 <http://www.gnu.org/licenses/gpl.txt>
29
 * @license   CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
29
 * @license   CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
30
 * @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
30
 * @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
31
 */
31
 */
32
class Sql {
32
class Sql {
33
 
33
 
34
	const APPLI_IMG = 'IMG';
34
	const APPLI_IMG = 'IMG';
35
	const APPLI_OBS = 'OBS';
35
	const APPLI_OBS = 'OBS';
36
 
36
 
37
	private $conteneur;
37
	private $conteneur;
38
	private $bdd;
38
	private $bdd;
39
	private $parametres = array();
39
	private $parametres = array();
40
	private $appli;
40
	private $appli;
41
	private $requete = array(
41
	private $requete = array(
42
		'join' => array(),
42
		'join' => array(),
43
		'where' => array(),
43
		'where' => array(),
44
		'groupby' => array(),
44
		'groupby' => array(),
45
		'orderby' => array());
45
		'orderby' => array());
46
 
46
 
47
	private $champsPrenom = array('prenom_utilisateur');
47
	private $champsPrenom = array('prenom_utilisateur');
48
	private $champsNom = array('nom_utilisateur');
48
	private $champsNom = array('nom_utilisateur');
49
	private $champsSousRequeteObs = array('masque.genre', 'masque.famille', 'masque.ns', 'masque.commune', 'masque.milieu', 'masque.pays');
49
	private $champsSousRequeteObs = array('masque.genre', 'masque.famille', 'masque.ns', 'masque.commune', 'masque.milieu', 'masque.pays');
50
 
50
 
51
	public function __construct(Conteneur $conteneur) {
51
	public function __construct(Conteneur $conteneur) {
52
		$this->conteneur = $conteneur;
52
		$this->conteneur = $conteneur;
53
		$this->bdd = $this->conteneur->getBdd();
53
		$this->bdd = $this->conteneur->getBdd();
54
	}
54
	}
55
 
55
 
56
	public function setParametres(Array $parametres) {
56
	public function setParametres(Array $parametres) {
57
		$this->parametres = $parametres;
57
		$this->parametres = $parametres;
58
	}
58
	}
59
 
59
 
60
	public function setAppli($appliType) {
60
	public function setAppli($appliType) {
61
		if ($appliType == 'IMG' || $appliType == 'OBS') {
61
		if ($appliType == 'IMG' || $appliType == 'OBS') {
62
			$this->appli = $appliType;
62
			$this->appli = $appliType;
63
		} else {
63
		} else {
64
			throw new Exception("Les types d'appli disponible sont : IMG (pour PictoFlora) et OBS (pour IdentiPlante)");
64
			throw new Exception("Les types d'appli disponible sont : IMG (pour PictoFlora) et OBS (pour IdentiPlante)");
65
		}
65
		}
66
	}
66
	}
67
 
67
 
68
	private function getPrefixe() {
68
	private function getPrefixe() {
69
		return $this->appli === 'IMG' ? 'di' : 'do';
69
		return $this->appli === 'IMG' ? 'di' : 'do';
70
	}
70
	}
71
 
71
 
72
	private function etreAppliImg() {
72
	private function etreAppliImg() {
73
		return $this->appli === 'IMG' ? true : false;
73
		return $this->appli === 'IMG' ? true : false;
74
	}
74
	}
75
 
75
 
76
	private function etreAppliObs() {
76
	private function etreAppliObs() {
77
		return $this->appli === 'OBS' ? true : false;
77
		return $this->appli === 'OBS' ? true : false;
78
	}
78
	}
79
 
79
 
80
	public function getRequeteSql() {
80
	public function getRequeteSql() {
81
		return $this->requete;
81
		return $this->requete;
82
	}
82
	}
83
 
83
 
84
	private function addJoin($join) {
84
	private function addJoin($join) {
85
		if (!isset($this->requete['join'][$join])) {
85
		if (!isset($this->requete['join'][$join])) {
86
			$this->requete['join'][$join] = $join;
86
			$this->requete['join'][$join] = $join;
87
		}
87
		}
88
	}
88
	}
89
 
89
 
90
	public function getJoin() {
90
	public function getJoin() {
91
		return ($this->requete['join'] ? implode(' ', array_unique($this->requete['join'])).' ' : '');
91
		return ($this->requete['join'] ? implode(' ', array_unique($this->requete['join'])).' ' : '');
92
	}
92
	}
93
 
93
 
94
	private function addJoinDis($join) {
94
	private function addJoinDis($join) {
95
		$this->requete['join']['dis'] = $join;
95
		$this->requete['join']['dis'] = $join;
96
	}
96
	}
97
 
97
 
98
	private function addWhere($idParam, $where) {
98
	private function addWhere($idParam, $where) {
99
		if (isset($this->parametres['_parametres_condition_or_'])
99
		if (isset($this->parametres['_parametres_condition_or_'])
100
				&& in_array($idParam, $this->parametres['_parametres_condition_or_'])) {
100
				&& in_array($idParam, $this->parametres['_parametres_condition_or_'])) {
101
			if ($this->etreAppliImg() && in_array($idParam, $this->champsSousRequeteObs)) {
101
			if ($this->etreAppliImg() && in_array($idParam, $this->champsSousRequeteObs)) {
102
				$this->requete['where']['OR_SOUS_REQUETE'][] = $where;
102
				$this->requete['where']['OR_SOUS_REQUETE'][] = $where;
103
			} else {
103
			} else {
104
				$this->requete['where']['OR'][] = $where;
104
				$this->requete['where']['OR'][] = $where;
105
			}
105
			}
106
		} else {
106
		} else {
107
			$this->requete['where']['AND'][] = $where;
107
			$this->requete['where']['AND'][] = $where;
108
		}
108
		}
109
	}
109
	}
110
 
110
 
111
	public function getWhere() {
111
	public function getWhere() {
112
		// Sous-requete spéciale pour éviter de rechercher dans la table obs jointe à img depuis Pictoflora...
112
		// Sous-requete spéciale pour éviter de rechercher dans la table obs jointe à img depuis Pictoflora...
113
		if (isset($this->requete['where']['OR_SOUS_REQUETE']) && count($this->requete['where']['OR_SOUS_REQUETE']) > 0) {
113
		if (isset($this->requete['where']['OR_SOUS_REQUETE']) && count($this->requete['where']['OR_SOUS_REQUETE']) > 0) {
114
			$clauseWhereSousRequete = implode(' OR ', $this->requete['where']['OR_SOUS_REQUETE']);
114
			$clauseWhereSousRequete = implode(' OR ', $this->requete['where']['OR_SOUS_REQUETE']);
115
			$sousRequete = 'di.ce_observation IN '.
115
			$sousRequete = 'di.ce_observation IN '.
116
				"(SELECT id_observation FROM del_observation AS do WHERE $clauseWhereSousRequete ) ";
116
				"(SELECT id_observation FROM del_observation AS do WHERE $clauseWhereSousRequete ) ";
117
			$this->requete['where']['OR'][] = "( $sousRequete )";
117
			$this->requete['where']['OR'][] = "( $sousRequete )";
118
			unset($this->requete['join']['LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ']);
118
			unset($this->requete['join']['LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ']);
119
		}
119
		}
120
 
120
 
121
		if (isset($this->requete['where']['OR']) && count($this->requete['where']['OR']) > 0) {
121
		if (isset($this->requete['where']['OR']) && count($this->requete['where']['OR']) > 0) {
122
			$this->requete['where']['AND'][] = '('.implode(' OR ', $this->requete['where']['OR']).')';
122
			$this->requete['where']['AND'][] = '('.implode(' OR ', $this->requete['where']['OR']).')';
123
		}
123
		}
124
 
124
 
125
		$where = ' TRUE ';
125
		$where = ' TRUE ';
126
		if (isset($this->requete['where']['AND']) && count($this->requete['where']['AND']) > 0) {
126
		if (isset($this->requete['where']['AND']) && count($this->requete['where']['AND']) > 0) {
127
			$where = implode(' AND ', $this->requete['where']['AND']).' ';
127
			$where = implode(' AND ', $this->requete['where']['AND']).' ';
128
		}
128
		}
129
		return $where;
129
		return $where;
130
	}
130
	}
131
 
131
 
132
	private function addGroupBy($groupBy) {
132
	private function addGroupBy($groupBy) {
133
		$this->requete['groupby'][] = $groupBy;
133
		$this->requete['groupby'][] = $groupBy;
134
	}
134
	}
135
 
135
 
136
	public function getGroupBy() {
136
	public function getGroupBy() {
137
		$groupby = '';
137
		$groupby = '';
138
		if (isset($this->requete['groupby']) && count($this->requete['groupby']) > 0) {
138
		if (isset($this->requete['groupby']) && count($this->requete['groupby']) > 0) {
139
			$groupby = 'GROUP BY '.implode(', ', array_unique($this->requete['groupby'])).' ';
139
			$groupby = 'GROUP BY '.implode(', ', array_unique($this->requete['groupby'])).' ';
140
		}
140
		}
141
		return $groupby;
141
		return $groupby;
142
	}
142
	}
143
 
143
 
144
	private function addOrderBy($orderby) {
144
	private function addOrderBy($orderby) {
145
		$this->requete['orderby'][] = $orderby;
145
		$this->requete['orderby'][] = $orderby;
146
	}
146
	}
147
 
147
 
148
	public function getOrderBy() {
148
	public function getOrderBy() {
149
		$orderby = '';
149
		$orderby = '';
150
		if (isset($this->requete['orderby']) && count($this->requete['orderby']) > 0) {
150
		if (isset($this->requete['orderby']) && count($this->requete['orderby']) > 0) {
151
			$orderby = 'ORDER BY '.implode(', ', array_unique($this->requete['orderby'])).' ';
151
			$orderby = 'ORDER BY '.implode(', ', array_unique($this->requete['orderby'])).' ';
152
		}
152
		}
153
		return $orderby;
153
		return $orderby;
154
	}
154
	}
155
 
155
 
156
	public function getLimit() {
156
	public function getLimit() {
157
		return 'LIMIT '.$this->parametres['navigation.depart'].','.$this->parametres['navigation.limite'].' ';
157
		return 'LIMIT '.$this->parametres['navigation.depart'].','.$this->parametres['navigation.limite'].' ';
158
	}
158
	}
159
 
159
 
160
	/**
160
	/**
161
 
161
 
162
	 *
162
	 *
163
	 * @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes)
163
	 * @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes)
164
	 * @param $req le tableau, passé par référence représentant les composants de la requête à bâtir
164
	 * @param $req le tableau, passé par référence représentant les composants de la requête à bâtir
165
	 */
165
	 */
166
	public function ajouterContraintes() {
166
	public function ajouterContraintes() {
167
		$this->ajouterContrainteAuteur();
167
		$this->ajouterContrainteAuteur();
168
		$this->ajouterContrainteDate();
168
		$this->ajouterContrainteDate();
169
		$this->ajouterContraintePays();
169
		$this->ajouterContraintePays();
170
		$this->ajouterContrainteDepartement();
170
		$this->ajouterContrainteDepartement();
171
		$this->ajouterContrainteIdZoneGeo();
171
		$this->ajouterContrainteIdZoneGeo();
172
		$this->ajouterContrainteGenre();
172
		$this->ajouterContrainteGenre();
173
		$this->ajouterContrainteFamille();
173
		$this->ajouterContrainteFamille();
174
		$this->ajouterContrainteNs();
174
		$this->ajouterContrainteNs();
175
		$this->ajouterContrainteNn();
175
		$this->ajouterContrainteNn();
176
		$this->ajouterContrainteReferentiel();
176
		$this->ajouterContrainteReferentiel();
177
		$this->ajouterContrainteCommune();
177
		$this->ajouterContrainteCommune();
178
	}
178
	}
179
 
179
 
180
	private function ajouterContrainteAuteur() {
180
	private function ajouterContrainteAuteur() {
181
		if (isset($this->parametres['masque.auteur'])) {
181
		if (isset($this->parametres['masque.auteur'])) {
182
			$auteur = $this->parametres['masque.auteur'];
182
			$auteur = $this->parametres['masque.auteur'];
183
			// id du poster de l'obs
183
			// id du poster de l'obs
184
			$prefixe = $this->getPrefixe();
184
			$prefixe = $this->getPrefixe();
185
 
185
 
186
			if (is_numeric($auteur)) {
186
			if (is_numeric($auteur)) {
187
				$this->ajouterContrainteAuteurId();
187
				$this->ajouterContrainteAuteurId();
188
			} elseif(preg_match('/@[a-z0-9-]+(?:\.[a-z0-9-]+)*\.[a-z]{2,}$/i', $auteur)) {
188
			} elseif(preg_match('/@[a-z0-9-]+(?:\.[a-z0-9-]+)*\.[a-z]{2,}$/i', $auteur)) {
189
				$this->ajouterContrainteAuteurEmail();
189
				$this->ajouterContrainteAuteurEmail();
190
			} else {
190
			} else {
191
				$this->ajouterContrainteAuteurIntitule();
191
				$this->ajouterContrainteAuteurIntitule();
192
			}
192
			}
193
		}
193
		}
194
	}
194
	}
195
 
195
 
196
	private function ajouterContrainteAuteurId() {
196
	private function ajouterContrainteAuteurId() {
197
		$id = $this->parametres['masque.auteur'];
197
		$id = $this->parametres['masque.auteur'];
198
		$prefixe = $this->getPrefixe();
198
		$prefixe = $this->getPrefixe();
199
		$sqlTpl = "(du.id_utilisateur = %1\$d OR $prefixe.ce_utilisateur = %1\$d)";
199
		$sqlTpl = "(du.id_utilisateur = %1\$d OR $prefixe.ce_utilisateur = %1\$d)";
200
		$whereAuteur = sprintf($sqlTpl, $id);
200
		$whereAuteur = sprintf($sqlTpl, $id);
201
		$this->addWhere('masque.auteur', $whereAuteur);
201
		$this->addWhere('masque.auteur', $whereAuteur);
202
	}
202
	}
203
 
203
 
204
	private function ajouterContrainteAuteurEmail() {
204
	private function ajouterContrainteAuteurEmail() {
205
		$email = $this->parametres['masque.auteur'];
205
		$email = $this->parametres['masque.auteur'];
206
		$prefixe = $this->getPrefixe();
206
		$prefixe = $this->getPrefixe();
207
		$sqlTpl = "(du.courriel LIKE %1\$s OR $prefixe.courriel_utilisateur LIKE %1\$s )";
207
		$sqlTpl = "(du.courriel LIKE %1\$s OR $prefixe.courriel_utilisateur LIKE %1\$s )";
208
		$emailP = $this->bdd->proteger("$email%");
208
		$emailP = $this->bdd->proteger("$email%");
209
		$whereAuteur = sprintf($sqlTpl, $emailP);
209
		$whereAuteur = sprintf($sqlTpl, $emailP);
210
		$this->addWhere('masque.auteur', $whereAuteur);
210
		$this->addWhere('masque.auteur', $whereAuteur);
211
	}
211
	}
212
 
212
 
213
	/**
213
	/**
214
	 * Retourne une clause where du style:
214
	 * Retourne une clause where du style:
215
	 * CONCAT(IF(du.prenom IS NULL, "", du.prenom), [...] vdi.i_nomutilisateur) REGEXP 'xxx'
215
	 * CONCAT(IF(du.prenom IS NULL, "", du.prenom), [...] vdi.i_nomutilisateur) REGEXP 'xxx'
216
	 */
216
	 */
217
	private function ajouterContrainteAuteurIntitule() {
217
	private function ajouterContrainteAuteurIntitule() {
218
		$auteurExplode = explode(' ', $this->parametres['masque.auteur']);
218
		$auteurExplode = explode(' ', $this->parametres['masque.auteur']);
219
		$nbreMots = count($auteurExplode);
219
		$nbreMots = count($auteurExplode);
220
 
220
 
221
		if ($nbreMots == 1) {
221
		if ($nbreMots == 1) {
222
			$this->ajouterContrainteAuteurPrenomOuNom();
222
			$this->ajouterContrainteAuteurPrenomOuNom();
223
		} else if ($nbreMots == 2) {
223
		} else if ($nbreMots == 2) {
224
			$this->ajouterContrainteAuteurPrenomEtNom();
224
			$this->ajouterContrainteAuteurPrenomEtNom();
225
		}
225
		}
226
	}
226
	}
227
 
227
 
228
	private function ajouterContrainteAuteurPrenomOuNom() {
228
	private function ajouterContrainteAuteurPrenomOuNom() {
229
		$prenomOuNom = $this->parametres['masque.auteur'];
229
		$prenomOuNom = $this->parametres['masque.auteur'];
230
 
230
 
231
		$sqlTpl = 'CONCAT(%s,%s) LIKE %s';
231
		$sqlTpl = 'CONCAT(%s,%s) LIKE %s';
232
		$prefixe = $this->getPrefixe();
232
		$prefixe = $this->getPrefixe();
233
		$champsPrenomSql = self::ajouterIfNullPourConcat($this->champsPrenom, $prefixe);
233
		$champsPrenomSql = self::ajouterIfNullPourConcat($this->champsPrenom, $prefixe);
234
		$champsNomSql = self::ajouterIfNullPourConcat($this->champsNom, $prefixe);
234
		$champsNomSql = self::ajouterIfNullPourConcat($this->champsNom, $prefixe);
235
		$auteurMotif = $this->bdd->proteger("%$prenomOuNom%");
235
		$auteurMotif = $this->bdd->proteger("%$prenomOuNom%");
236
 
236
 
237
		$auteurWhere = sprintf($sqlTpl, $champsPrenomSql, $champsNomSql, $auteurMotif);
237
		$auteurWhere = sprintf($sqlTpl, $champsPrenomSql, $champsNomSql, $auteurMotif);
238
		$this->addWhere('masque.auteur', $auteurWhere);
238
		$this->addWhere('masque.auteur', $auteurWhere);
239
	}
239
	}
240
 
240
 
241
	private function ajouterContrainteAuteurPrenomEtNom() {
241
	private function ajouterContrainteAuteurPrenomEtNom() {
242
		list($prenom, $nom) = explode(' ', $this->parametres['masque.auteur']);
242
		list($prenom, $nom) = explode(' ', $this->parametres['masque.auteur']);
243
 
243
 
244
		$sqlTpl = '(CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s)';
244
		$sqlTpl = '(CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s)';
245
		$prefixe = $this->getPrefixe();
245
		$prefixe = $this->getPrefixe();
246
		$champsPrenomSql = self::ajouterIfNullPourConcat($this->champsPrenom, $prefixe);
246
		$champsPrenomSql = self::ajouterIfNullPourConcat($this->champsPrenom, $prefixe);
247
		$champsNomSql = self::ajouterIfNullPourConcat($this->champsNom, $prefixe);
247
		$champsNomSql = self::ajouterIfNullPourConcat($this->champsNom, $prefixe);
248
		$prenomMotif = $this->bdd->proteger("%$prenom%");
248
		$prenomMotif = $this->bdd->proteger("%$prenom%");
249
		$nomMotif = $this->bdd->proteger("%$nom%");
249
		$nomMotif = $this->bdd->proteger("%$nom%");
250
 
250
 
251
		$auteurWhere = sprintf($sqlTpl, $champsPrenomSql, $champsNomSql, $prenomMotif, $nomMotif);
251
		$auteurWhere = sprintf($sqlTpl, $champsPrenomSql, $champsNomSql, $prenomMotif, $nomMotif);
252
		$this->addWhere('masque.auteur', $auteurWhere);
252
		$this->addWhere('masque.auteur', $auteurWhere);
253
	}
253
	}
254
 
254
 
255
	/**
255
	/**
256
	 * Lorsque l'on concatène des champs, un seul NULL prend le dessus.
256
	 * Lorsque l'on concatène des champs, un seul NULL prend le dessus.
257
	 * Il faut donc utiliser la syntaxe IFNULL(%s, "").
257
	 * Il faut donc utiliser la syntaxe IFNULL(%s, "").
258
	 * Cette fonction effectue aussi l'implode() "final".
258
	 * Cette fonction effectue aussi l'implode() "final".
259
	 */
259
	 */
260
	private static function ajouterIfNullPourConcat($champs, $prefixe) {
260
	private static function ajouterIfNullPourConcat($champs, $prefixe) {
261
		$champsProteges = array();
261
		$champsProteges = array();
262
		foreach ($champs as $champ) {
262
		foreach ($champs as $champ) {
263
			if (strstr($champ, '.') === false) {
263
			if (strstr($champ, '.') === false) {
264
				$champ = "$prefixe.$champ";
264
				$champ = "$prefixe.$champ";
265
			}
265
			}
266
			$champsProteges[] = "IFNULL($champ, '')";
266
			$champsProteges[] = "IFNULL($champ, '')";
267
		}
267
		}
268
		return implode(',', $champsProteges);
268
		return implode(',', $champsProteges);
269
	}
269
	}
270
 
270
 
271
	private function ajouterContrainteDate() {
271
	private function ajouterContrainteDate() {
272
		if (isset($this->parametres['masque.date'])) {
272
		if (isset($this->parametres['masque.date'])) {
273
			$date = $this->parametres['masque.date'];
273
			$date = $this->parametres['masque.date'];
274
			if (preg_match('/^\d{4}$/', $date) && $date < 2030 && $date > 1600) {
274
			if (preg_match('/^\d{4}$/', $date) && $date < 2030 && $date > 1600) {
275
				$sqlTpl = "YEAR(do.date_observation) = %d";
275
				$sqlTpl = "YEAR(do.date_observation) = %d";
276
				$dateWhere = sprintf($sqlTpl, $date);
276
				$dateWhere = sprintf($sqlTpl, $date);
277
				$this->addWhere('masque.date', $dateWhere);
277
				$this->addWhere('masque.date', $dateWhere);
278
			} else {
278
			} else {
279
				$sqlTpl = "do.date_observation = %s";
279
				$sqlTpl = "do.date_observation = %s";
280
				$dateP = $this->bdd->proteger($date);
280
				$dateP = $this->bdd->proteger($date);
281
				$dateWhere = sprintf($sqlTpl, $dateP);
281
				$dateWhere = sprintf($sqlTpl, $dateP);
282
				$this->addWhere('masque.date', $dateWhere);
282
				$this->addWhere('masque.date', $dateWhere);
283
			}
283
			}
284
 
284
 
285
			if ($this->etreAppliImg()) {
-
 
286
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
287
			}
285
			$this->ajouterJoinObsSiNecessaire();
288
		}
286
		}
289
	}
287
	}
290
 
288
 
291
	private function ajouterContrainteDepartement() {
289
	private function ajouterContrainteDepartement() {
292
		if (isset($this->parametres['masque.departement'])) {
290
		if (isset($this->parametres['masque.departement'])) {
293
			$dept = $this->parametres['masque.departement'];
291
			$dept = $this->parametres['masque.departement'];
294
			$deptMotif = $this->bdd->proteger("INSEE-C:$dept");
292
			$deptMotif = $this->bdd->proteger("INSEE-C:$dept");
295
			$this->addWhere('masque.departement', "do.ce_zone_geo LIKE $deptMotif");
293
			$this->addWhere('masque.departement', "do.ce_zone_geo LIKE $deptMotif");
296
 
294
 
297
			if ($this->etreAppliImg()) {
-
 
298
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
299
			}
295
			$this->ajouterJoinObsSiNecessaire();
300
		}
296
		}
301
	}
297
	}
302
	
298
	
303
	private function ajouterContraintePays() {
299
	private function ajouterContraintePays() {
304
		if (isset($this->parametres['masque.pays'])) {
300
		if (isset($this->parametres['masque.pays'])) {
305
			// Attention le standard contient parfois FX pour la france métropolitaine
301
			// Attention le standard contient parfois FX pour la france métropolitaine
306
			// Dans ce cas particulier on cherche donc FR et FX
302
			// Dans ce cas particulier on cherche donc FR et FX
307
			$this->parametres['masque.pays'] = strtoupper($this->parametres['masque.pays']);
303
			$this->parametres['masque.pays'] = strtoupper($this->parametres['masque.pays']);
308
			if(strpos($this->parametres['masque.pays'], 'FR') !== false) {
304
			if(strpos($this->parametres['masque.pays'], 'FR') !== false) {
309
				$this->parametres['masque.pays'] = str_replace('FR', 'FR,FX', $this->parametres['masque.pays']);
305
				$this->parametres['masque.pays'] = str_replace('FR', 'FR,FX', $this->parametres['masque.pays']);
310
			}
306
			}
311
			$pays = explode(',', $this->parametres['masque.pays']);
307
			$pays = explode(',', $this->parametres['masque.pays']);
312
			$pays = implode(',', $this->bdd->proteger($pays));
308
			$pays = implode(',', $this->bdd->proteger($pays));
313
			$this->addWhere('masque.pays', "do.pays IN ($pays)");
309
			$this->addWhere('masque.pays', "do.pays IN ($pays)");
314
	
310
	
315
			if ($this->etreAppliImg()) {
-
 
316
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
317
			}
311
			$this->ajouterJoinObsSiNecessaire();
318
		}
312
		}
319
	}
313
	}
320
 
314
 
321
	private function ajouterContrainteIdZoneGeo() {
315
	private function ajouterContrainteIdZoneGeo() {
322
		if (isset($this->parametres['masque.id_zone_geo'])) {
316
		if (isset($this->parametres['masque.id_zone_geo'])) {
323
			$idZgMotif = $this->bdd->proteger($this->parametres['masque.id_zone_geo']);
317
			$idZgMotif = $this->bdd->proteger($this->parametres['masque.id_zone_geo']);
324
			$this->addWhere('masque.id_zone_geo', "do.ce_zone_geo = $idZgMotif");
318
			$this->addWhere('masque.id_zone_geo', "do.ce_zone_geo = $idZgMotif");
-
 
319
			
325
			if ($this->etreAppliImg()) {
320
			$this->ajouterJoinObsSiNecessaire();
326
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
327
			}
-
 
328
		}
321
		}
329
	}
322
	}
330
 
323
 
331
	private function ajouterContrainteGenre() {
324
	private function ajouterContrainteGenre() {
332
		if (isset($this->parametres['masque.genre'])) {
325
		if (isset($this->parametres['masque.genre'])) {
333
			$genre = $this->parametres['masque.genre'];
326
			$genre = $this->parametres['masque.genre'];
334
			$genreMotif = $this->bdd->proteger("$genre%");
327
			$genreMotif = $this->bdd->proteger("$genre%");
335
			$this->addWhere('masque.genre', "do.nom_sel LIKE $genreMotif");
328
			$this->addWhere('masque.genre', "do.nom_sel LIKE $genreMotif");
336
 
329
 
337
			if ($this->etreAppliImg()) {
-
 
338
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
339
			}
330
			$this->ajouterJoinObsSiNecessaire();
340
		}
331
		}
341
	}
332
	}
342
 
333
 
343
	private function ajouterContrainteFamille() {
334
	private function ajouterContrainteFamille() {
344
		if (isset($this->parametres['masque.famille'])) {
335
		if (isset($this->parametres['masque.famille'])) {
345
			$familleMotif = $this->bdd->proteger($this->parametres['masque.famille']);
336
			$familleMotif = $this->bdd->proteger($this->parametres['masque.famille']);
346
			$this->addWhere('masque.famille', "do.famille = $familleMotif");
337
			$this->addWhere('masque.famille', "do.famille = $familleMotif");
347
 
338
 
348
			if ($this->etreAppliImg()) {
-
 
349
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
350
			}
339
			$this->ajouterJoinObsSiNecessaire();
351
		}
340
		}
352
	}
341
	}
353
 
342
 
354
	private function ajouterContrainteNs() {
343
	private function ajouterContrainteNs() {
355
		if (isset($this->parametres['masque.ns'])) {
344
		if (isset($this->parametres['masque.ns'])) {
356
			$ns = $this->parametres['masque.ns'];
345
			$ns = $this->parametres['masque.ns'];
357
			$nsMotif = $this->bdd->proteger("$ns%");
346
			$nsMotif = $this->bdd->proteger("$ns%");
358
			$this->addWhere('masque.ns', "do.nom_sel LIKE $nsMotif");
347
			$this->addWhere('masque.ns', "do.nom_sel LIKE $nsMotif");
359
 
348
			
360
			if ($this->etreAppliImg()) {
349
			$this->ajouterJoinObsSiNecessaire();
361
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
362
			}
-
 
363
		}
350
		}
364
	}
351
	}
365
 
352
 
366
	private function ajouterContrainteNn() {
353
	private function ajouterContrainteNn() {
367
		if (isset($this->parametres['masque.nn'])) {
354
		if (isset($this->parametres['masque.nn'])) {
368
			$sqlTpl = '(do.nom_sel_nn = %1$d OR do.nom_ret_nn = %1$d)';
355
			$sqlTpl = '(do.nom_sel_nn = %1$d OR do.nom_ret_nn = %1$d)';
369
			$nnWhere = sprintf($sqlTpl, $this->parametres['masque.nn']);
356
			$nnWhere = sprintf($sqlTpl, $this->parametres['masque.nn']);
370
			$this->addWhere('masque.nn', $nnWhere);
357
			$this->addWhere('masque.nn', $nnWhere);
371
 
358
 
372
			if ($this->etreAppliImg()) {
-
 
373
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
374
			}
359
			$this->ajouterJoinObsSiNecessaire();
375
		}
360
		}
376
	}
361
	}
377
 
362
 
378
	private function ajouterContrainteReferentiel() {
363
	private function ajouterContrainteReferentiel() {
379
		if (isset($this->parametres['masque.referentiel'])) {
364
		if (isset($this->parametres['masque.referentiel'])) {
380
			$ref = $this->parametres['masque.referentiel'];
365
			$ref = $this->parametres['masque.referentiel'];
381
			$refMotif = $this->bdd->proteger("$ref%");
366
			$refMotif = $this->bdd->proteger("$ref%");
382
			$this->addWhere('masque.referentiel', "do.nom_referentiel LIKE $refMotif");
367
			$this->addWhere('masque.referentiel', "do.nom_referentiel LIKE $refMotif");
383
 
368
 
384
			if ($this->etreAppliImg()) {
-
 
385
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
-
 
386
			}
369
			$this->ajouterJoinObsSiNecessaire();
387
		}
370
		}
388
	}
371
	}
389
 
372
 
390
	private function ajouterContrainteCommune() {
373
	private function ajouterContrainteCommune() {
391
		if (isset($this->parametres['masque.commune'])) {
374
		if (isset($this->parametres['masque.commune'])) {
392
			$commune = $this->parametres['masque.commune'];
375
			$commune = $this->parametres['masque.commune'];
393
			$communeMotif = $this->bdd->proteger("$commune%");
376
			$communeMotif = $this->bdd->proteger("$commune%");
394
			$this->addWhere('masque.commune', "do.zone_geo LIKE $communeMotif");
377
			$this->addWhere('masque.commune', "do.zone_geo LIKE $communeMotif");
-
 
378
 
-
 
379
			$this->ajouterJoinObsSiNecessaire();
-
 
380
		}
-
 
381
	}
-
 
382
	
395
 
383
	private function ajouterJoinObsSiNecessaire() {
396
			if ($this->etreAppliImg()) {
384
			if ($this->etreAppliImg()) {
397
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
385
				$this->addJoin('INNER JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
398
			}
-
 
399
		}
386
			}
400
	}
387
	}
401
 
388
 
402
	public function ajouterConstrainteAppliObs() {
389
	public function ajouterConstrainteAppliObs() {
403
		$this->ajouterContrainteTagCel();
390
		$this->ajouterContrainteTagCel();
404
		$this->ajouterContrainteType();
391
		$this->ajouterContrainteType();
405
		// TODO : ATTENTION -> vue que l'on utilise une vue basée sur les images, nous devons grouper par obs
392
		// TODO : ATTENTION -> vue que l'on utilise une vue basée sur les images, nous devons grouper par obs
406
		$this->addGroupBy('do.id_observation');
393
		$this->addGroupBy('do.id_observation');
407
	}
394
	}
408
 
395
 
409
	private function ajouterContrainteType() {
396
	private function ajouterContrainteType() {
410
		// Les contraintes régissant les onglets sont issus de la réunion dont le compte rendu 
397
		// Les contraintes régissant les onglets sont issus de la réunion dont le compte rendu 
411
		// disponible ici : http://tela-botanica.net/intranet/wakka.php?wiki=Octobre2014
398
		// disponible ici : http://tela-botanica.net/intranet/wakka.php?wiki=Octobre2014
412
		// Ce lien est à modifier pour pointer vers toute nouvelle réunion modifiant ce fonctionnement
399
		// Ce lien est à modifier pour pointer vers toute nouvelle réunion modifiant ce fonctionnement
413
		
400
		
414
		if (isset($this->parametres['masque.type'])) {
401
		if (isset($this->parametres['masque.type'])) {
415
			if (array_key_exists('adeterminer', $this->parametres['masque.type'])) {
402
			if (array_key_exists('adeterminer', $this->parametres['masque.type'])) {
416
				// A DETERMINER : toutes les observations qui ont le tag "aDeterminer" 
403
				// A DETERMINER : toutes les observations qui ont le tag "aDeterminer" 
417
				// *ou* qui n'ont pas de nom d'espèce
404
				// *ou* qui n'ont pas de nom d'espèce
418
				// *ou* qui ont la "certitude" à ("aDeterminer" *ou* "douteux")
405
				// *ou* qui ont la "certitude" à ("aDeterminer" *ou* "douteux")
419
				$this->addWhere('masque.type', '('.
406
				$this->addWhere('masque.type', '('.
420
					'do.certitude = "aDeterminer" '.
407
					'do.certitude = "aDeterminer" '.
421
					'OR do.certitude = "douteux" '.
408
					'OR do.certitude = "douteux" '.
422
					'OR do.mots_cles_texte LIKE "%aDeterminer%" '.
409
					'OR do.mots_cles_texte LIKE "%aDeterminer%" '.
423
					'OR do.nom_sel_nn IS NULL '.
410
					'OR do.nom_sel_nn IS NULL '.
424
					'OR do.nom_sel_nn = 0 '.// il ne DEVRAIT pas y avoir d'entrées à 0, mais il y en a quand-même !!
411
					'OR do.nom_sel_nn = 0 '.// il ne DEVRAIT pas y avoir d'entrées à 0, mais il y en a quand-même !!
425
					')');
412
					')');
426
			}
413
			}
427
			
414
			
428
			if (array_key_exists('validees', $this->parametres['masque.type'])) {
415
			if (array_key_exists('validees', $this->parametres['masque.type'])) {
429
				// VALIDEES : toutes les observations ayant un commentaire doté de proposition_retenue = 1
416
				// VALIDEES : toutes les observations ayant un commentaire doté de proposition_retenue = 1
430
				// ou bien possédant une proposition initiale avec un nom valide ayant totalisé un score d'au moins 4
417
				// ou bien possédant une proposition initiale avec un nom valide ayant totalisé un score d'au moins 4
431
				// (ce qui correspond à au moins deux votes positifs dans la plupart des cas, dont un identifié)
418
				// (ce qui correspond à au moins deux votes positifs dans la plupart des cas, dont un identifié)
432
				$sous_requete_score_prop_votees = $this->getSousRequeteSommeVotesPropositions();				
419
				$sous_requete_score_prop_votees = $this->getSousRequeteSommeVotesPropositions();				
433
				$this->addJoin('INNER JOIN del_commentaire AS dc '.
420
				$this->addJoin('INNER JOIN del_commentaire AS dc '.
434
					'ON ( '.
421
					'ON ( '.
435
						'do.id_observation = dc.ce_observation '.
422
						'do.id_observation = dc.ce_observation '.
436
						'AND ( '.
423
						'AND ( '.
437
							'dc.proposition_retenue = 1 OR '.
424
							'dc.proposition_retenue = 1 OR '.
438
							'( '.
425
							'( '.
439
								'dc.proposition_initiale = 1 '.
426
								'dc.proposition_initiale = 1 '.
440
								'AND dc.nom_sel_nn != 0 '.
427
								'AND dc.nom_sel_nn != 0 '.
441
								'AND dc.nom_sel_nn IS NOT NULL '.
428
								'AND dc.nom_sel_nn IS NOT NULL '.
442
								' AND dc.id_commentaire IN ('.$sous_requete_score_prop_votees.' >= 4) '.
429
								' AND dc.id_commentaire IN ('.$sous_requete_score_prop_votees.' >= 4) '.
443
							') '.
430
							') '.
444
						') '.
431
						') '.
445
					')'
432
					')'
446
				);
433
				);
447
			}
434
			}
448
			
435
			
449
			if(array_key_exists('aconfirmer', $this->parametres['masque.type'])) {
436
			if(array_key_exists('aconfirmer', $this->parametres['masque.type'])) {
450
				// A CONFIRMER : toutes les observations moins les validées et à confirmer
437
				// A CONFIRMER : toutes les observations moins les validées et à confirmer
451
				// i.e. : des observations avec un nom valide, qui ne sont pas à déterminer
438
				// i.e. : des observations avec un nom valide, qui ne sont pas à déterminer
452
				// (ni certitude "aDeterminer" ou "douteuse", ni mot clé),
439
				// (ni certitude "aDeterminer" ou "douteuse", ni mot clé),
453
				// ne possédant pas de proposition officiellement retenue 
440
				// ne possédant pas de proposition officiellement retenue 
454
				// et ayant une proposition initiale totalisant un score de moins de 4 
441
				// et ayant une proposition initiale totalisant un score de moins de 4 
455
				$sous_requete_score_prop_votees = $this->getSousRequeteSommeVotesPropositions();
442
				$sous_requete_score_prop_votees = $this->getSousRequeteSommeVotesPropositions();
456
				$this->addWhere('masque.type', 
443
				$this->addWhere('masque.type', 
457
						'('.
444
						'('.
458
							'do.id_observation IN ('.
445
							'do.id_observation IN ('.
459
								'SELECT dc.ce_observation FROM del_commentaire dc WHERE dc.proposition_retenue = 0'.
446
								'SELECT dc.ce_observation FROM del_commentaire dc WHERE dc.proposition_retenue = 0'.
460
								' AND ( '.
447
								' AND ( '.
461
									'dc.proposition_initiale = 1 '.
448
									'dc.proposition_initiale = 1 '.
462
									'AND dc.nom_sel_nn != 0 '.
449
									'AND dc.nom_sel_nn != 0 '.
463
									'AND dc.nom_sel_nn IS NOT NULL '.
450
									'AND dc.nom_sel_nn IS NOT NULL '.
464
									'AND dc.id_commentaire IN ('.$sous_requete_score_prop_votees.' < 4) '.
451
									'AND dc.id_commentaire IN ('.$sous_requete_score_prop_votees.' < 4) '.
465
								') '.
452
								') '.
466
							') AND do.id_observation NOT IN ('.
453
							') AND do.id_observation NOT IN ('.
467
								'SELECT dc.ce_observation FROM del_commentaire dc '.
454
								'SELECT dc.ce_observation FROM del_commentaire dc '.
468
								'WHERE '.
455
								'WHERE '.
469
								' dc.proposition_retenue = 1'.
456
								' dc.proposition_retenue = 1'.
470
							') '.
457
							') '.
471
							'AND do.certitude != "douteux" AND do.certitude != "aDeterminer" '.
458
							'AND do.certitude != "douteux" AND do.certitude != "aDeterminer" '.
472
							'AND do.mots_cles_texte NOT LIKE "%aDeterminer%" '.
459
							'AND do.mots_cles_texte NOT LIKE "%aDeterminer%" '.
473
							'AND do.nom_sel_nn != 0 '.
460
							'AND do.nom_sel_nn != 0 '.
474
							'AND do.nom_sel_nn IS NOT NULL'.
461
							'AND do.nom_sel_nn IS NOT NULL'.
475
						') '	
462
						') '	
476
					);
463
					);
477
			}	
464
			}	
478
 
465
 
479
			if ($this->etreAppliImg()) {
466
			if ($this->etreAppliImg()) {
480
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
467
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
481
			}
468
			}
482
		}
469
		}
483
	}
470
	}
484
	
471
	
485
	private function getSousRequeteSommeVotesPropositions() {
472
	private function getSousRequeteSommeVotesPropositions() {
486
		// ATTENTION : un vote identifié compte 3 votes anonymes (dans les deux sens)
473
		// ATTENTION : un vote identifié compte 3 votes anonymes (dans les deux sens)
487
		return  'SELECT ce_proposition '.
474
		return  'SELECT ce_proposition '.
488
				'FROM del_commentaire_vote dcv '.
475
				'FROM del_commentaire_vote dcv '.
489
				'GROUP BY ce_proposition HAVING '.
476
				'GROUP BY ce_proposition HAVING '.
490
				'SUM(CASE '.
477
				'SUM(CASE '.
491
				'	WHEN valeur = 1 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' != 0 THEN 3 '.
478
				'	WHEN valeur = 1 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' != 0 THEN 3 '.
492
				'	WHEN valeur = 0 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' != 0 THEN -3 '.
479
				'	WHEN valeur = 0 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' != 0 THEN -3 '.
493
				'	WHEN valeur = 1 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' = 0 THEN 1 '.
480
				'	WHEN valeur = 1 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' = 0 THEN 1 '.
494
				'	WHEN valeur = 0 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' = 0 THEN -1 '.
481
				'	WHEN valeur = 0 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' = 0 THEN -1 '.
495
				'END '.
482
				'END '.
496
			') ';
483
			') ';
497
	}
484
	}
498
 
485
 
499
	public function ajouterConstrainteAppliImg() {
486
	public function ajouterConstrainteAppliImg() {
500
		$this->ajouterContrainteMilieu();
487
		$this->ajouterContrainteMilieu();
501
		$this->ajouterContrainteTri();
488
		$this->ajouterContrainteTri();
502
		$this->ajouterContrainteTagCel();
489
		$this->ajouterContrainteTagCel();
503
		$this->ajouterContrainteTagDel();
490
		$this->ajouterContrainteTagDel();
504
	}
491
	}
505
 
492
 
506
	private function ajouterContrainteMilieu() {
493
	private function ajouterContrainteMilieu() {
507
		if (isset($this->parametres['masque.milieu'])) {
494
		if (isset($this->parametres['masque.milieu'])) {
508
			$milieu = $this->parametres['masque.milieu'];
495
			$milieu = $this->parametres['masque.milieu'];
509
			$milieuMotif = $this->bdd->proteger("%$milieu%");
496
			$milieuMotif = $this->bdd->proteger("%$milieu%");
510
			$this->addWhere('masque.milieu', "do.milieu LIKE $milieuMotif");
497
			$this->addWhere('masque.milieu', "do.milieu LIKE $milieuMotif");
511
 
498
 
512
			if ($this->etreAppliImg()) {
499
			if ($this->etreAppliImg()) {
513
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
500
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
514
			}
501
			}
515
		}
502
		}
516
	}
503
	}
517
 
504
 
518
	private function ajouterContrainteTri() {
505
	private function ajouterContrainteTri() {
519
		if (isset($this->parametres['tri'])) {
506
		if (isset($this->parametres['tri'])) {
520
			$tri = $this->parametres['tri'];
507
			$tri = $this->parametres['tri'];
521
 
508
 
522
			if (isset($this->parametres['protocole'])  && ($tri == 'moyenne-arithmetique' || $tri == 'points')) {
509
			if (isset($this->parametres['protocole'])  && ($tri == 'moyenne-arithmetique' || $tri == 'points')) {
523
				// $this->parametres['protocole'] *est* défini (cf Outils::filtrerUrlsParams...())
510
				// $this->parametres['protocole'] *est* défini (cf Outils::filtrerUrlsParams...())
524
				$sqlTpl = 'LEFT JOIN del_image_stat AS dis ON di.id_image = dis.ce_image AND dis.ce_protocole = %d';
511
				$sqlTpl = 'LEFT JOIN del_image_stat AS dis ON di.id_image = dis.ce_image AND dis.ce_protocole = %d';
525
				$triSql = sprintf($sqlTpl, $this->parametres['protocole']);
512
				$triSql = sprintf($sqlTpl, $this->parametres['protocole']);
526
				$this->addJoinDis($triSql);
513
				$this->addJoinDis($triSql);
527
			}
514
			}
528
 
515
 
529
			if (isset($this->parametres['ordre']) && $tri == 'tags') {
516
			if (isset($this->parametres['ordre']) && $tri == 'tags') {
530
				$typeJointure = ($this->parametres['ordre'] == 'desc') ? 'INNER' : 'LEFT';
517
				$typeJointure = ($this->parametres['ordre'] == 'desc') ? 'INNER' : 'LEFT';
531
				$this->addJoin("$typeJointure JOIN del_image_stat AS dis ON di.id_image = dis.ce_image");
518
				$this->addJoin("$typeJointure JOIN del_image_stat AS dis ON di.id_image = dis.ce_image");
532
			}
519
			}
533
		}
520
		}
534
	}
521
	}
535
 
522
 
536
	private function ajouterContrainteTagCel() {
523
	private function ajouterContrainteTagCel() {
537
		if (isset($this->parametres['masque.tag_cel'])) {
524
		if (isset($this->parametres['masque.tag_cel'])) {
538
			if (isset($this->parametres['masque.tag_cel']['AND'])) {
525
			if (isset($this->parametres['masque.tag_cel']['AND'])) {
539
				$tags = $this->parametres['masque.tag_cel']['AND'];
526
				$tags = $this->parametres['masque.tag_cel']['AND'];
540
				$clausesWhere = array();
527
				$clausesWhere = array();
541
				foreach ($tags as $tag) {
528
				foreach ($tags as $tag) {
542
					$tagMotif = $this->bdd->proteger("%$tag%");
529
					$tagMotif = $this->bdd->proteger("%$tag%");
543
					if ($this->etreAppliImg()) {
530
					if ($this->etreAppliImg()) {
544
						$sousRequete = 'SELECT id_observation '.
531
						$sousRequete = 'SELECT id_observation '.
545
							'FROM del_observation '.
532
							'FROM del_observation '.
546
							"WHERE mots_cles_texte LIKE $tagMotif ";
533
							"WHERE mots_cles_texte LIKE $tagMotif ";
547
						$sql = " (di.mots_cles_texte LIKE $tagMotif OR di.id_image IN ($sousRequete) ) ";
534
						$sql = " (di.mots_cles_texte LIKE $tagMotif OR di.id_image IN ($sousRequete) ) ";
548
					} else {
535
					} else {
549
						// WARNING : la sous-requête est la meilleure solution trouvée pour contrer le fonctionnement
536
						// WARNING : la sous-requête est la meilleure solution trouvée pour contrer le fonctionnement
550
						// étrange de l'optimiseur de MYSQL 5.6 (à retester avec Mysql 5.7 et suivant).
537
						// étrange de l'optimiseur de MYSQL 5.6 (à retester avec Mysql 5.7 et suivant).
551
						$sousRequete = 'SELECT DISTINCT ce_observation '.
538
						$sousRequete = 'SELECT DISTINCT ce_observation '.
552
							'FROM del_image '.
539
							'FROM del_image '.
553
							"WHERE mots_cles_texte LIKE $tagMotif ".
540
							"WHERE mots_cles_texte LIKE $tagMotif ".
554
							'AND ce_observation IS NOT NULL';
541
							'AND ce_observation IS NOT NULL';
555
						$sql = " (do.mots_cles_texte LIKE $tagMotif OR do.id_observation IN ($sousRequete)) ";
542
						$sql = " (do.mots_cles_texte LIKE $tagMotif OR do.id_observation IN ($sousRequete)) ";
556
					}
543
					}
557
					$clausesWhere[] = $sql;
544
					$clausesWhere[] = $sql;
558
				}
545
				}
559
				$whereTags = implode(' AND ', $clausesWhere);
546
				$whereTags = implode(' AND ', $clausesWhere);
560
				$this->addWhere('masque.tag_cel', "($whereTags)");
547
				$this->addWhere('masque.tag_cel', "($whereTags)");
561
			} else if (isset($this->parametres['masque.tag_cel']['OR'])) {
548
			} else if (isset($this->parametres['masque.tag_cel']['OR'])) {
562
				$tags = $this->parametres['masque.tag_cel']['OR'];
549
				$tags = $this->parametres['masque.tag_cel']['OR'];
563
				$tagMotif = $this->bdd->proteger(implode('|', $tags));
550
				$tagMotif = $this->bdd->proteger(implode('|', $tags));
564
				$sqlTpl = "CONCAT(IFNULL(do.mots_cles_texte,''),IFNULL(di.mots_cles_texte,'')) REGEXP %s";
551
				$sqlTpl = "CONCAT(IFNULL(do.mots_cles_texte,''),IFNULL(di.mots_cles_texte,'')) REGEXP %s";
565
				$tagSql = sprintf($sqlTpl, $tagMotif);
552
				$tagSql = sprintf($sqlTpl, $tagMotif);
566
 
553
 
567
				$this->addWhere('masque.tag_cel', $tagSql);
554
				$this->addWhere('masque.tag_cel', $tagSql);
568
 
555
 
569
				if ($this->etreAppliObs()) {
556
				if ($this->etreAppliObs()) {
570
					$this->addJoin('LEFT JOIN del_image AS di ON (di.ce_observation = do.id_observation) ');
557
					$this->addJoin('LEFT JOIN del_image AS di ON (di.ce_observation = do.id_observation) ');
571
				}
558
				}
572
			}
559
			}
573
			if ($this->etreAppliImg()) {
560
			if ($this->etreAppliImg()) {
574
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
561
				$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ');
575
			}
562
			}
576
		}
563
		}
577
	}
564
	}
578
 
565
 
579
	/**
566
	/**
580
	 * Plusieurs solutions sont disponibles dans les anciennes versions (voir DelTk et l'historique SVN de ce fichier).
567
	 * Plusieurs solutions sont disponibles dans les anciennes versions (voir DelTk et l'historique SVN de ce fichier).
581
	 */
568
	 */
582
	private function ajouterContrainteTagDel() {
569
	private function ajouterContrainteTagDel() {
583
		if (isset($this->parametres['masque.tag_del'])) {
570
		if (isset($this->parametres['masque.tag_del'])) {
584
			$nbTags = $this->getNombreDeTags();
571
			$nbTags = $this->getNombreDeTags();
585
			if($nbTags > 1) {
572
			if($nbTags > 1) {
586
				$tagsMotif = $this->construireTagsMotif();
573
				$tagsMotif = $this->construireTagsMotif();
587
				if (is_null($tagsMotif) === false) {
574
				if (is_null($tagsMotif) === false) {
588
					$sousRequete = 'SELECT ce_image '.
575
					$sousRequete = 'SELECT ce_image '.
589
						'FROM del_image_tag '.
576
						'FROM del_image_tag '.
590
						'WHERE actif = 1 '.
577
						'WHERE actif = 1 '.
591
						'GROUP BY ce_image '.
578
						'GROUP BY ce_image '.
592
						"HAVING GROUP_CONCAT(DISTINCT tag_normalise ORDER BY tag_normalise) REGEXP $tagsMotif ";
579
						"HAVING GROUP_CONCAT(DISTINCT tag_normalise ORDER BY tag_normalise) REGEXP $tagsMotif ";
593
				}
580
				}
594
			} else {
581
			} else {
595
				// Si un seul tag est demandé il se trouve dans le OR
582
				// Si un seul tag est demandé il se trouve dans le OR
596
				$tag = $this->parametres['masque.tag_del']['OR'][0];
583
				$tag = $this->parametres['masque.tag_del']['OR'][0];
597
				$sousRequete = 'SELECT ce_image '.
584
				$sousRequete = 'SELECT ce_image '.
598
						'FROM del_image_tag '.
585
						'FROM del_image_tag '.
599
						'WHERE actif = 1 '.
586
						'WHERE actif = 1 '.
600
						'AND tag_normalise LIKE '.$this->bdd->proteger($tag.'%');
587
						'AND tag_normalise LIKE '.$this->bdd->proteger($tag.'%');
601
			}
588
			}
602
			
589
			
603
			$this->addWhere('masque.tag_del', "di.id_image IN ($sousRequete)");
590
			$this->addWhere('masque.tag_del', "di.id_image IN ($sousRequete)");
604
		}
591
		}
605
	}
592
	}
606
	
593
	
607
	private function getNombreDeTags() {
594
	private function getNombreDeTags() {
608
		$somme = 0;
595
		$somme = 0;
609
		if (isset($this->parametres['masque.tag_del']['AND'])) {
596
		if (isset($this->parametres['masque.tag_del']['AND'])) {
610
			$somme = count($this->parametres['masque.tag_del']['AND']);
597
			$somme = count($this->parametres['masque.tag_del']['AND']);
611
		} else {
598
		} else {
612
			$somme = count($this->parametres['masque.tag_del']['OR']);
599
			$somme = count($this->parametres['masque.tag_del']['OR']);
613
		}
600
		}
614
		return $somme;
601
		return $somme;
615
	}
602
	}
616
 
603
 
617
	private function construireTagsMotif() {
604
	private function construireTagsMotif() {
618
		$tagsMotif = null;
605
		$tagsMotif = null;
619
		if (isset($this->parametres['masque.tag_del']['AND'])) {
606
		if (isset($this->parametres['masque.tag_del']['AND'])) {
620
			$tags = $this->parametres['masque.tag_del']['AND'];
607
			$tags = $this->parametres['masque.tag_del']['AND'];
621
			// ATTENTION -> optimisation: en cas de "AND" on sort() l'input et le GROUP_CONCAT()
608
			// ATTENTION -> optimisation: en cas de "AND" on sort() l'input et le GROUP_CONCAT()
622
			// donc nous utilisons des ".*" plutôt que de multiples conditions et "|"
609
			// donc nous utilisons des ".*" plutôt que de multiples conditions et "|"
623
			sort($tags);
610
			sort($tags);
624
			$tagsMotif = $this->bdd->proteger(implode('.*', $tags));
611
			$tagsMotif = $this->bdd->proteger(implode('.*', $tags));
625
		} else if (isset($this->parametres['masque.tag_del']['OR'])) {
612
		} else if (isset($this->parametres['masque.tag_del']['OR'])) {
626
			$tags = $this->parametres['masque.tag_del']['OR'];
613
			$tags = $this->parametres['masque.tag_del']['OR'];
627
			$tagsMotif = $this->bdd->proteger(implode('|', $tags));
614
			$tagsMotif = $this->bdd->proteger(implode('|', $tags));
628
		}
615
		}
629
		return $tagsMotif;
616
		return $tagsMotif;
630
	}
617
	}
631
 
618
 
632
	/**
619
	/**
633
	 * Partie spécifique à PictoFlora:
620
	 * Partie spécifique à PictoFlora:
634
	 * Attention : si le critère de tri n'est pas suffisant, les résultats affichés peuvent varier à chaque appel
621
	 * Attention : si le critère de tri n'est pas suffisant, les résultats affichés peuvent varier à chaque appel
635
	 * de la même page de résultat de PictoFlora.
622
	 * de la même page de résultat de PictoFlora.
636
	 */
623
	 */
637
	public function definirOrdreSqlAppliImg() {
624
	public function definirOrdreSqlAppliImg() {
638
		$ordre = $this->parametres['ordre'];
625
		$ordre = $this->parametres['ordre'];
639
		
626
		
640
		$tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : '';
627
		$tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : '';
641
		switch ($tri) {
628
		switch ($tri) {
642
			case 'moyenne-arithmetique' :
629
			case 'moyenne-arithmetique' :
643
				$this->addOrderBy("dis.moyenne $ordre, dis.nb_votes $ordre, id_image $ordre");
630
				$this->addOrderBy("dis.moyenne $ordre, dis.nb_votes $ordre, id_image $ordre");
644
				break;
631
				break;
645
			case 'points' :
632
			case 'points' :
646
				$this->addOrderBy("dis.nb_points $ordre, dis.moyenne $ordre, dis.nb_votes $ordre, id_image $ordre");
633
				$this->addOrderBy("dis.nb_points $ordre, dis.moyenne $ordre, dis.nb_votes $ordre, id_image $ordre");
647
				break;
634
				break;
648
			case 'tags' :
635
			case 'tags' :
649
				$this->addOrderBy("dis.nb_tags $ordre, id_image $ordre");
636
				$this->addOrderBy("dis.nb_tags $ordre, id_image $ordre");
650
				break;
637
				break;
651
			case 'date_observation' :
638
			case 'date_observation' :
652
				$this->addOrderBy("date_observation $ordre, ce_observation $ordre");
639
				$this->addOrderBy("date_observation $ordre, ce_observation $ordre");
653
				break;
640
				break;
654
			case 'date_transmission' :
641
			case 'date_transmission' :
655
			default:
642
			default:
656
				$this->addOrderBy("di.date_transmission $ordre, ce_observation $ordre");
643
				$this->addOrderBy("di.date_transmission $ordre, ce_observation $ordre");
657
		}
644
		}
658
	}
645
	}
659
 
646
 
660
	public function definirOrdreSqlAppliObs() {
647
	public function definirOrdreSqlAppliObs() {
661
		$ordre = $this->parametres['ordre'];
648
		$ordre = $this->parametres['ordre'];
662
 
649
 
663
		// parmi self::$tri_possible
650
		// parmi self::$tri_possible
664
		$tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : '';
651
		$tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : '';
665
			switch ($tri) {
652
			switch ($tri) {
666
			case 'date_observation' :
653
			case 'date_observation' :
667
				$this->addOrderBy("date_observation $ordre, id_observation $ordre");
654
				$this->addOrderBy("date_observation $ordre, id_observation $ordre");
668
				break;			
655
				break;			
669
			case 'nb_commentaires' :
656
			case 'nb_commentaires' :
670
				$sql_nb_comms = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc WHERE ce_observation = id_observation)';
657
				$sql_nb_comms = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc WHERE ce_observation = id_observation)';
671
				$this->addOrderBy("$sql_nb_comms $ordre, id_observation $ordre");
658
				$this->addOrderBy("$sql_nb_comms $ordre, id_observation $ordre");
672
				break;
659
				break;
673
			case 'date_transmission' :
660
			case 'date_transmission' :
674
			default:
661
			default:
675
				$this->addOrderBy("do.date_transmission $ordre, id_observation $ordre");
662
				$this->addOrderBy("do.date_transmission $ordre, id_observation $ordre");
676
		}
663
		}
677
	}
664
	}
678
 
665
 
679
	public function getAliasDesChamps($champsEtAlias, $select = null, $prefix = null) {
666
	public function getAliasDesChamps($champsEtAlias, $select = null, $prefix = null) {
680
		$arr = ($select) ? array_intersect_key($champsEtAlias, array_flip($select)) :  $champsEtAlias;
667
		$arr = ($select) ? array_intersect_key($champsEtAlias, array_flip($select)) :  $champsEtAlias;
681
		$keys = array_keys($arr);
668
		$keys = array_keys($arr);
682
 
669
 
683
		if ($prefix) {
670
		if ($prefix) {
684
			array_walk($keys, create_function('&$val, $k, $prefix', '$val = sprintf("%s.`%s`", $prefix, $val);'), $prefix);
671
			array_walk($keys, create_function('&$val, $k, $prefix', '$val = sprintf("%s.`%s`", $prefix, $val);'), $prefix);
685
		} else {
672
		} else {
686
			array_walk($keys, create_function('&$val, $k', '$val = sprintf("`%s`", $val);'));
673
			array_walk($keys, create_function('&$val, $k', '$val = sprintf("`%s`", $val);'));
687
		}
674
		}
688
 
675
 
689
		return implode(', ', array_map(create_function('$v, $k', 'return sprintf("%s AS `%s`", $k, $v);'), $arr, $keys));
676
		return implode(', ', array_map(create_function('$v, $k', 'return sprintf("%s AS `%s`", $k, $v);'), $arr, $keys));
690
	}
677
	}
691
 
678
 
692
	public function getVotesDesImages($idsImages, $protocole = null) {
679
	public function getVotesDesImages($idsImages, $protocole = null) {
693
		if (!$idsImages) return;
680
		if (!$idsImages) return;
694
 
681
 
695
		$mappingVotes = $this->conteneur->getParametreTableau('votes.mapping');
682
		$mappingVotes = $this->conteneur->getParametreTableau('votes.mapping');
696
		$mappingProtocoles = $this->conteneur->getParametreTableau('protocoles.mapping');
683
		$mappingProtocoles = $this->conteneur->getParametreTableau('protocoles.mapping');
697
 		$selectVotes = array('id_vote', 'ce_image', 'ce_protocole', 'ce_utilisateur', 'valeur', 'date');
684
 		$selectVotes = array('id_vote', 'ce_image', 'ce_protocole', 'ce_utilisateur', 'valeur', 'date');
698
		$selectProtocole = array('id_protocole', 'intitule', 'descriptif', 'tag');
685
		$selectProtocole = array('id_protocole', 'intitule', 'descriptif', 'tag');
699
		$voteChamps = $this->getAliasDesChamps($mappingVotes, $selectVotes, 'v'); // "v": cf alias dans la requête
686
		$voteChamps = $this->getAliasDesChamps($mappingVotes, $selectVotes, 'v'); // "v": cf alias dans la requête
700
		$protoChamps = $this->getAliasDesChamps($mappingProtocoles, $selectProtocole, 'p');
687
		$protoChamps = $this->getAliasDesChamps($mappingProtocoles, $selectProtocole, 'p');
701
		$idImgsConcat = implode(',', $idsImages);
688
		$idImgsConcat = implode(',', $idsImages);
702
 
689
 
703
		$requete = "SELECT $voteChamps, $protoChamps ".
690
		$requete = "SELECT $voteChamps, $protoChamps ".
704
			'FROM del_image_vote AS v '.
691
			'FROM del_image_vote AS v '.
705
			'	INNER JOIN del_image_protocole AS p ON (v.ce_protocole = p.id_protocole) '.
692
			'	INNER JOIN del_image_protocole AS p ON (v.ce_protocole = p.id_protocole) '.
706
			"WHERE v.ce_image IN ($idImgsConcat) ".
693
			"WHERE v.ce_image IN ($idImgsConcat) ".
707
			($protocole ? "	AND v.ce_protocole = $protocole " : '').
694
			($protocole ? "	AND v.ce_protocole = $protocole " : '').
708
			"ORDER BY FIELD(v.ce_image, $idImgsConcat) ".
695
			"ORDER BY FIELD(v.ce_image, $idImgsConcat) ".
709
			'-- '.__FILE__.':'.__LINE__;
696
			'-- '.__FILE__.':'.__LINE__;
710
		return $this->bdd->recupererTous($requete);
697
		return $this->bdd->recupererTous($requete);
711
	}
698
	}
712
 
699
 
713
	/**
700
	/**
714
	 * Ajoute les informations sur le protocole et les votes aux images.
701
	 * Ajoute les informations sur le protocole et les votes aux images.
715
	 *
702
	 *
716
	 * ATTENTION : Subtilité, nous passons ici le tableau d'images indexé par id_image qui est bien
703
	 * ATTENTION : Subtilité, nous passons ici le tableau d'images indexé par id_image qui est bien
717
	 * plus pratique pour associer les vote à un tableau, puisque nous ne connaissons pas les id d'observation.
704
	 * plus pratique pour associer les vote à un tableau, puisque nous ne connaissons pas les id d'observation.
718
	 * Mais magiquement (par référence), cela va remplir notre tableau indexé par couple d'id (id_image, id_observation)
705
	 * Mais magiquement (par référence), cela va remplir notre tableau indexé par couple d'id (id_image, id_observation)
719
	 * cf ListeImages::reformateImagesDoubleIndex() à qui revient la tâche de créer ces deux versions
706
	 * cf ListeImages::reformateImagesDoubleIndex() à qui revient la tâche de créer ces deux versions
720
	 * simultanément lorsque c'est encore possible.
707
	 * simultanément lorsque c'est encore possible.
721
	 */
708
	 */
722
	// TODO : supprimer cette "subtilité" source d'erreurs
709
	// TODO : supprimer cette "subtilité" source d'erreurs
723
	public function ajouterInfosVotesProtocoles($votes, &$images) {
710
	public function ajouterInfosVotesProtocoles($votes, &$images) {
724
		if (!$votes) return;
711
		if (!$votes) return;
725
 
712
 
726
		$mappingVotes = $this->conteneur->getParametreTableau('votes.mapping');
713
		$mappingVotes = $this->conteneur->getParametreTableau('votes.mapping');
727
		$mappingProtocoles = $this->conteneur->getParametreTableau('protocoles.mapping');
714
		$mappingProtocoles = $this->conteneur->getParametreTableau('protocoles.mapping');
728
 
715
 
729
		// pour chaque vote
716
		// pour chaque vote
730
		foreach ($votes as $vote) {
717
		foreach ($votes as $vote) {
731
			$imgId = $vote['image.id'];
718
			$imgId = $vote['image.id'];
732
			$protoId = $vote['protocole.id'];
719
			$protoId = $vote['protocole.id'];
733
 
720
 
734
			if (!array_key_exists('protocoles_votes', $images[$imgId]) ||
721
			if (!array_key_exists('protocoles_votes', $images[$imgId]) ||
735
					!array_key_exists($protoId, $images[$imgId]['protocoles_votes'])) {
722
					!array_key_exists($protoId, $images[$imgId]['protocoles_votes'])) {
736
				// extrait les champs spécifique au protocole (le LEFT JOIN de chargerVotesImage les ramène en doublons
723
				// extrait les champs spécifique au protocole (le LEFT JOIN de chargerVotesImage les ramène en doublons
737
				$protocole = array_intersect_key($vote, array_flip($mappingProtocoles));
724
				$protocole = array_intersect_key($vote, array_flip($mappingProtocoles));
738
				$images[$imgId]['protocoles_votes'][$protoId] = $protocole;
725
				$images[$imgId]['protocoles_votes'][$protoId] = $protocole;
739
			}
726
			}
740
 
727
 
741
			$chpsVotes = array('id_vote', 'ce_image', 'ce_utilisateur', 'valeur', 'date');
728
			$chpsVotes = array('id_vote', 'ce_image', 'ce_utilisateur', 'valeur', 'date');
742
			$voteSelection = array_intersect_key($mappingVotes, array_flip($chpsVotes));
729
			$voteSelection = array_intersect_key($mappingVotes, array_flip($chpsVotes));
743
			$vote = array_intersect_key($vote, array_flip($voteSelection));
730
			$vote = array_intersect_key($vote, array_flip($voteSelection));
744
			$images[$imgId]['protocoles_votes'][$protoId]['votes'][$vote['vote.id']] = $vote;
731
			$images[$imgId]['protocoles_votes'][$protoId]['votes'][$vote['vote.id']] = $vote;
745
		}
732
		}
746
	}
733
	}
747
 
734
 
748
	public function getTotalLignesTrouvees() {
735
	public function getTotalLignesTrouvees() {
749
		$resultat = $this->bdd->recuperer('SELECT FOUND_ROWS() AS nbre -- '.__FILE__.':'.__LINE__);
736
		$resultat = $this->bdd->recuperer('SELECT FOUND_ROWS() AS nbre -- '.__FILE__.':'.__LINE__);
750
		return intval($resultat['nbre']);
737
		return intval($resultat['nbre']);
751
	}
738
	}
752
}
739
}