25,7 → 25,9 |
|
// simplifie et accélère la sanitization de l'input: |
// SELECT MAX(num_nom) FROM coste_v2_00; |
define('_COSTE_TEXTE_MAX_NUM_NOM', 7015 + 1000); |
define('_COSTE_TEXTE_MAX_COSTE_NN', 7015 + 1000); |
// SELECT MAX(num_nom) FROM bdtfx_v1_02; |
define('_COSTE_TEXTE_MAX_BDTFX_NN', 103386 + 10000); |
|
/*restore_error_handler(); |
error_reporting(E_ALL);*/ |
45,6 → 47,9 |
// les champs de base de coste_v2_00 |
// mysql -N tb_eflore<<<"SHOW FIELDS FROM coste_v2_00"|egrep -v 'page_'|awk '{print $1}'|xargs -i -n1 printf "'%s' => 'c.%s',\n" {} {} |
static $allow_champs = array( |
'coste:nn' => 'c.num_nom', |
'bdtfx:nn' => 'IF(c.flore_bdtfx_nn = "",NULL,c.flore_bdtfx_nn)', |
'bdtfx:nt' => 'c.flore_bdtfx_nt', |
'num_nom' => 'c.num_nom', |
'num_nom_retenu' => 'c.num_nom_retenu', |
'num_tax_sup' => 'c.num_tax_sup', |
93,7 → 98,13 |
); |
|
// les champs suivants disparaissent de la liste utilisée pour former la requête SQL |
static $special_champs = array('nom_sci_html', 'nom_sci', '*'); |
// (ils sont exclue lorsque '*' est utilisée, ce sont généralement des synonymes) |
static $special_champs = array('nom_sci_html', 'nom_sci', '*', 'flore_bdtfx_nn', 'flore_bdtfx_nt', 'num_nom'); |
|
// ces champs sont toujours dans les résultats (cf sqlSelectFields() |
static $champs_obligatoires = array('coste:nn', 'bdtfx:nn'); |
|
|
// le pattern utilisé pour la recherche dite "floue" |
static $soundex_scheme = '(%1$s LIKE %2$s OR SOUNDEX(%1$s) = SOUNDEX(%2$s) OR SOUNDEX(REVERSE(%1$s)) = SOUNDEX(REVERSE(%2$s)))'; |
|
145,10 → 156,10 |
$matches = intval($matches['total']); |
} |
|
// reformate les résultats pour les indexer par num_nom |
// reformate les résultats pour les indexer par coste:nn |
$res2 = array(); |
foreach($res as $v) { |
$res2[$v['num_nom']] = $v; |
$res2[$v['coste:nn']] = $v; |
} |
|
// l'appelant s'occupera du json_encode() |
163,8 → 174,8 |
} |
|
|
// la fonction central: récupère les infos à partir de paramètres |
// et une optionnel contrainte de num_nom |
// la fonction centrale: récupère les infos à partir de paramètres |
// et une optionnelle contrainte sur coste:nn ou bdtfx:nn |
static function getCosteInfo(array $params, $db) { |
// contraintes (WHERE): |
$constraints = self::sqlAddConstraint($params, $db); |
176,9 → 187,8 |
|
// joins: |
$other_join = self::sqlAddJoins($params, $champs_valides_non_formattes); |
|
$req = sprintf(<<<EOF |
SELECT SQL_CALC_FOUND_ROWS c.num_nom, %s |
SELECT SQL_CALC_FOUND_ROWS %s |
FROM tb_eflore.coste_v2_00 c |
LEFT JOIN tela_prod_wikini.florecoste_pages dsc ON c.page_wiki_dsc = dsc.tag AND dsc.latest = 'Y' |
LEFT JOIN tela_prod_wikini.florecoste_pages cle ON c.page_wiki_cle = cle.tag AND cle.latest = 'Y' |
255,11 → 265,18 |
$stack[] = 'c.tome = ' . intval($params['masque.tome']); |
} |
|
// ajout de la contrainte sur num_nom si un composant d'URL supplémentaire |
// ajout de la contrainte sur coste:nn ou bdtfx:nn si un composant d'URL supplémentaire |
// comportant un #id existe, cf self::requestFilterIds() |
$o_stack = array(); |
if(array_key_exists('_ids', $params) && $params['_ids']) { |
$stack[] = sprintf("c.num_nom IN (%s)", implode(',', $params['_ids'])); |
if($params['_ids']['coste']) { |
$o_stack[] = sprintf("c.num_nom IN (%s)", implode(',', $params['_ids']['coste'])); |
} |
if($params['_ids']['bdtfx']) { |
$o_stack[] = sprintf("c.flore_bdtfx_nn IN (%s)", implode(',', $params['_ids']['bdtfx'])); |
} |
} |
if($o_stack) $stack[] = '(' . implode(' OR ', $o_stack) . ')'; |
|
return $stack; |
} |
271,7 → 288,7 |
static function sqlSelectFields($params, &$unmerged) { |
$champs = $params['retour.champs']; |
// champs coste_v2_00 |
$c = array_intersect_key(self::$allow_champs, array_flip(explode(',', $champs))); |
$c = self::addSQLToFieldSynonym(explode(',', $champs)); |
if(isset($c['*'])) { |
$t = array_diff_key(self::$allow_champs, array_flip(self::$special_champs)); |
} |
291,12 → 308,18 |
if(array_key_exists('titre', $t)) |
$t['titre'] = $params['txt.format'] == 'txt' ? 'c.nom_sci' : 'c.nom_sci_html'; |
|
// champs obligatoires: |
$t = array_merge($t, self::addSQLToFieldSynonym(self::$champs_obligatoires)); |
$unmerged = $t; |
|
// XXX: PHP-5.3 |
$ret = array(); |
foreach($t as $k => $v) { |
$ret[] = "$v AS $k"; |
if(strpos($k, ':') !== FALSE) { |
$ret[] = "$v AS \"$k\""; |
} else { |
$ret[] = "$v AS $k"; |
} |
} |
return implode(',',$ret); |
} |
307,12 → 330,20 |
// ou contraintes générées par sqlAddConstraint() |
if(array_key_exists('masque.famille', $params) || |
array_key_exists('famille', $champs)) { |
$j .= 'LEFT JOIN tb_eflore.bdtfx_v1_02 b ON c.num_nom = b.num_nom'; |
$j .= 'LEFT JOIN tb_eflore.bdtfx_v1_02 b ON c.flore_bdtfx_nn = b.num_nom'; |
} |
|
return $j; |
} |
|
// d'un tableau de type array("coste:nn", "type_epithete") |
// retourne |
// un tableau de type array("coste:nn" => "c.num_nom", "type_epithete" => "c.type_epithete") |
// basé sur self::$allow_champs |
static function addSQLToFieldSynonym(Array $syno) { |
return array_intersect_key(self::$allow_champs, array_flip($syno)); |
} |
|
// request handler |
static function requestParse(&$ressource, &$params) { |
$uri = explode('/', $_SERVER['REDIRECT_URL']); |
355,7 → 386,7 |
FILTER_VALIDATE_INT, |
array('options' => array('default' => NULL, |
'min_range' => 0, |
'max_range' => _COSTE_TEXTE_MAX_NUM_NOM))); |
'max_range' => _COSTE_TEXTE_MAX_COSTE_NN))); |
|
// on filtre les NULL, FALSE et '', mais pas les 0, d'où le callback() |
// TODO: PHP-5.3 |
368,17 → 399,23 |
static function requestFilterIds($uri) { |
if(count($uri) != 1) return NULL; |
|
// getNN renvoie le num_nom passé comme segment d'URI |
// getNN* renvoient le num_nom passé comme segment d'URI: |
// - soit un id selon coste (num_nom dans coste_v2_00) |
// - soit un id selon bdtfx (num_nom dans bdtfx_v1_02) |
// ou bien l'extrait du pattern bdtfx.nn:(#id) |
$ids = array_filter(array_map(array(__CLASS__, 'getNN'), explode(',', $uri[0]))); |
$ids_coste = array_filter(array_map(array(__CLASS__, 'getNNCoste'), explode(',', $uri[0]))); |
$ids_bdtfx = array_filter(array_map(array(__CLASS__, 'getNNBdtfx'), explode(',', $uri[0]))); |
|
// en cas d'échec (tous les id sont invalides), bail-out |
if(!$ids) { |
if(!$ids_bdtfx && !$ids_coste) { |
// http_response_code(500); |
throw new Exception('not supported', 500); |
} |
|
return array_slice($ids, 0, _COSTE_TEXTE_MAX_RESULT_LIMIT); |
return array( |
'coste' => array_slice($ids_coste, 0, intval(_COSTE_TEXTE_MAX_RESULT_LIMIT/2) ), |
'bdtfx' => array_slice($ids_bdtfx, 0, intval(_COSTE_TEXTE_MAX_RESULT_LIMIT/2) ) |
); |
} |
|
static function aide() { |
387,11 → 424,12 |
Service coste/textes: |
Retourne des informations (choisies) à propos d'un taxon donné (à partir de son numéro nomenclatural |
Retourne des informations (choisies) à propos de taxons recherchés (à partir de divers critères) |
|
Les résultats sont indexés. La clef par défaut est le num_nom d'après coste (attribut \"coste:nn\") |
Usage: |
coste/textes/<liste-num_nom>?<params> |
* <liste-num_nom> étant une liste de numéros nomenclaturaux de taxons bdtfx séparés par des virgules |
au format <#id> ou <bdtfx.nn:#id> |
* <liste-num_nom> étant une liste de numéros nomenclaturaux de taxons séparés par des virgules au format: |
- <#id>: un numéro nomenclatural dans la base coste |
- <bdtfx.nn:#id>: un numéro nomenclatural dans la base bdtfx |
* retour.champs une liste de champs séparés par des virgules parmi *,%s |
* les paramètres acceptés sont les suivants: %s |
* les champs retournés par défaut sont les suivants: %s |
404,13 → 442,18 |
); |
} |
|
static function getNN($refnn) { |
static function getNNCoste($refnn) { |
if(is_numeric($refnn)) { |
$t = intval($refnn); |
if($t >= 1 && $t < _COSTE_TEXTE_MAX_NUM_NOM) return $t; |
return FALSE; |
if($t >= 1 && $t < _COSTE_TEXTE_MAX_COSTE_NN) return $t; |
} |
return FALSE; |
} |
|
static function getNNBdtfx($refnn) { |
if(strpos($refnn, 'bdtfx.nn:') !== 0) return FALSE; |
return intval(str_replace('bdtfx.nn:', '', $refnn)); |
$t = intval(str_replace('bdtfx.nn:', '', $refnn)); |
if($t >= 1 && $t < _COSTE_TEXTE_MAX_BDTFX_NN) return $t; |
return FALSE; |
} |
} |