Files
Investidor-V2/database/seeders/TerritoryReferenceSeeder.php
T
nala e65cb26901
tests / ci (push) Canceled after 0s
varias alteracoes
2026-10-06 14:50:12 +02:00

169 lines
6.8 KiB
PHP

<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use RuntimeException;
class TerritoryReferenceSeeder extends Seeder
{
private const SOURCE_CHECKSUM = '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff';
private const RECORDS_CHECKSUM = '630b574a3bfc5fa80dfb8d68314d7a2c413c86c3b1aa9e71603b393523b81c3c';
private const EXPECTED_COUNTS = [
'country' => 1,
'province' => 11,
'district' => 148,
'admin_post' => 437,
'locality' => 1324,
];
public function run(): void
{
$data = json_decode(File::get(database_path('data/territory-locations.json')), true, 512, JSON_THROW_ON_ERROR);
if (! is_array($data) || ! is_array($data['records'] ?? null)) {
throw new RuntimeException('Territory reference dataset is malformed.');
}
$records = $data['records'];
$actualCounts = array_count_values(array_column($records, 'location_type'));
ksort($actualCounts);
$expectedCounts = self::EXPECTED_COUNTS;
ksort($expectedCounts);
if (($data['source_system'] ?? null) !== 'cartografia-workbook'
|| ($data['source_sha256'] ?? null) !== self::SOURCE_CHECKSUM
|| ($data['source_version'] ?? null) !== 3
|| ! is_string($data['records_sha256'] ?? null)
|| ! hash_equals(self::RECORDS_CHECKSUM, $data['records_sha256'])
|| ! hash_equals(self::RECORDS_CHECKSUM, hash('sha256', json_encode($records, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR)))
|| $actualCounts !== $expectedCounts) {
throw new RuntimeException('Territory reference dataset failed its source or completeness checks.');
}
$counts = DB::transaction(function () use ($records): array {
DB::select('SELECT pg_advisory_xact_lock(280926, 150000)');
$seen = [];
$types = [];
$counts = ['created' => 0, 'unchanged' => 0, 'made_public' => 0];
foreach ($records as $record) {
$this->validateRecord($record, $seen, $types);
$externalId = self::SOURCE_CHECKSUM.':'.$record['id'];
$existing = DB::table('geo_locations')->where('id', $record['id'])->first();
$externalMatch = DB::table('geo_locations')
->where('source_system', 'cartografia-workbook')
->where('external_id', $externalId)
->first();
if ($externalMatch && (! $existing || $externalMatch->id !== $existing->id)) {
throw new RuntimeException('Territory external identifier collision: '.$record['id']);
}
if ($existing) {
if ($existing->source_system !== 'cartografia-workbook' || $existing->external_id !== $externalId) {
throw new RuntimeException('Territory ID belongs to another source: '.$record['id']);
}
foreach (['name', 'parent_id', 'location_type', 'code', 'source_code'] as $field) {
if ($record[$field] !== $existing->{$field}) {
throw new RuntimeException('Territory reference differs from packaged source: '.$record['id']);
}
}
if ($existing->deleted_at !== null) {
throw new RuntimeException('Packaged territory reference is archived: '.$record['id']);
}
if ($existing->data_classification === 'internal') {
DB::table('geo_locations')->where('id', $record['id'])->update([
'data_classification' => 'public',
'updated_at' => now(),
]);
$counts['made_public']++;
} elseif ($existing->data_classification === 'public') {
$counts['unchanged']++;
} else {
throw new RuntimeException('Territory reference has an unexpected classification: '.$record['id']);
}
continue;
}
DB::table('geo_locations')->insert([
...$record,
'source_system' => 'cartografia-workbook',
'external_id' => $externalId,
'version_no' => 1,
'data_classification' => 'public',
'created_at' => now(),
'updated_at' => now(),
'deleted_at' => null,
]);
$counts['created']++;
}
return $counts;
});
$this->command->info(sprintf(
'Referências territoriais: %d criadas, %d já existentes, %d classificadas como públicas.',
$counts['created'],
$counts['unchanged'],
$counts['made_public'],
));
}
/** @param array<string, mixed> $record
* @param array<string, bool> $seen
* @param array<string, string> $types
*
* @param-out array<string, bool> $seen
* @param-out array<string, string> $types
*/
private function validateRecord(array $record, array &$seen, array &$types): void
{
$id = $record['id'] ?? null;
if (! is_string($id) || $id === '') {
throw new RuntimeException('Territory reference is missing a valid id.');
}
foreach (['id', 'name', 'location_type', 'code', 'source_code'] as $field) {
if (! isset($record[$field]) || $record[$field] === '') {
throw new RuntimeException('Territory reference is missing '.$field.'.');
}
}
$type = $record['location_type'];
$parentTypes = [
'country' => null,
'province' => 'country',
'district' => 'province',
'admin_post' => 'district',
'locality' => 'admin_post',
];
if (! is_string($type) || ! array_key_exists($type, $parentTypes) || isset($seen[$id])) {
throw new RuntimeException('Territory reference has an invalid type or duplicate ID.');
}
$expectedParent = $parentTypes[$type];
if ($expectedParent === null) {
if ($record['parent_id'] !== null) {
throw new RuntimeException('Country reference cannot have a parent.');
}
} elseif (! is_string($record['parent_id'] ?? null) || ($types[$record['parent_id']] ?? null) !== $expectedParent) {
throw new RuntimeException('Territory reference has a missing or invalid parent: '.$id);
}
$seen[$id] = true;
$types[$id] = $type;
}
}