26,9 → 26,12 |
// SELECT MAX(num_nom) FROM bdtfx_v2_00; |
define('_LISTE_OBS_MAX_BDTFX_NN', 103386 + 10000); |
|
restore_error_handler(); |
restore_exception_handler(); |
error_reporting(E_ALL); |
require_once(dirname(__FILE__) . '/../images/ListeImages2.php'); |
/* |
restore_error_handler(); |
restore_exception_handler(); |
error_reporting(E_ALL); |
*/ |
|
class ListeObservations { |
|
41,27 → 44,27 |
static $tris_possibles = array('date_observation'); |
// paramètres autorisés |
static $parametres_autorises = array('masque', 'masque.famille', 'masque.nn', 'masque.referentiel', // taxon |
'masque.genre', 'masque.espece', 'masque.ns', // nom_sel |
'masque.commune', 'masque.departement', 'masque.id_zone_geo', // loc |
'masque.auteur', 'masque.date', 'masque.tag', 'masque.type', // autres |
// tri, offset |
'navigation.depart', 'navigation.limite', |
'tri', 'ordre', // TODO: 'total=[yes]', 'fields=[x,y,...]' |
// TODO: masque.annee, masque.insee (!= departement) |
'masque.genre', 'masque.espece', 'masque.ns', // nom_sel |
'masque.commune', 'masque.departement', 'masque.id_zone_geo', // loc |
'masque.auteur', 'masque.date', 'masque.tag', 'masque.type', // autres |
// tri, offset |
'navigation.depart', 'navigation.limite', |
'tri', 'ordre', // TODO: 'total=[yes]', 'fields=[x,y,...]' |
// TODO: masque.annee, masque.insee (!= departement) |
); |
|
static $default_params = array('navigation.depart' => 0, 'navigation.limite' => 10, |
'tri' => 'date_transmission', 'ordre' => 'desc'); |
'tri' => 'date_transmission', 'ordre' => 'desc'); |
|
static $sql_fields_liaisons = array( |
'dob' => array('id_observation', 'nom_sel AS `determination.ns`', 'nt AS `determination.nt`', |
'nom_sel_nn AS `determination.nn`', 'famille AS `determination.famille`', |
'nom_referentiel AS `determination.referentiel`', |
'ce_zone_geo AS id_zone_geo', 'zone_geo', 'lieudit', |
'station', 'milieu', 'date_observation', 'mots_cles_texte', 'date_transmission', |
'ce_utilisateur AS `auteur.id`', 'prenom_utilisateur AS `auteur.prenom`', |
'nom_utilisateur AS `auteur.nom`', 'courriel_utilisateur AS observateur', |
'commentaire'), |
'nom_sel_nn AS `determination.nn`', 'famille AS `determination.famille`', |
'nom_referentiel AS `determination.referentiel`', |
'ce_zone_geo AS id_zone_geo', 'zone_geo', 'lieudit', |
'station', 'milieu', 'date_observation', 'mots_cles_texte', 'date_transmission', |
'ce_utilisateur AS `auteur.id`', 'prenom_utilisateur AS `auteur.prenom`', |
'nom_utilisateur AS `auteur.nom`', 'courriel_utilisateur AS observateur', |
'commentaire'), |
'di' => array('id_image', 'date_prise_de_vue AS `date`', 'hauteur',/* 'largeur','nom_original' // apparemment inutilisés */), |
'du' => array('prenom', 'nom', 'courriel'), |
'dc' => array('commentaire') |
165,6 → 168,9 |
|
// filtrage de l'INPUT |
$params = self::requestFilterParams($parametres, self::$parametres_autorises, $this->conteneur); |
|
$params['masque.tag'] = ListeImages2::buildTagsAST(@$parametres['masque.tag'], 'OR', ','); |
|
// ... et paramètres par défaut |
$params = array_merge(self::$default_params, $params); |
|
203,7 → 209,7 |
// 6) JSON output |
$resultat = new ResultatService(); |
$resultat->corps = array('entete' => self::makeJSONHeader($total, $params, Config::get('url_service')), |
'resultats' => $observations); |
'resultats' => $observations); |
|
return $resultat; |
} |
230,26 → 236,26 |
*/ |
static function getIdObs($p, $req, $db) { |
$req_s = sprintf('SELECT SQL_CALC_FOUND_ROWS id_observation' . |
' FROM v_del_image vdi'. |
' %s' . // LEFT JOIN if any |
' WHERE %s'. // where-clause ou TRUE |
' %s'. // group-by |
' %s'. // having (si commentaires) |
' ORDER BY %s %s %s'. |
' LIMIT %d, %d -- %s', |
' FROM v_del_image vdi'. |
' %s' . // LEFT JOIN if any |
' WHERE %s'. // where-clause ou TRUE |
' %s'. // group-by |
' %s'. // having (si commentaires) |
' ORDER BY %s %s %s'. |
' LIMIT %d, %d -- %s', |
|
$req['join'] ? implode(' ', $req['join']) : '', |
$req['where'] ? implode(' AND ', $req['where']) : 'TRUE', |
$req['join'] ? implode(' ', $req['join']) : '', |
$req['where'] ? implode(' AND ', $req['where']) : 'TRUE', |
|
$req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '', |
$req['having'] ? ('HAVING ' . implode(' AND ', $req['having'])) : '', |
$req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '', |
$req['having'] ? ('HAVING ' . implode(' AND ', $req['having'])) : '', |
|
$p['tri'], strtoupper($p['ordre']), |
// date_transmission peut-être NULL et nous voulons de la consistence |
// (sauf après r1860 de Cel) |
$p['tri'] == 'date_transmission' ? ', id_observation' : '', |
$p['tri'], strtoupper($p['ordre']), |
// date_transmission peut-être NULL et nous voulons de la consistence |
// (sauf après r1860 de Cel) |
$p['tri'] == 'date_transmission' ? ', id_observation' : '', |
|
$p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__); |
$p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__); |
|
$res = $db->recupererTous($req_s); |
$err = mysql_error(); |
273,16 → 279,16 |
*/ |
static function getInfos($idobs, $db) { |
/*$select_fields = implode(',', array_merge( |
array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['dob']), |
array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['di']), |
array_map(create_function('$a', 'return "du.".$a;'), self::$sql_fields_liaisons['du'])));*/ |
array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['dob']), |
array_map(create_function('$a', 'return "vdi.".$a;'), self::$sql_fields_liaisons['di']), |
array_map(create_function('$a', 'return "du.".$a;'), self::$sql_fields_liaisons['du'])));*/ |
$select_fields = array_merge(self::$sql_fields_liaisons['dob'], |
self::$sql_fields_liaisons['di']); |
self::$sql_fields_liaisons['di']); |
$req_s = sprintf('SELECT %s FROM v_del_image vdi'. |
// ' LEFT JOIN del_commentaire AS dc ON di.id_observation = dc.ce_observation AND dc.nom_sel IS NOT NULL'. |
' WHERE id_observation IN (%s)', |
implode(',', $select_fields), |
implode(',', $idobs)); |
// ' LEFT JOIN del_commentaire AS dc ON di.id_observation = dc.ce_observation AND dc.nom_sel IS NOT NULL'. |
' WHERE id_observation IN (%s)', |
implode(',', $select_fields), |
implode(',', $idobs)); |
return $db->recupererTous($req_s); |
} |
|
321,7 → 327,7 |
} |
elseif(preg_match(';^.{5,}@[a-z0-9-.]{5,}$;i', $p['masque.auteur'])) { |
$req['where'][] = sprintf('(du.courriel LIKE %1$s OR vdi.courriel LIKE %1$s )', |
$db->proteger($p['masque.auteur'] . '%')); |
$db->proteger($p['masque.auteur'] . '%')); |
} |
else { |
self::addAuteursConstraint($p['masque.auteur'], $db, $req['where']); |
334,7 → 340,7 |
} |
else { |
$req['where'][] = sprintf("DATE_FORMAT(vdi.date_observation, '%%Y-%%m-%%d') = %s", |
$db->proteger(strftime('%Y-%m-%d', $p['masque.date']))); |
$db->proteger(strftime('%Y-%m-%d', $p['masque.date']))); |
} |
} |
|
364,11 → 370,30 |
$req['where'][] = 'vdi.zone_geo LIKE '.$db->proteger($p['masque.commune'].'%'); |
} |
if(!empty($p['masque.tag'])) { |
// TODO: remove LOWER() lorsqu'on est sur que les tags sont uniformés en minuscule |
// i_mots_cles_texte provient de la VIEW v_del_image |
// TODO: remove LOWER() lorsqu'on est sur que les tags sont uniformés en minuscule |
$req['where'][] = sprintf('LOWER(CONCAT(%s)) REGEXP %s', |
self::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')), |
$db->proteger(strtolower($p['masque.tag']))); |
if(isset($p['masque.tag']['AND'])) { |
/* Lorsque nous interprêtons la chaîne provenant du masque général (cf: buildTagsAST($p['masque'], 'OR', ' ') dans sqlAddMasqueConstraint()), |
nous sommes splittés par espace. Cependant, assurons que si une virgule à été saisie, nous n'aurons pas le motif |
" AND CONCAT(mots_cles_texte, i_mots_cles_texte) REGEXP ',' " dans notre requête. |
XXX: Au 12/11/2013, une recherche sur tag depuis le masque général implique un OU, donc le problème ne se pose pas ici */ |
$subwhere = array(); |
foreach($p['masque.tag']['AND'] as $tag) { |
if(trim($tag) == ',') continue; |
|
$subwhere[] = sprintf( |
'LOWER(CONCAT(%s)) REGEXP %s', |
self::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')), |
$db->proteger(strtolower($tag))); |
} |
$req['where'][] = '(' . implode(' AND ', $subwhere) . ')'; |
} |
else { |
$req['where'][] = sprintf( |
'LOWER(CONCAT(%s)) REGEXP %s', |
self::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')), |
$db->proteger(strtolower(implode('|', $p['masque.tag']['OR'])))); |
} |
} |
|
if(!empty($p['masque.type'])) { |
383,15 → 408,16 |
static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) { |
if(!empty($p['masque'])) { |
$or_params = array('masque.auteur' => $p['masque'], |
'masque.departement' => $p['masque'], |
'masque.id_zone_geo' => $p['masque'], |
'masque.tag' => $p['masque'], |
'masque.ns' => $p['masque'], |
'masque.famille' => $p['masque'], |
'masque.date' => $p['masque'], |
'masque.genre' => $p['masque'], |
/* milieu: TODO ? */ ); |
'masque.departement' => $p['masque'], |
'masque.id_zone_geo' => $p['masque'], |
'masque.tag' => $p['masque'], |
'masque.ns' => $p['masque'], |
'masque.famille' => $p['masque'], |
'masque.date' => $p['masque'], |
'masque.genre' => $p['masque'], |
/* milieu: TODO ? */ ); |
$or_masque = self::requestFilterParams($or_params, array_keys($or_params), $c); |
$or_masque['masque.tag'] = ListeImages2::buildTagsAST($p['masque'], 'OR', ' '); |
// $or_req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array()); |
$or_req = array('join' => array(), 'where' => array()); |
self::sqlAddConstraint($or_masque, $db, $or_req); |
430,11 → 456,11 |
@list($a, $b) = explode(' ', $val, 2); |
// un seul terme |
$champs_n = array('du.prenom', // info user authentifié de l'obs depuis l'annuaire |
'vdi.prenom_utilisateur', // info user anonyme de l'obs |
/* 'vdi.i_prenom_utilisateur' */ ); // info user anonyme de l'image |
'vdi.prenom_utilisateur', // info user anonyme de l'obs |
/* 'vdi.i_prenom_utilisateur' */ ); // info user anonyme de l'image |
$champs_p = array('du.nom', // idem pour le nom |
'vdi.nom_utilisateur', |
/* 'vdi.i_nom_utilisateur' */ ); |
'vdi.nom_utilisateur', |
/* 'vdi.i_nom_utilisateur' */ ); |
|
/* |
Note: pour l'heure, étant donnés: |
444,18 → 470,18 |
et l'âge du capitaine... |
- REGEXP est case-sensitive, et collate les caractères accentués |
- LIKE est case-insensitive, et collate les caractères accentués |
*/ |
*/ |
if(! $b) { |
$where[] = sprintf('CONCAT(%s,%s) LIKE %s', |
self::sqlAddIfNullPourConcat($champs_n), |
self::sqlAddIfNullPourConcat($champs_p), |
$db->proteger("%".$val."%")); |
self::sqlAddIfNullPourConcat($champs_n), |
self::sqlAddIfNullPourConcat($champs_p), |
$db->proteger("%".$val."%")); |
} |
else { |
$where[] = sprintf('(CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s)', |
self::sqlAddIfNullPourConcat($champs_n), |
self::sqlAddIfNullPourConcat($champs_p), |
$db->proteger("%" . $a . "%"), $db->proteger("%" . $b . "%")); |
self::sqlAddIfNullPourConcat($champs_n), |
self::sqlAddIfNullPourConcat($champs_p), |
$db->proteger("%" . $a . "%"), $db->proteger("%" . $b . "%")); |
} |
} |
|
502,15 → 528,15 |
|
|
/** |
* Récupérer toutes les déterminations et le nombre de commentaire au total |
* @param array $observations la liste des observations à mettre à jour |
* */ |
* Récupérer toutes les déterminations et le nombre de commentaire au total |
* @param array $observations la liste des observations à mettre à jour |
* */ |
private function chargerDeterminations(&$observations) { |
$idObs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'), |
$observations)); |
$observations)); |
$r = sprintf('SELECT * FROM del_commentaire AS dc WHERE dc.nom_sel IS NOT NULL AND ce_observation IN (%s) -- %s', |
implode(',',$idObs), |
__FILE__ . ':' . __LINE__); |
implode(',',$idObs), |
__FILE__ . ':' . __LINE__); |
$propositions = $this->bdd->recupererTous($r); |
if(!$propositions) return; |
foreach ($propositions as $proposition) { |
555,7 → 581,7 |
if($ligneProposition['ce_commentaire_parent'] != $commentId) { |
// restore_error_handler(); |
error_log(sprintf("possible error: nb_commentaires = %s: comment = %d, parent = %d, %s", |
$ligneProposition['nb'], $commentId, $ligneProposition['ce_commentaire_parent'], __FILE__)); |
$ligneProposition['nb'], $commentId, $ligneProposition['ce_commentaire_parent'], __FILE__)); |
} |
$proposition_formatee['nb_commentaires'] = $ligneProposition['nb']; |
} else { |
567,9 → 593,9 |
} |
|
/** |
* Formater un vote en fonction du fichier de configuration config_votes.ini |
* @param $votes array() |
* */ |
* Formater un vote en fonction du fichier de configuration config_votes.ini |
* @param $votes array() |
* */ |
private function formaterVote($vote) { |
$retour = array(); |
foreach ($vote as $param=>$valeur) { |
611,15 → 637,15 |
// TODO: use filter_input(INPUT_GET); |
// renvoie FALSE ou NULL si absent ou invalide |
$p['navigation.limite'] = filter_var(@$params['navigation.limite'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 1, |
'max_range' => _LISTE_OBS_MAX_RESULT_LIMIT))); |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 1, |
'max_range' => _LISTE_OBS_MAX_RESULT_LIMIT))); |
$p['navigation.depart'] = filter_var(@$params['navigation.depart'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_ID_OBS))); |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_ID_OBS))); |
if(isset($params['masque.departement'])) { |
// STRING: 0 -> 95, 971 -> 976, 2A + 2B (./services/configurations/config_departements_bruts.ini) |
// accept leading 0 ? |
641,26 → 667,26 |
$p['masque.date'] = $params['masque.date']; |
} |
elseif(strpos($params['masque.date'], '/' !== false) && |
($x = strtotime(str_replace('/','-',$params['masque.date'])))) { |
($x = strtotime(str_replace('/','-',$params['masque.date'])))) { |
$p['masque.date'] = $x; |
} |
elseif(strpos($params['masque.date'], '-' !== false) && |
($x = strtotime($params['masque.date'])) ) { |
($x = strtotime($params['masque.date'])) ) { |
$p['masque.date'] = $x; |
} |
} |
|
$p['masque.nn'] = filter_var(@$params['masque.nn'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_BDTFX_NN))); |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_BDTFX_NN))); |
|
$p['masque.nt'] = filter_var(@$params['masque.nt'], |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_BDTFX_NT))); |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _LISTE_OBS_MAX_BDTFX_NT))); |
|
|
// TODO: should we really trim() ? |
671,8 → 697,8 |
if(isset($params['masque.famille'])) { |
// mysql -N<<<"SELECT DISTINCT famille FROM bdtfx_v1_02;"|sed -r "s/(.)/\1\n/g"|sort -u|tr -d "\n" |
$p['masque.famille'] = preg_replace('/[^a-zA-Z %_]/', '', iconv("UTF-8", |
"ASCII//TRANSLIT", |
$params['masque.famille'])); |
"ASCII//TRANSLIT", |
$params['masque.famille'])); |
} |
|
// masque.genre est un alias pour masque.ns (nom_sel), mais permet de rajouter une clause supplémentaire |
709,7 → 735,7 |
// masque.type: ['adeterminer', 'aconfirmer', 'endiscussion', 'validees'] |
if(isset($params['masque.type'])) { |
$p['masque.type'] = array_flip(array_intersect(array_filter(explode(';', $params['masque.type'])), |
array('adeterminer', 'aconfirmer', 'endiscussion', 'validees'))); |
array('adeterminer', 'aconfirmer', 'endiscussion', 'validees'))); |
} |
|
|