| 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 |
}
|