Publier Globinours 1.0.0-rc.3

This commit is contained in:
Alexandre NOEL 2026-09-03 12:39:15 +02:00
commit 9a2b4068da
325 changed files with 38230 additions and 20 deletions

View file

@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
final class Asm3AnimalImporter
{
public static function run(string $path, PDO $db, bool $apply = false, bool $createBackup = true): array
{
$plan = Asm3MigrationPlanner::plan($path, $db);
$hash = hash_file('sha256', $path);
if ($hash === false) {
throw new RuntimeException(t('asm3.hash_failed'));
}
$result = [
'mode' => $apply ? 'apply' : 'dry-run',
'source' => basename($path),
'source_sha256' => $hash,
'planned' => $plan['summary'],
'created' => 0,
'linked_matches' => 0,
'skipped_existing_import' => 0,
'skipped_match' => 0,
'skipped_review' => $plan['summary']['review'],
'backup' => null,
'read_only' => !$apply,
];
if (!$apply) {
$result['would_create'] = $plan['summary']['create'];
return $result;
}
if ($createBackup) {
$backup = BackupService::create('pre-asm3-import');
$result['backup'] = $backup['name'] ?? null;
}
$ownsTransaction = !$db->inTransaction();
if ($ownsTransaction) {
$db->beginTransaction();
}
try {
$run = $db->prepare(
"INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(:name,:hash,'completed','{}',:backup)",
);
$run->execute([':name' => basename($path), ':hash' => $hash, ':backup' => $result['backup']]);
$runId = (int) $db->lastInsertId();
foreach ($plan['items'] as $item) {
if ($item['action'] === 'review') {
continue;
}
$check = $db->prepare(
"SELECT target_id FROM asm3_import_links WHERE source_sha256=:hash AND entity_type='animal' AND source_id=:source",
);
$check->execute([':hash' => $hash, ':source' => $item['asm3_id']]);
if ($check->fetchColumn()) {
$result['skipped_existing_import']++;
continue;
}
if ($item['action'] === 'match') {
$target = (int) ($item['globinours_candidates'][0]['id'] ?? 0);
if ($target <= 0) {
$result['skipped_match']++;
continue;
}
$result['linked_matches']++;
} else {
$target = self::insert($db, $item['mapped'], $item['asm3_id']);
$result['created']++;
}
$db->prepare(
"INSERT INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(:hash,'animal',:source,:target,:run)",
)->execute([':hash' => $hash, ':source' => $item['asm3_id'], ':target' => $target, ':run' => $runId]);
}
$db->prepare('UPDATE asm3_import_runs SET summary_json=:summary WHERE id=:id')->execute([
':summary' => json_encode($result, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR),
':id' => $runId,
]);
if ($ownsTransaction) {
$db->commit();
}
} catch (Throwable $e) {
if ($ownsTransaction && $db->inTransaction()) {
$db->rollBack();
}
throw $e;
}
return $result;
}
private static function insert(PDO $db, array $a, int $sourceId): int
{
$code = trim((string) $a['internal_code']);
if ($code === '') {
$code = 'ASM3-' . $sourceId;
}
$exists = $db->prepare('SELECT 1 FROM animals WHERE internal_code=:code');
$exists->execute([':code' => $code]);
if ($exists->fetchColumn()) {
$code .= '-ASM3-' . $sourceId;
}
$stmt = $db->prepare(
"INSERT INTO animals(internal_code,name,species,sex,birth_date,birth_is_estimated,chip_id,status,sterilized,sterilization_status,sterilization_date,color,breed,notes,intake_date,archived_at,identification_type,identification_date,identification_registration_status,adoption_availability,adoption_available_from,adoption_unavailability_reason,compatibility_dogs,compatibility_cats,compatibility_children,house_trained,created_at,updated_at) VALUES(:code,:name,:species,:sex,:birth,:estimated,:chip,:status,:sterilized,:sterilization_status,:sterilization_date,:color,:breed,:notes,:intake,:archived,:identification_type,:identification_date,:registration,:availability,:available_from,:unavailable_reason,:dogs,:cats,:children,:trained,datetime('now'),datetime('now'))",
);
$stmt->execute([
':code' => $code,
':name' => $a['name'] ?: 'Animal ASM3 ' . $sourceId,
':species' => $a['species'] ?: 'inconnu',
':sex' => $a['sex'],
':birth' => $a['birth_date'],
':estimated' => $a['birth_is_estimated'],
':chip' => $a['chip_id'] ?: null,
':status' => $a['status'],
':sterilized' => $a['sterilization_status'] === 'yes' ? 1 : 0,
':sterilization_status' => $a['sterilization_status'],
':sterilization_date' => $a['sterilization_date'],
':color' => $a['color'],
':breed' => $a['breed'] ?: null,
':notes' => $a['notes'] ?: null,
':intake' => $a['intake_date'],
':archived' => $a['archived'] ? date('Y-m-d H:i:s') : null,
':identification_type' => $a['identification_type'],
':identification_date' => $a['identification_date'],
':registration' => $a['identification_registration_status'],
':availability' => $a['adoption_availability'],
':available_from' => $a['adoption_available_from'],
':unavailable_reason' => $a['adoption_unavailability_reason'] ?: null,
':dogs' => $a['compatibility_dogs'],
':cats' => $a['compatibility_cats'],
':children' => $a['compatibility_children'],
':trained' => $a['house_trained'],
]);
$id = (int) $db->lastInsertId();
if ($a['deceased_date']) {
$db->prepare(
"INSERT INTO animal_deaths(animal_id,deceased_date,cause_code,cause_details,place_type,body_disposition,notes) VALUES(:animal,:date,'unknown',NULL,'inconnu','pending',:notes)",
)->execute([':animal' => $id, ':date' => $a['deceased_date'], ':notes' => 'Importé depuis ASM3']);
}
return $id;
}
}