Globinours/app/Services/Asm3LitterImporter.php

102 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
final class Asm3LitterImporter
{
public static function run(string $path, PDO $db, bool $apply = false, bool $createBackup = true): array
{
$hash = hash_file('sha256', $path);
$src = Asm3Analyzer::rows($path, ['animallitter', 'animal']);
$links = [];
$q = $db->prepare(
"SELECT source_id,target_id FROM asm3_import_links WHERE source_sha256=:h AND entity_type='animal'",
);
$q->execute([':h' => $hash]);
foreach ($q as $r) {
$links[(int) $r['source_id']] = (int) $r['target_id'];
}
$animals = [];
foreach ($src['animal'] ?? [] as $a) {
$animals[(string) $a['ACCEPTANCENUMBER']][] = (int) $a['ID'];
}
$result = [
'mode' => $apply ? 'apply' : 'dry-run',
'read_only' => !$apply,
'litters' => count($src['animallitter'] ?? []),
'would_import' => 0,
'unresolved' => 0,
'created' => 0,
'kittens_linked' => 0,
'backup' => null,
];
foreach ($src['animallitter'] ?? [] as $l) {
$parent = (int) $l['PARENTANIMALID'];
$kids = array_filter($animals[(string) $l['ACCEPTANCENUMBER']] ?? [], fn($id) => $id !== $parent);
if (!isset($links[$parent]) || array_filter($kids, fn($id) => !isset($links[$id]))) {
$result['unresolved']++;
continue;
}
$result['would_import']++;
}
if (!$apply) {
return $result;
}
if ($createBackup) {
$b = BackupService::create('pre-asm3-import');
$result['backup'] = $b['name'] ?? null;
}
$owns = !$db->inTransaction();
if ($owns) {
$db->beginTransaction();
}
try {
$db->prepare(
"INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(:n,:h,'completed','{}',:b)",
)->execute([':n' => basename($path) . ' · portées', ':h' => $hash, ':b' => $result['backup']]);
$run = (int) $db->lastInsertId();
foreach ($src['animallitter'] ?? [] as $l) {
$source = (int) $l['ID'];
$seen = $db->prepare(
"SELECT 1 FROM asm3_import_links WHERE source_sha256=:h AND entity_type='litter' AND source_id=:s",
);
$seen->execute([':h' => $hash, ':s' => $source]);
if ($seen->fetchColumn()) {
continue;
}
$parent = (int) $l['PARENTANIMALID'];
$kids = array_values(
array_filter($animals[(string) $l['ACCEPTANCENUMBER']] ?? [], fn($id) => $id !== $parent),
);
if (!isset($links[$parent]) || array_filter($kids, fn($id) => !isset($links[$id]))) {
continue;
}
$db->prepare('INSERT INTO litters(mother_id,birth_date,notes) VALUES(:parent,:date,:notes)')->execute([
':parent' => $links[$parent],
':date' => substr((string) $l['DATE'], 0, 10),
':notes' => trim((string) $l['COMMENTS']) ?: null,
]);
$target = (int) $db->lastInsertId();
$ins = $db->prepare(
'INSERT OR IGNORE INTO litter_kittens(litter_id,animal_id,position) VALUES(:litter,:animal,:position)',
);
foreach ($kids as $i => $kid) {
$ins->execute([':litter' => $target, ':animal' => $links[$kid], ':position' => $i + 1]);
$result['kittens_linked']++;
}
$db->prepare(
"INSERT INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(:h,'litter',:s,:t,:r)",
)->execute([':h' => $hash, ':s' => $source, ':t' => $target, ':r' => $run]);
$result['created']++;
}
if ($owns) {
$db->commit();
}
} catch (Throwable $e) {
if ($owns && $db->inTransaction()) {
$db->rollBack();
}
throw $e;
}
return $result;
}
}