Globinours/app/Services/Asm3ContactImporter.php

103 lines
4.4 KiB
PHP

<?php
declare(strict_types=1);
final class Asm3ContactImporter
{
public static function run(string $path, PDO $db, bool $apply = false, bool $createBackup = true): array
{
$plan = Asm3ContactPlanner::plan($path, $db);
$hash = hash_file('sha256', $path);
if ($hash === false) {
throw new RuntimeException(t('asm3.hash_unavailable'));
}
$result = [
'mode' => $apply ? 'apply' : 'dry-run',
'entity' => 'contacts',
'planned' => $plan['summary'],
'created' => 0,
'linked_matches' => 0,
'skipped_match' => 0,
'skipped_review' => $plan['summary']['review'],
'backup' => null,
'read_only' => !$apply,
'would_create' => $plan['summary']['create'],
];
if (!$apply) {
return $result;
}
if ($createBackup) {
$backup = BackupService::create('pre-asm3-import');
$result['backup'] = $backup['name'] ?? null;
}
$ownsTransaction = !$db->inTransaction();
if ($ownsTransaction) {
$db->beginTransaction();
}
try {
$db->prepare(
"INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(:name,:hash,'completed','{}',:backup)",
)->execute([':name' => basename($path) . ' · contacts', ':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='contact' AND source_id=:source",
);
$check->execute([':hash' => $hash, ':source' => $item['asm3_id']]);
if ($check->fetchColumn()) {
continue;
}
$c = $item['mapped'];
if ($item['action'] === 'match') {
$target = (int) ($item['globinours_candidates'][0]['id'] ?? 0);
if ($target <= 0) {
$result['skipped_match']++;
continue;
}
$result['linked_matches']++;
} else {
$db->prepare(
'INSERT INTO directory_contacts(kind,name,phone,email,address,postal_code,city,country,notes) VALUES(:kind,:name,:phone,:email,:address,:postal,:city,:country,:notes)',
)->execute([
':kind' => $c['kind'],
':name' => $c['name'],
':phone' => $c['phone'],
':email' => $c['email'],
':address' => $c['address'],
':postal' => $c['postal_code'],
':city' => $c['city'],
':country' => $c['country'],
':notes' => $c['notes'],
]);
$target = (int) $db->lastInsertId();
$result['created']++;
}
$role = $db->prepare(
'INSERT OR IGNORE INTO directory_contact_roles(contact_id,role) VALUES(:contact,:role)',
);
foreach ($c['roles'] as $value) {
$role->execute([':contact' => $target, ':role' => $value]);
}
$db->prepare(
"INSERT INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(:hash,'contact',: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;
}
}