Subversion Repositories eFlore/Applications.del

Rev

Rev 1451 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1451 Rev 1486
Line 51... Line 51...
51
 * - *peut-être*: passer requestFilterParams() en méthode de classe
51
 * - *peut-être*: passer requestFilterParams() en méthode de classe
52
 *
52
 *
53
 *
53
 *
54
 * MySQL sux:
54
 * MySQL sux:
55
 * EXPLAIN SELECT  id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1 LIMIT 1);
55
 * EXPLAIN SELECT  id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1 LIMIT 1);
56
 *  MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery
56
 *	MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery
57
 * EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT 3);
57
 * EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT 3);
58
 *  PRIMARY
58
 *	PRIMARY
59
 * EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT MIN(3));
59
 * EXPLAIN SELECT * FROM del_image WHERE id_image IN (SELECT MIN(3));
60
 *  DEPENDENT SUBQUERY ... ... ... mwarf !
60
 *	DEPENDENT SUBQUERY ... ... ... mwarf !
61
 * EXPLAIN SELECT  id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1);
61
 * EXPLAIN SELECT  id_image FROM v_del_image vdi WHERE vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1);
62
 *  5.5: MATERIALIZED		del_image_tag	ALL				ce_image NULL NULL NULL 38276 Using where
62
 *	5.5: MATERIALIZED		del_image_tag	ALL				ce_image NULL NULL NULL 38276 Using where
63
 *  5.1: DEPENDENT SUBQUERY	del_image_tag	index_subquery	ce_image ce_image 8 func 1 Using where
63
 *	5.1: DEPENDENT SUBQUERY	del_image_tag	index_subquery	ce_image ce_image 8 func 1 Using where
64
 * FORCE INDEX/IGNORE INDEX semble incapable de résoudre le problème de l'optimiseur MySQL
64
 * FORCE INDEX/IGNORE INDEX semble incapable de résoudre le problème de l'optimiseur MySQL
65
 *
65
 *
66
 */
66
 */
Line 67... Line 67...
67
 
67
 
Line 85... Line 85...
85
 
85
 
86
	// en plus de ceux dans ListeObservations
86
	// en plus de ceux dans ListeObservations
Line 87... Line 87...
87
	static $parametres_autorises = array('protocole', 'masque.tag_cel', 'masque.tag_pictoflora', 'masque.milieu');
87
	static $parametres_autorises = array('protocole', 'masque.tag_cel', 'masque.tag_pictoflora', 'masque.milieu');
88
 
88
 
89
	static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10,
89
	static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10,
90
								   'tri' => 'date_transmission', 'ordre' => 'desc',
90
    'tri' => 'date_transmission', 'ordre' => 'desc',
Line 91... Line 91...
91
								   // spécifiques à PictoFlora:
91
    // spécifiques à PictoFlora:
Line 92... Line 92...
92
								   'format' => 'XL');
92
    'format' => 'XL');
93
 
93
 
Line 150... Line 150...
150
		// filtrage de l'INPUT général, on réutilise 90% de identiplante en terme de paramètres autorisés
150
		// filtrage de l'INPUT général, on réutilise 90% de identiplante en terme de paramètres autorisés
151
		// ($parametres_autorises) sauf... masque.type qui fait des modif' de WHERE sur les mots-clefs.
151
		// ($parametres_autorises) sauf... masque.type qui fait des modif' de WHERE sur les mots-clefs.
152
		// Évitons ce genre de chose pour PictoFlora et les risques de conflits avec masque.tag
152
		// Évitons ce genre de chose pour PictoFlora et les risques de conflits avec masque.tag
153
		// même si ceux-ci sont improbables (pas d'<input> pour cela).
153
		// même si ceux-ci sont improbables (pas d'<input> pour cela).
154
		$params_ip = ListeObservations::requestFilterParams($parametres,
154
		$params_ip = ListeObservations::requestFilterParams($parametres,
155
														  array_diff(ListeObservations::$parametres_autorises,
155
        array_diff(ListeObservations::$parametres_autorises,
156
																	 array('masque.type')),
156
        array('masque.type')),
157
														  $this->conteneur);
157
        $this->conteneur);
