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

@@ -0,0 +1,115 @@
<?php
/**
* Background resolver + cache for alternate idHAL forms.
*
* Problem: a member's WP `identifiant_hal` stores ONE idHAL form, but HAL may
* tag their publications under other valid forms of the same person. Matching
* on the single stored form silently drops those links.
*
* Fix: resolve every member's full set of valid idHAL forms (via HAL ref/author)
* and cache them in usermeta `_hal_id_forms`. Matching then uses the cached
* forms — with ZERO network calls in the UI / import path.
*
* All resolution happens in the background via WP-Cron, in small batches, so the
* admin interface and the import flow stay as fast as before.
*/
if (!defined('ABSPATH')) {
exit;
}
class Thalim_HAL_Forms_Cache {
const META_FORMS = '_hal_id_forms'; // usermeta: JSON array of forms
const META_SOURCE = '_hal_id_forms_src'; // usermeta: the identifiant_hal the cache was built from
const CRON_HOOK = 'thalim_hal_refresh_forms';
const BATCH_SIZE = 15; // members resolved per cron tick
/** Wire the background hooks. Called once at plugins_loaded. */
public static function init() {
add_action(self::CRON_HOOK, [__CLASS__, 'run_batch']);
// Ensure the recurring event exists (hourly).
if (!wp_next_scheduled(self::CRON_HOOK)) {
wp_schedule_event(time() + 60, 'hourly', self::CRON_HOOK);
}
// When a profile's identifiant_hal changes, invalidate its cache so the
// next background tick re-resolves it (no synchronous API call here).
add_action('updated_user_meta', [__CLASS__, 'on_user_meta_change'], 10, 4);
add_action('added_user_meta', [__CLASS__, 'on_user_meta_change'], 10, 4);
}
/** Remove the scheduled event (plugin deactivation). */
public static function clear_schedule() {
$ts = wp_next_scheduled(self::CRON_HOOK);
if ($ts) wp_unschedule_event($ts, self::CRON_HOOK);
}
/** Invalidate a user's cache when their identifiant_hal is edited. */
public static function on_user_meta_change($meta_id, $user_id, $meta_key, $_meta_value) {
if ($meta_key === 'identifiant_hal') {
delete_user_meta($user_id, self::META_SOURCE); // marks the cache stale
}
}
/**
* Read cached alternate forms for a user's identifiant_hal.
* Always returns at least the stored form itself (graceful degradation:
* behaves exactly like the old code until the background job has run).
*
* @return string[] lowercased idHAL forms.
*/
public static function forms_for_user($user_id, $identifiant_hal) {
$base = strtolower(trim((string) $identifiant_hal));
if ($base === '') return [];
$src = get_user_meta($user_id, self::META_SOURCE, true);
if ($src === $base) {
$cached = json_decode((string) get_user_meta($user_id, self::META_FORMS, true), true);
if (is_array($cached) && $cached) {
$cached[] = $base;
return array_values(array_unique(array_map('strtolower', $cached)));
}
}
// Not resolved yet (or stale) -> fall back to the single stored form.
return [$base];
}
/**
* Cron worker: resolve forms for a batch of members whose cache is missing
* or stale. Runs in the background; safe to be interrupted (idempotent).
*/
public static function run_batch() {
$users = get_users([
'meta_key' => 'identifiant_hal',
'meta_compare' => 'EXISTS',
'fields' => ['ID'],
'number' => 500,
]);
// Select those needing (re)resolution: stored form != cached source.
$todo = [];
foreach ($users as $u) {
$idhal = strtolower(trim((string) get_user_meta($u->ID, 'identifiant_hal', true)));
if ($idhal === '') continue;
$src = get_user_meta($u->ID, self::META_SOURCE, true);
if ($src !== $idhal) {
$todo[$idhal][] = (int) $u->ID; // group users sharing a slug
}
if (count($todo) >= self::BATCH_SIZE) break;
}
if (empty($todo)) return;
$api = new Thalim_HAL_API();
$expanded = $api->expand_hal_id_forms(array_keys($todo));
foreach ($todo as $idhal => $user_ids) {
$forms = $expanded[$idhal] ?? [$idhal];
foreach ($user_ids as $uid) {
update_user_meta($uid, self::META_FORMS, wp_json_encode(array_values($forms)));
update_user_meta($uid, self::META_SOURCE, $idhal);
}
}
}
}