Import HAL : match des auteurs sur toutes les formes d'idHAL (résolution en fond via cron)

This commit is contained in:
2026-07-07 13:44:08 +02:00
parent c38f8b4d7e
commit f083b36369
5 changed files with 262 additions and 5 deletions

View File

@@ -120,6 +120,95 @@ class Thalim_HAL_API {
return $result;
}
/**
* Expand a set of idHAL slugs to ALL valid idHAL forms of the same people.
*
* HAL frequently registers a person under several PREFERRED idHAL forms
* (e.g. "xavier-garnier" AND "xaviergarnier"). A publication may be tagged
* with any one of them, so matching a WP profile against a single stored
* form silently misses those tagged under an alternate form.
*
* ref/author exposes every form under the same person, sharing the same
* numeric root of `docid` ("6951-1022", "6951-180497" => person 6951).
* We resolve each input slug to its person root(s), then collect every
* idHAL form attached to those roots.
*
* NOTE: this hits the network. It is meant to be called from the background
* cron resolver (see Thalim_HAL_Forms_Cache), never from the UI/import path.
*
* @param string[] $idhals Slugs to expand (a member's stored identifiant_hal).
* @return array Map [input_slug_lowercased => [form1, form2, ...]].
* On API error a slug maps to just itself.
*/
public function expand_hal_id_forms(array $idhals) {
$out = [];
$clean = [];
foreach ($idhals as $id) {
$id = strtolower(trim((string) $id));
if ($id !== '') { $clean[$id] = true; $out[$id] = [$id]; }
}
if (empty($clean)) return $out;
$endpoint = 'https://api.archives-ouvertes.fr/ref/author/';
// Step 1: for each slug, find the person root(s) of its docid.
$slug_roots = []; // slug => [root => true]
$all_roots = []; // root => true
foreach (array_chunk(array_keys($clean), 50) as $chunk) {
$quoted = array_map(fn($id) => '"' . str_replace('"', '', $id) . '"', $chunk);
$params = [
'q=' . urlencode('idHal_s:(' . implode(' OR ', $quoted) . ')'),
'fl=' . urlencode('docid,idHal_s'),
'rows=' . (count($chunk) * 5),
'wt=json',
];
$data = $this->request($endpoint . '?' . implode('&', $params));
if (is_wp_error($data)) continue;
foreach ($data['response']['docs'] ?? [] as $doc) {
$slug = strtolower($doc['idHal_s'] ?? '');
$root = isset($doc['docid']) ? explode('-', $doc['docid'])[0] : '';
if ($slug !== '' && $root !== '') {
$slug_roots[$slug][$root] = true;
$all_roots[$root] = true;
}
}
usleep(250000);
}
if (empty($all_roots)) return $out;
// Step 2: collect every idHAL form attached to those person roots.
// NB: do NOT quote the "root-*" terms — quoting disables the Solr wildcard.
// Roots are numeric, so they are safe to inline; keep only digits defensively.
$root_forms = []; // root => [form => true]
foreach (array_chunk(array_keys($all_roots), 50) as $chunk) {
$terms = array_map(fn($r) => preg_replace('/\D/', '', $r) . '-*', $chunk);
$params = [
'q=' . urlencode('docid:(' . implode(' OR ', $terms) . ')'),
'fl=' . urlencode('docid,idHal_s'),
'rows=' . (count($chunk) * 10),
'wt=json',
];
$data = $this->request($endpoint . '?' . implode('&', $params));
if (is_wp_error($data)) continue;
foreach ($data['response']['docs'] ?? [] as $doc) {
$root = isset($doc['docid']) ? explode('-', $doc['docid'])[0] : '';
$form = strtolower($doc['idHal_s'] ?? '');
if ($root !== '' && $form !== '') $root_forms[$root][$form] = true;
}
usleep(250000);
}
// Step 3: map each input slug to the union of forms across its roots.
foreach ($clean as $slug => $_) {
$forms = [$slug => true];
foreach (array_keys($slug_roots[$slug] ?? []) as $root) {
foreach (array_keys($root_forms[$root] ?? []) as $f) $forms[$f] = true;
}
$out[$slug] = array_keys($forms);
}
return $out;
}
/**
* Test API connection
*/