Line 158... Line 158...
158
 
158
 
159
		// notre propre filtrage sur l'INPUT
159
		// notre propre filtrage sur l'INPUT
160
		$params_pf = self::requestFilterParams($parametres,
160
		$params_pf = self::requestFilterParams($parametres,
161
											   array_merge(ListeObservations::$parametres_autorises,
161
        array_merge(ListeObservations::$parametres_autorises,
Line 162... Line 162...
162
														   self::$parametres_autorises));
162
        self::$parametres_autorises));
163
 
163
 
164
		/* filtrage des tags + sémantique des valeurs multiples:
164
		/* filtrage des tags + sémantique des valeurs multiples:
165
		   Lorsqu'on utilise masque.tag* pour chercher des tags, ils sont
165
		   Lorsqu'on utilise masque.tag* pour chercher des tags, ils sont
166
		   postulés comme séparés par des virgule, et l'un au moins des tags doit matcher. */
166
		   postulés comme séparés par des virgule, et l'un au moins des tags doit matcher. */
Line 167... Line 167...
167
		$params_pf['masque.tag_cel'] = self::buildTagsAST(@$parametres['masque.tag_cel'], 'OR', ',');
167
		$params_pf['masque.tag_cel'] = self::buildTagsAST(@$parametres['masque.tag_cel'], 'OR', ',');
168
		$params_pf['masque.tag_pictoflora'] = self::buildTagsAST(@$parametres['masque.tag_pictoflora'], 'OR', ',');
168
		$params_pf['masque.tag_pictoflora'] = self::buildTagsAST(@$parametres['masque.tag_pictoflora'], 'OR', ',');
169
 
169
 
170
		$params = array_merge(ListeObservations::$default_params, // paramètre par défaut Identiplante
170
		$params = array_merge(ListeObservations::$default_params, // paramètre par défaut Identiplante
Line 171... Line 171...
171
							  self::$default_params, // paramètres par défaut PictoFlora
171
        self::$default_params, // paramètres par défaut PictoFlora
172
							  $params_ip, // les paramètres passés, traités par Identiplante
172
        $params_ip, // les paramètres passés, traités par Identiplante
173
							  $params_pf); // les paramètres passés, traités par PictoFlora
173
        $params_pf); // les paramètres passés, traités par PictoFlora
Line 191... Line 191...
191
 
191
 
192
		// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats dans la table del_obs_images
192
		// Ce n'est pas la peine de continuer s'il n'y a pas eu de résultats dans la table del_obs_images
193
		if(!$idobs_tab) {
193
		if(!$idobs_tab) {
194
			$resultat = new ResultatService();
194
			$resultat = new ResultatService();
195
			$resultat->corps = array('entete' => ListeObservations::makeJSONHeader(0, $params, Config::get('url_service')),
195
			$resultat->corps = array('entete' => ListeObservations::makeJSONHeader(0, $params, Config::get('url_service')),
196
									 'resultats' => array());
196
            'resultats' => array());
197
			return $resultat;
197
			return $resultat;
198
			/*
198
			/*
199
			header('HTTP/1.0 404 Not Found');
199
              header('HTTP/1.0 404 Not Found');
200
			// don't die (phpunit)
200
              // don't die (phpunit)
201
			throw(new Exception()); */
201
              throw(new Exception()); */
Line 202... Line 202...
202
		}
202
		}
203
 
203
 
204
 
204
 
Line 205... Line 205...
205
		// idobs est une liste (toujours ordonnée) des id d'observations recherchées
205
		// idobs est une liste (toujours ordonnée) des id d'observations recherchées
Line 206... Line 206...
206
		$idobs = array_values(array_map(create_function('$a', 'return $a["id_image"];'), $idobs_tab));
206
		$idobs = array_values(array_map(create_function('$a', 'return $a["id_image"];'), $idobs_tab));
207
		$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']);
207
		$total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']);
208
 
208
 
209
		$liaisons = self::chargerImages($db, $idobs);
