Line 45... |
Line 45... |
45 |
* - subqueries dans le FROM pour les critère WHERE portant directement sur v_del_image
|
45 |
* - subqueries dans le FROM pour les critère WHERE portant directement sur v_del_image
|
46 |
* plutôt que dans WHERE (qui nécessite dès lors un FULL-JOIN)
|
46 |
* plutôt que dans WHERE (qui nécessite dès lors un FULL-JOIN)
|
47 |
* (http://www.mysqlperformanceblog.com/2007/04/06/using-delayed-join-to-optimize-count-and-limit-queries/)
|
47 |
* (http://www.mysqlperformanceblog.com/2007/04/06/using-delayed-join-to-optimize-count-and-limit-queries/)
|
48 |
* - éviter de dépendre d'une jointure systématique sur `cel_obs`, uniquement pour `(date_)transmission
|
48 |
* - éviter de dépendre d'une jointure systématique sur `cel_obs`, uniquement pour `(date_)transmission
|
49 |
* (cf VIEW del_image)
|
49 |
* (cf VIEW del_image)
|
50 |
* - réorganiser les méthodes statiques parmis Observation, ListeObservations2 et ListImages2
|
50 |
* - réorganiser les méthodes statiques parmis Observation, ListeObservations et ListImages2
|
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);
|
Line 63... |
Line 63... |
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 |
|
68 |
require_once(dirname(__FILE__) . '/../observations/ListeObservations2.php');
|
68 |
require_once(dirname(__FILE__) . '/../observations/ListeObservations.php');
|
69 |
require_once(dirname(__FILE__) . '/../observations/Observation.php');
|
69 |
require_once(dirname(__FILE__) . '/../observations/Observation.php');
|
70 |
restore_error_handler();
|
70 |
restore_error_handler();
|
71 |
restore_exception_handler();
|
71 |
restore_exception_handler();
|
Line 81... |
Line 81... |
81 |
// TODO: PHP-x.y, ces variables devrait être des "const"
|
81 |
// TODO: PHP-x.y, ces variables devrait être des "const"
|
82 |
static $format_image_possible = array('O','CRX2S','CRS','CXS','CS','XS','S','M','L','XL','X2L','X3L');
|
82 |
static $format_image_possible = array('O','CRX2S','CRS','CXS','CS','XS','S','M','L','XL','X2L','X3L');
|
Line 83... |
Line 83... |
83 |
|
83 |
|
Line 84... |
Line 84... |
84 |
static $tri_possible = array('date_transmission', 'date_observation', 'votes', 'tags');
|
84 |
static $tri_possible = array('date_transmission', 'date_observation', 'votes', 'tags');
|
85 |
|
85 |
|
Line 86... |
Line 86... |
86 |
// en plus de ceux dans ListeObservations2
|
86 |
// en plus de ceux dans ListeObservations
|
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 |
|
Line 149... |
Line 149... |
149 |
|
149 |
|
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 = ListeObservations2::requestFilterParams($parametres,
|
154 |
$params_ip = ListeObservations::requestFilterParams($parametres,
|
155 |
array_diff(ListeObservations2::$parametres_autorises,
|
155 |
array_diff(ListeObservations::$parametres_autorises,
|
156 |
array('masque.type')),
|
156 |
array('masque.type')),
|
Line 157... |
Line 157... |
157 |
$this->conteneur);
|
157 |
$this->conteneur);
|
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,
|
Line 161... |
Line 161... |
161 |
array_merge(ListeObservations2::$parametres_autorises,
|
161 |
array_merge(ListeObservations::$parametres_autorises,
|
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
|
Line 166... |
Line 166... |
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. */
|
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 |
|
Line 170... |
Line 170... |
170 |
$params = array_merge(ListeObservations2::$default_params, // paramètre par défaut Identiplante
|
170 |
$params = array_merge(ListeObservations::$default_params, // paramètre par défaut Identiplante
|
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
|
Line 173... |
Line 173... |
173 |
$params_pf); // les paramètres passés, traités par PictoFlora
|
173 |
$params_pf); // les paramètres passés, traités par PictoFlora
|
174 |
|
174 |
|
175 |
// XXX: temp tweak
|
175 |
// XXX: temp tweak
|
176 |
/* $this->conteneur->setParametre('url_images', sprintf($this->conteneur->getParametre('url_images'),
|
176 |
/* $this->conteneur->setParametre('url_images', sprintf($this->conteneur->getParametre('url_images'),
|
177 |
"%09d", $params['format']));*/
|
177 |
"%09d", $params['format']));*/
|
178 |
|
178 |
|
179 |
// création des contraintes (génériques, de ListeObservations2)
|
179 |
// création des contraintes (génériques, de ListeObservations)
|
180 |
ListeObservations2::sqlAddConstraint($params, $db, $req, $this->conteneur);
|
180 |
ListeObservations::sqlAddConstraint($params, $db, $req, $this->conteneur);
|
Line 181... |
Line 181... |
181 |
// création des contraintes spécifiques (sur les tags essentiellement)
|
181 |
// création des contraintes spécifiques (sur les tags essentiellement)
|
182 |
self::sqlAddConstraint($params, $db, $req, $this->conteneur);
|
182 |
self::sqlAddConstraint($params, $db, $req, $this->conteneur);
|
183 |
// création des contraintes spécifiques impliquées par le masque général
|
183 |
// création des contraintes spécifiques impliquées par le masque général
|
Line 184... |
Line 184... |
184 |
self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur);
|
184 |
self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur);
|
185 |
// l'ORDER BY s'avére complexe
|
185 |
// l'ORDER BY s'avére complexe
|
186 |
self::sqlOrderBy($params, $db, $req);
|
186 |
self::sqlOrderBy($params, $db, $req);
|
187 |
|
187 |
|
188 |
// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS)
|
188 |
// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS)
|
189 |
// $idobs_tab = ListeObservations2::getIdObs($params, $req, $db);
|
189 |
// $idobs_tab = ListeObservations::getIdObs($params, $req, $db);
|
190 |
$idobs_tab = self::getIdImages($params, $req, $db);
|
190 |
$idobs_tab = self::getIdImages($params, $req, $db);
|
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
|
Line 214... |
Line 214... |
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 |
}
|
218 |
*/
|
218 |
*/
|
219 |
list($images, $images_keyed_by_id_image) = ListeObservations2::reformateImagesDoubleIndex(
|
219 |
list($images, $images_keyed_by_id_image) = ListeObservations::reformateImagesDoubleIndex(
|
220 |
$liaisons,
|
220 |
$liaisons,
|
221 |
$this->conteneur->getParametre('url_images'),
|
221 |
$this->conteneur->getParametre('url_images'),
|
222 |
$params['format']);
|
222 |
$params['format']);
|
Line 235... |
Line 235... |
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' => ListeObservations2::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;
|
243 |
}
|
243 |
}
|
Line 244... |
Line 244... |
244 |
|
244 |
|
Line 290... |
Line 290... |
290 |
* équivalent à:
|
290 |
* équivalent à:
|
291 |
* (split sur " ", "OR" entre chaque condition, "AND" pour chaque valeur de tag)
|
291 |
* (split sur " ", "OR" entre chaque condition, "AND" pour chaque valeur de tag)
|
292 |
*
|
292 |
*
|
293 |
*/
|
293 |
*/
|
294 |
static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) {
|
294 |
static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) {
|
295 |
// TODO implement dans ListeObservations2 ?
|
295 |
// TODO implement dans ListeObservations ?
|
296 |
if(!empty($p['masque.milieu'])) {
|
296 |
if(!empty($p['masque.milieu'])) {
|
297 |
$req['where'][] = 'vdi.milieu LIKE '.$db->proteger('%' . $p['masque.milieu'].'%');
|
297 |
$req['where'][] = 'vdi.milieu LIKE '.$db->proteger('%' . $p['masque.milieu'].'%');
|
298 |
}
|
298 |
}
|
Line 425... |
Line 425... |
425 |
de manière identique à la seule différence que:
|
425 |
de manière identique à la seule différence que:
|
426 |
1) ils sont combinés par des "OU" logiques plutôt que des "ET".
|
426 |
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:
|
427 |
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
|
428 |
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)
|
429 |
(dit autrement, str_replace(" ", ".*", $mots-clefs-requête) =~ $mots-clefs-mysql)
|
430 |
Pour plus d'information: ListeObservations2::sqlAddMasqueConstraint() */
|
430 |
Pour plus d'information: ListeObservations::sqlAddMasqueConstraint() */
|
431 |
static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
|
431 |
static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
|
432 |
if(!empty($p['masque'])) {
|
432 |
if(!empty($p['masque'])) {
|
433 |
$or_params = array('masque.auteur' => $p['masque'],
|
433 |
$or_params = array('masque.auteur' => $p['masque'],
|
434 |
'masque.departement' => $p['masque'],
|
434 |
'masque.departement' => $p['masque'],
|
435 |
'masque.commune' => $p['masque'], // TODO/XXX ?
|
435 |
'masque.commune' => $p['masque'], // TODO/XXX ?
|
Line 449... |
Line 449... |
449 |
// tri est aussi nécessaire car affecte les contraintes de JOIN
|
449 |
// tri est aussi nécessaire car affecte les contraintes de JOIN
|
450 |
'tri' => $p['tri'],
|
450 |
'tri' => $p['tri'],
|
451 |
'ordre' => $p['ordre']);
|
451 |
'ordre' => $p['ordre']);
|
Line 452... |
Line 452... |
452 |
|
452 |
|
453 |
$or_masque = array_merge(
|
453 |
$or_masque = array_merge(
|
454 |
ListeObservations2::requestFilterParams($or_params, NULL, $c /* pour masque.departement */),
|
454 |
ListeObservations::requestFilterParams($or_params, NULL, $c /* pour masque.departement */),
|
Line 455... |
Line 455... |
455 |
self::requestFilterParams($or_params));
|
455 |
self::requestFilterParams($or_params));
|
456 |
|
456 |
|
457 |
/* Lorsqu'on utilise le masque général pour chercher des tags, ils sont
|
457 |
/* Lorsqu'on utilise le masque général pour chercher des tags, ils sont
|
458 |
postulés comme séparés par des espaces, et doivent être tous matchés. */
|
458 |
postulés comme séparés par des espaces, et doivent être tous matchés. */
|
Line 459... |
Line 459... |
459 |
$or_masque['masque.tag_cel'] = self::buildTagsAST($p['masque'], 'AND', ' ');
|
459 |
$or_masque['masque.tag_cel'] = self::buildTagsAST($p['masque'], 'AND', ' ');
|
460 |
$or_masque['masque.tag_pictoflora'] = self::buildTagsAST($p['masque'], 'AND', ' ');
|
460 |
$or_masque['masque.tag_pictoflora'] = self::buildTagsAST($p['masque'], 'AND', ' ');
|
461 |
|
461 |
|
462 |
|
462 |
|
Line 463... |
Line 463... |
463 |
// pas de select, groupby & co ici: uniquement 'join' et 'where'
|
463 |
// pas de select, groupby & co ici: uniquement 'join' et 'where'
|
464 |
$or_req = array('join' => array(), 'where' => array());
|
464 |
$or_req = array('join' => array(), 'where' => array());
|
465 |
ListeObservations2::sqlAddConstraint($or_masque, $db, $or_req);
|
465 |
ListeObservations::sqlAddConstraint($or_masque, $db, $or_req);
|
466 |
self::sqlAddConstraint($or_masque, $db, $or_req);
|
466 |
self::sqlAddConstraint($or_masque, $db, $or_req);
|
467 |
|
467 |
|
468 |
if($or_req['where']) {
|
468 |
if($or_req['where']) {
|
469 |
$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')';
|
469 |
$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')';
|
Line 470... |
Line 470... |
470 |
// utile au cas ou des jointures seraient rajoutées
|
470 |
// utile au cas ou des jointures seraient rajoutées
|
471 |
$req['join'] = array_unique(array_merge($req['join'], $or_req['join']));
|
471 |
$req['join'] = array_unique(array_merge($req['join'], $or_req['join']));
|
472 |
}
|
472 |
}
|
473 |
}
|
473 |
}
|
474 |
}
|
474 |
}
|
Line 475... |
Line 475... |
475 |
|
475 |
|
476 |
// complete & override ListeObservations2::requestFilterParams() (même usage)
|
476 |
// complete & override ListeObservations::requestFilterParams() (même usage)
|
477 |
static function requestFilterParams(Array $params, $parametres_autorises = NULL) {
|
477 |
static function requestFilterParams(Array $params, $parametres_autorises = NULL) {
|
Line 478... |
Line 478... |
478 |
if($parametres_autorises) { // filtrage de toute clef inconnue
|
478 |
if($parametres_autorises) { // filtrage de toute clef inconnue
|
479 |
$params = array_intersect_key($params, array_flip($parametres_autorises));
|
479 |
$params = array_intersect_key($params, array_flip($parametres_autorises));
|
Line 480... |
Line 480... |
480 |
}
|
480 |
}
|