138 lines
6.6 KiB
PHP
138 lines
6.6 KiB
PHP
<?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;
|
|
}
|
|
}
|