209
		$liaisons = self::chargerImages($db, $idobs);
210
 
210
 
211
		/* 
211
		/* 
212
		   // Q&D
212
        // Q&D
213
		   $images = array();
213
        $images = array();
214
		   $o = new Observation($this->conteneur);
214
        $o = new Observation($this->conteneur);
215
		   foreach($idobs as $i) {
215
        foreach($idobs as $i) {
216
		   $images[$i] = $o->consulter(array($i), array('justthrow' => 1));
216
        $images[$i] = $o->consulter(array($i), array('justthrow' => 1));
217
		   }
217
        }
Line 233... Line 233...
233
		if($votes) Observation::mapVotesToImages($votes, $images_keyed_by_id_image);
233
		if($votes) Observation::mapVotesToImages($votes, $images_keyed_by_id_image);
Line 234... Line 234...
234
 
234
 
235
		// les deux masques de tags sont transformés en AST dans le processus de construction de la requête.
235
		// les deux masques de tags sont transformés en AST dans le processus de construction de la requête.
236
		// Reprenous les paramètres originaux non-nettoyés (ils sont valables car le nettoyage est déterministe)
236
		// Reprenous les paramètres originaux non-nettoyés (ils sont valables car le nettoyage est déterministe)
237
		$params_header = array_merge($params, array_filter(array('masque.tag_cel' => @$parametres['masque.tag_cel'],
237
		$params_header = array_merge($params, array_filter(array('masque.tag_cel' => @$parametres['masque.tag_cel'],
238
																 'masque.tag_pictoflora' => @$parametres['masque.tag_pictoflora'])));
238
        'masque.tag_pictoflora' => @$parametres['masque.tag_pictoflora'])));
239
		$resultat = new ResultatService();
239
		$resultat = new ResultatService();
240
		$resultat->corps = array('entete' => ListeObservations::makeJSONHeader($total, $params_header, Config::get('url_service')),
240
		$resultat->corps = array('entete' => ListeObservations::makeJSONHeader($total, $params_header, Config::get('url_service')),
241
								 'resultats' => $images);
241
        'resultats' => $images);
242
		return $resultat;
242
		return $resultat;
Line 243... Line 243...
243
	}
243
	}
244
 
244
 
Line 301... Line 301...
301
		/* Pour le tri par AVG() des votes nous avons toujours un protocole donné,
301
		/* Pour le tri par AVG() des votes nous avons toujours un protocole donné,
302
		   celui-ci indique sur quels votes porte l'AVG.
302
		   celui-ci indique sur quels votes porte l'AVG.
303
		   (c'est un *vote* qui porte sur un protocole et non l'image elle-même) */
303
		   (c'est un *vote* qui porte sur un protocole et non l'image elle-même) */
304
		/* TODO: perf problème:
304
		/* TODO: perf problème:
305
		   1) SQL_CALC_FOUND_ROWS: fixable en:
305
		   1) SQL_CALC_FOUND_ROWS: fixable en:
306
		   	- dissociant le comptage de la récup d'id + javascript async
306
           - dissociant le comptage de la récup d'id + javascript async
307
			- ou ne rafraîchir le total *que* pour les requête impliquant un changement de pagination
307
           - ou ne rafraîchir le total *que* pour les requête impliquant un changement de pagination
308
				(paramètre booléen "with-total" par exemple)
308
           (paramètre booléen "with-total" par exemple)
309
		   2) jointure forcées: en utilisant `del_imagè`, nous forçons les 2 premiers
309
		   2) jointure forcées: en utilisant `del_imagè`, nous forçons les 2 premiers
310
		   	JOIN sur cel_obs_images et cel_obs pour filtrer sur "transmission".
310
           JOIN sur cel_obs_images et cel_obs pour filtrer sur "transmission".
311
			Dénormaliser cette valeur et l'intégrer à `cel_images` ferait économiser cette couteuse
311
           Dénormaliser cette valeur et l'intégrer à `cel_images` ferait économiser cette couteuse
312
			jointure, ... lorsqu'aucun masque portant sur `cel_obs` n'est utilisé
312
           jointure, ... lorsqu'aucun masque portant sur `cel_obs` n'est utilisé
313
		   3) non-problème: l'ordre des joins est forcé par l'usage de la vue:
313
		   3) non-problème: l'ordre des joins est forcé par l'usage de la vue:
314
		   	(cel_images/cel_obs_images/cel_obs/del_image_stat)
314
           (cel_images/cel_obs_images/cel_obs/del_image_stat)
315
			Cependant c'est à l'optimiseur de définir son ordre préféré. */
315
           Cependant c'est à l'optimiseur de définir son ordre préféré. */
316
		if($p['tri'] == 'votes') {
316
		if($p['tri'] == 'votes') {
317
			// $p['protocole'] *est* défini (cf requestFilterParams())
317
			// $p['protocole'] *est* défini (cf requestFilterParams())
318
			// petite optimisation: INNER JOIN si ordre DESC car les 0 à la fin
318
			// petite optimisation: INNER JOIN si ordre DESC car les 0 à la fin
319
			if($p['ordre'] == 'desc') {
319
			if($p['ordre'] == 'desc') {
320
				// pas de group by nécessaire pour cette jointure
320
				// pas de group by nécessaire pour cette jointure
321
				// PRIMARY KEY (`ce_image`, `ce_protocole`)
321
				// PRIMARY KEY (`ce_image`, `ce_protocole`)
322
				$req['join'][] = sprintf('INNER JOIN del_image_stat dis'.
322
				$req['join'][] = sprintf('INNER JOIN del_image_stat dis'.
323
										 ' ON vdi.id_image = dis.ce_image'.
323
                ' ON vdi.id_image = dis.ce_image'.
324
										 ' AND dis.ce_protocole = %d',
324
                ' AND dis.ce_protocole = %d',
325
										 $p['protocole']);
325
                $p['protocole']);
326
			} else {
326
			} else {
327
				$req['join'][] = sprintf('LEFT JOIN del_image_stat dis'.
327
				$req['join'][] = sprintf('LEFT JOIN del_image_stat dis'.
328
										 ' ON vdi.id_image = dis.ce_image'.
328
                ' ON vdi.id_image = dis.ce_image'.
329
										 ' AND dis.ce_protocole = %d',
329
                ' AND dis.ce_protocole = %d',
330
										 $p['protocole']);
330
                $p['protocole']);
331
				// nécessaire (dup ce_image dans del_image_stat)
331
				// nécessaire (dup ce_image dans del_image_stat)
332
				$req['groupby'][] = 'vdi.id_observation';
332
				$req['groupby'][] = 'vdi.id_observation';
333
			}
333
			}
334
		}
334
		}
Line 335... Line 335...
335
 
335
 
336
		if($p['tri'] == 'tags') {
336
		if($p['tri'] == 'tags') {
337
			$req['join'][] = sprintf('%s JOIN del_image_stat dis ON vdi.id_image = dis.ce_image',
337
			$req['join'][] = sprintf('%s JOIN del_image_stat dis ON vdi.id_image = dis.ce_image',
338
									 ($p['ordre'] == 'desc') ? 'INNER' : 'LEFT');
338
            ($p['ordre'] == 'desc') ? 'INNER' : 'LEFT');
339
			// nécessaire (dup ce_image dans del_image_stat)
339
			// nécessaire (dup ce_image dans del_image_stat)
340
			$req['groupby'][] = 'vdi.id_observation';
340
			$req['groupby'][] = 'vdi.id_observation';
Line 341... Line 341...
341
		}
341
		}
Line 346... Line 346...
346
			if(isset($p['masque.tag_cel']['AND'])) {
346
			if(isset($p['masque.tag_cel']['AND'])) {
347
				// TODO: utiliser les tables de mots clefs normaliées dans tb_cel ?
347
				// TODO: utiliser les tables de mots clefs normaliées dans tb_cel ?
348
				// et auquel cas laisser au client le choix du couteux "%" ?
348
				// et auquel cas laisser au client le choix du couteux "%" ?
349
				$tags = $p['masque.tag_cel']['AND'];
349
				$tags = $p['masque.tag_cel']['AND'];
350
				array_walk($tags, create_function('&$val, $k, $db',
350
				array_walk($tags, create_function('&$val, $k, $db',
351
												  '$val = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) LIKE %s",
351
                '$val = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) LIKE %s",
352
 																  $db->proteger("%".$val."%"));'),
352
																  $db->proteger("%".$val."%"));'),
353
						   $db);
353
                $db);
354
				$req['where'][] = '(' . implode(' AND ', $tags) . ')';
354
				$req['where'][] = '(' . implode(' AND ', $tags) . ')';
355
			}
355
			}
356
			else {
356
			else {
357
				$req['where'][] = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) REGEXP %s",
357
				$req['where'][] = sprintf("CONCAT(vdi.mots_cles_texte,vdi.i_mots_cles_texte) REGEXP %s",
358
										  $db->proteger(implode('|', $p['masque.tag_cel']['OR'])));
358
                $db->proteger(implode('|', $p['masque.tag_cel']['OR'])));
359
			}
359
			}
360
		}
360
		}
Line 361... Line 361...
361
 
361
 
362
 
362
 
363
		// XXX: utiliser tag plutôt que tag_normalise ?
363
		// XXX: utiliser tag plutôt que tag_normalise ?
364
		if($p['masque.tag_pictoflora']) {
364
		if($p['masque.tag_pictoflora']) {
365
			// pas de LEFT JOIN ? ou bien peut-être en cas de tri, mais nous parlons bien ici d'un masque
365
			// pas de LEFT JOIN ? ou bien peut-être en cas de tri, mais nous parlons bien ici d'un masque
Line -... Line 366...
-
 
366
			/* $req['join'][] = 'LEFT JOIN del_image_tag dit ON dit.ce_image = vdi.id_image';
-
 
367
			   $req['where'][] = 'dit.actif = 1'; */
-
 
368
 
-
 
369
 
-
 
370
 
-
 
371
			// ==== commenté pour l'instant pour cause de soucis d'optimiseur MySQL (cf commentaire en intro) ====
-
 
372
			/*
-
 
373
              if(isset($p['masque.tag_pictoflora']['AND'])) {
-
 
374
              // optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT()
-
 
375
              // donc nous utilisons des ".*" plutôt que de multiples conditions et "|"
-
 
376
              sort($p['masque.tag_pictoflora']['AND']);
-
 
377
              $req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1".
-
 
378
              " GROUP BY ce_image".
-
 
379
              " HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s)",
-
 
380
              $db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND'])));
-
 
381
              }
-
 
382
              else {
-
 
383
              $req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1".
-
 
384
              " GROUP BY ce_image".
-
 
385
              " HAVING GROUP_CONCAT(tag_normalise) REGEXP %s)",
-
 
386
              $db->proteger(implode('|', $p['masque.tag_pictoflora']['OR'])));
-
 
387
              }
366
			/* $req['join'][] = 'LEFT JOIN del_image_tag dit ON dit.ce_image = vdi.id_image';
388
			*/
367
			   $req['where'][] = 'dit.actif = 1'; */
389
 
368
 
390
			// ==== XXX: puisque on est bassiné par cette "DEPENDENT SUBQUERY", nous la faisons donc indépendemment ====
369
			if(isset($p['masque.tag_pictoflora']['AND'])) {
391
			if(isset($p['masque.tag_pictoflora']['AND'])) {
-
 
392
				// optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT()
-
 
393
				// donc nous utilisons des ".*" plutôt que de multiples conditions et "|"
-
 
394
				sort($p['masque.tag_pictoflora']['AND']);
370
				// optimsation: en cas de "AND" on sort() l'input et le GROUP_CONCAT()
395
 
371
				// donc nous utilisons des ".*" plutôt que de multiples conditions et "|"
396
				// plutôt que db->connexion->query->fetchColumn(), une API pourrie nous oblige à ...
372
				sort($p['masque.tag_pictoflora']['AND']);
397
				$ids = $db->recupererTous(sprintf(
373
				$req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1".
398
					"SELECT ce_image FROM del_image_tag WHERE actif = 1".
-
 
399
					" GROUP BY ce_image".
-
 
400
					" HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s",
-
 
401
					$db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND']))));
-
 
402
				// puis:
374
										  " GROUP BY ce_image".
403
				$ids = array_map(create_function('$e', 'return $e["ce_image"];'), $ids);
375
										  " HAVING GROUP_CONCAT(tag_normalise ORDER BY tag_normalise) REGEXP %s)",
404
				if($ids) $req['where'][] = sprintf("vdi.id_image IN (%s)", implode(',', $ids));
-
 
405
 
376
										  $db->proteger(implode('.*', $p['masque.tag_pictoflora']['AND'])));
406
			}
377
			}
407
			else {
378
			else {
408
				$ids = $db->recupererTous(sprintf(
379
				$req['where'][] = sprintf("vdi.id_image IN (SELECT ce_image FROM del_image_tag WHERE actif = 1".
409
					"SELECT ce_image FROM del_image_tag WHERE actif = 1".
-
 
410
					" GROUP BY ce_image".
-
 
411
					" HAVING GROUP_CONCAT(tag_normalise) REGEXP %s",
380
										  " GROUP BY ce_image".
412
					$db->proteger(implode('|', $p['masque.tag_pictoflora']['OR']))));
-
 
413
				$ids = array_map(create_function('$e', 'return $e["ce_image"];'), $ids);
381
										  " HAVING GROUP_CONCAT(tag_normalise) REGEXP %s)",
414
				if($ids) $req['where'][] = sprintf("vdi.id_image IN (%s)", implode(',', $ids));
382
										  $db->proteger(implode('|', $p['masque.tag_pictoflora']['OR'])));
415
			}
Line 383... Line 416...
383
			}
416
 
Line 409... Line 442...
409
	static function chargerImages($db, $idImg) {
442
	static function chargerImages($db, $idImg) {
410
		$obs_fields = Observation::sqlFieldsToAlias(self::$mappings['observations'], NULL);
443
		$obs_fields = Observation::sqlFieldsToAlias(self::$mappings['observations'], NULL);
411
		$image_fields = Observation::sqlFieldsToAlias(self::$mappings['images'], NULL);
444
		$image_fields = Observation::sqlFieldsToAlias(self::$mappings['images'], NULL);
Line 412... Line 445...
412
	
445
	
413
		return $db->recupererTous(sprintf('SELECT '.
446
		return $db->recupererTous(sprintf('SELECT '.
414
										  ' CONCAT(id_image, "-", id_observation) AS jsonindex,'.
447
        ' CONCAT(id_image, "-", id_observation) AS jsonindex,'.
415
										  ' %1$s, %2$s FROM v_del_image '.
448
        ' %1$s, %2$s FROM v_del_image '.
416
										  ' WHERE %3$s'.
449
        ' WHERE %3$s'.
417
										  ' -- %4$s',
450
        ' -- %4$s',
418
										  $obs_fields, $image_fields,
451
        $obs_fields, $image_fields,
419
										  sprintf('id_image IN (%s)', implode(',', $idImg)),
452
        sprintf('id_image IN (%s)', implode(',', $idImg)),
Line 420... Line 453...
420
										  __FILE__ . ':' . __LINE__));
453
        __FILE__ . ':' . __LINE__));
Line 421... Line 454...
421
 
454
 
422
	}
455
	}
423
 
456
 
424
	/* "masque" ne fait jamais que faire une requête sur la plupart des champs, (presque) tous traités
457
	/* "masque" ne fait jamais que faire une requête sur la plupart des champs, (presque) tous traités
425
	   de manière identique à la seule différence que:
458
	   de manière identique à la seule différence que:
426
	   1) ils sont combinés par des "OU" logiques plutôt que des "ET".
459
	   1) ils sont combinés par des "OU" logiques plutôt que des "ET".
427
	   2) les tags sont traités différemment pour conserver la compatibilité avec l'utilisation historique:
460
	   2) les tags sont traités différemment pour conserver la compatibilité avec l'utilisation historique:
428
	   	  Tous les mots-clefs doivent matcher et sont séparés par des espaces
461
       Tous les mots-clefs doivent matcher et sont séparés par des espaces
429
		  (dit autrement, str_replace(" ", ".*", $mots-clefs-requête) =~ $mots-clefs-mysql)
462
       (dit autrement, str_replace(" ", ".*", $mots-clefs-requête) =~ $mots-clefs-mysql)
430
	   Pour plus d'information: ListeObservations::sqlAddMasqueConstraint() */
463
	   Pour plus d'information: ListeObservations::sqlAddMasqueConstraint() */
431
	static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
464
	static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
432
		if(!empty($p['masque'])) {
465
		if(!empty($p['masque'])) {
433
			$or_params = array('masque.auteur' => $p['masque'],
466
			$or_params = array('masque.auteur' => $p['masque'],
434
							   'masque.departement' => $p['masque'],
467
            'masque.departement' => $p['masque'],
435
							   'masque.commune' => $p['masque'], // TODO/XXX ?
468
            'masque.commune' => $p['masque'], // TODO/XXX ?
436
							   'masque.id_zone_geo' => $p['masque'],
469
            'masque.id_zone_geo' => $p['masque'],
437
 
470
 
438
							   /* tous-deux remplacent masque.tag
471
            /* tous-deux remplacent masque.tag
439
								  mais sont traité séparément des requestFilterParams() */
472
               mais sont traité séparément des requestFilterParams() */
440
							   // 'masque.tag_cel' => $p['masque'],
473
            // 'masque.tag_cel' => $p['masque'],
441
							   // 'masque.tag_pictoflora' => $p['masque'],
474
            // 'masque.tag_pictoflora' => $p['masque'],
442
 
475
 
443
							   'masque.ns' => $p['masque'],
476
            'masque.ns' => $p['masque'],
444
							   'masque.famille' => $p['masque'],
477
            'masque.famille' => $p['masque'],
445
							   'masque.date' => $p['masque'],
478
            'masque.date' => $p['masque'],
446
							   'masque.genre' => $p['masque'],
479
            'masque.genre' => $p['masque'],
447
							   'masque.milieu' => $p['masque'],
480
            'masque.milieu' => $p['masque'],
448
 
481
 
Line 449... Line 482...
449
							   // tri est aussi nécessaire car affecte les contraintes de JOIN
482
            // tri est aussi nécessaire car affecte les contraintes de JOIN
450
							   'tri' => $p['tri'],
483
            'tri' => $p['tri'],
451
							   'ordre' => $p['ordre']);
484
            'ordre' => $p['ordre']);
Line 550... Line 583...
550
		elseif(preg_match('/\b(OU|OR)\b/', $str)) $op = 'OR';
583
		elseif(preg_match('/\b(OU|OR)\b/', $str)) $op = 'OR';
551
		else $op = $default_op;
584
		else $op = $default_op;
Line 552... Line 585...
552
 
585
 
553
		if($additional_sep) {
586
		if($additional_sep) {
554
			array_walk($words,
587
			array_walk($words,
555
					   create_function('&$v, $k, $sep', '$v = preg_split("/".$sep."/", $v, -1, PREG_SPLIT_NO_EMPTY);'),
588
            create_function('&$v, $k, $sep', '$v = preg_split("/".$sep."/", $v, -1, PREG_SPLIT_NO_EMPTY);'),
556
					   $additional_sep);
589
            $additional_sep);
557
		}
590
		}
558
		$words = self::array_flatten($words);
591
		$words = self::array_flatten($words);
559
		$words = array_map('trim', $words);
592
		$words = array_map('trim', $words);
560
		return array($op => array_filter($words));
593
		return array($op => array_filter($words));
Line 592... Line 625...
592
				next($arr);
625
				next($arr);
593
			}
626
			}
594
		}
627
		}
595
		return $arr;
628
		return $arr;
596
	}
629
	}
597
}
-
 
598
630
}
-
 
631