netgescon-day0/app/Http/Controllers/Admin/ComuniImportController.php

249 lines
11 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Http\JsonResponse;
use Carbon\Carbon;
class ComuniImportController extends Controller
{
private function progressKey(): string
{
return 'comuni_import:' . (Auth::id() ?? 'guest');
}
public function stagingTables()
{
$conn = Config::get('database.connections.gescon_import') ? 'gescon_import' : Config::get('database.default');
// Try to list tables containing "comun"
$driver = DB::connection($conn)->getDriverName();
try {
if ($driver === 'mysql') {
$dbName = DB::connection($conn)->getDatabaseName();
$rows = DB::connection($conn)->select(
'SELECT table_name FROM information_schema.tables WHERE table_schema = ? AND table_name LIKE ? ORDER BY table_name',
[$dbName, 'mdb%comun%']
);
$tables = array_map(fn($r) => $r->table_name, $rows);
} elseif ($driver === 'pgsql') {
$rows = DB::connection($conn)->select(
"SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema') AND tablename ILIKE 'mdb%comun%' ORDER BY tablename"
);
$tables = array_map(fn($r) => $r->tablename, $rows);
} else {
// Fallback generic (may not work on all drivers)
$tables = [];
}
} catch (\Throwable $e) {
$tables = [];
}
return new JsonResponse(['tables' => $tables, 'connection' => $conn]);
}
public function init(Request $request)
{
$request->validate([
'staging_table' => 'required|string',
]);
$conn = Config::get('database.connections.gescon_import') ? 'gescon_import' : Config::get('database.default');
$table = $request->string('staging_table')->toString();
if (!DB::connection($conn)->getSchemaBuilder()->hasTable($table)) {
return new JsonResponse(['ok' => false, 'error' => 'Tabella di staging non trovata', 'table' => $table], 400);
}
$total = (int) DB::connection($conn)->table($table)->count();
$state = [
'table' => $table,
'connection' => $conn,
'total' => $total,
'processed' => 0,
'last_id' => 0,
'status' => 'running',
'started_at' => Carbon::now()->toISOString(),
];
Cache::put($this->progressKey(), $state, Carbon::now()->addHours(2));
return new JsonResponse(['ok' => true, 'progress' => $state]);
}
public function progress()
{
$state = Cache::get($this->progressKey());
if (!$state) return new JsonResponse(['ok' => false, 'error' => 'Nessun import attivo']);
// Calcola percentuale
$pct = $state['total'] > 0 ? (int) floor(($state['processed'] / $state['total']) * 100) : 0;
$state['percent'] = max(0, min(100, $pct));
return new JsonResponse(['ok' => true, 'progress' => $state]);
}
public function processChunk(Request $request)
{
$chunk = max(1, min(2000, (int) $request->input('chunk', 500)));
$state = Cache::get($this->progressKey());
if (!$state) return new JsonResponse(['ok' => false, 'error' => 'Import non inizializzato'], 400);
if (($state['status'] ?? '') === 'completed') {
return new JsonResponse(['ok' => true, 'progress' => $state]);
}
$conn = $state['connection'];
$table = $state['table'];
$lastId = (int) ($state['last_id'] ?? 0);
if (!DB::connection($conn)->getSchemaBuilder()->hasTable($table)) {
return new JsonResponse(['ok' => false, 'error' => 'Tabella di staging non trovata', 'table' => $table], 400);
}
$rows = DB::connection($conn)->table($table)
->where('id', '>', $lastId)
->orderBy('id')
->limit($chunk)
->get();
if ($rows->isEmpty()) {
$state['status'] = 'completed';
$state['completed_at'] = Carbon::now()->toISOString();
Cache::put($this->progressKey(), $state, Carbon::now()->addHours(2));
return new JsonResponse(['ok' => true, 'progress' => $state]);
}
// Import logic → comuni_italiani
$imported = 0;
foreach ($rows as $r) {
$data = (array) $r;
$map = $this->mapComuneRecord($data);
if (!$map) {
$lastId = $r->id; // advance pointer
continue;
}
try {
$this->upsertComuneItaliano($map);
$imported++;
} catch (\Throwable $e) {
Log::warning('Comuni import: errore record', ['id' => $r->id, 'err' => $e->getMessage()]);
}
$lastId = $r->id;
}
$state['processed'] = (int) $state['processed'] + $rows->count();
$state['last_id'] = $lastId;
if ($state['processed'] >= $state['total']) {
$state['status'] = 'completed';
$state['completed_at'] = Carbon::now()->toISOString();
}
Cache::put($this->progressKey(), $state, Carbon::now()->addHours(2));
return new JsonResponse(['ok' => true, 'progress' => $state, 'chunk_imported' => $imported]);
}
private function mapComuneRecord(array $row): ?array
{
// Normalizza chiavi in snake
$lower = [];
foreach ($row as $k => $v) {
$lower[Str::snake(strtolower((string) $k))] = is_string($v) ? trim($v) : $v;
}
$get = function (array $candidates) use ($lower) {
foreach ($candidates as $c) {
if (array_key_exists($c, $lower) && $lower[$c] !== null && $lower[$c] !== '') return $lower[$c];
}
return null;
};
$codiceIstat = $get(['codice_istat', 'istat', 'cod_istat', 'codiceistat']);
$denominazione = $get(['denominazione', 'comune', 'nome_comune', 'dencom']);
$den_straniera = $get(['denominazione_straniera', 'denominazione_altra_lingua', 'denominazione_alt']);
$codiceCat = $get(['codice_catastale', 'cod_catastale', 'cod_cat', 'belfiore']);
$cap = $get(['cap']);
$provCod = strtoupper((string) $get(['provincia', 'sigla_provincia', 'prov', 'pr']));
if ($provCod && strlen($provCod) > 2) $provCod = substr($provCod, 0, 2);
$provDen = $get(['provincia_denominazione', 'denominazione_provincia']);
$regCod = $get(['regione_codice', 'codice_regione', 'regione_cod']);
$regDen = $get(['regione_denominazione', 'denominazione_regione']);
if (!$denominazione && !$codiceIstat && !$codiceCat) return null;
return [
'codice_istat' => $codiceIstat,
'denominazione' => $denominazione ?: null,
'denominazione_straniera' => $den_straniera ?: null,
'codice_catastale' => $codiceCat ?: null,
'cap' => $cap ?: null,
'provincia_codice' => $provCod ?: null,
'provincia_denominazione' => $provDen ?: null,
'regione_codice' => $regCod ?: null,
'regione_denominazione' => $regDen ?: null,
];
}
private function upsertComuneItaliano(array $rec): void
{
// Preferisci upsert per codice_istat univoco, altrimenti fallback su codice_catastale
if (!empty($rec['codice_istat'])) {
DB::table('comuni_italiani')->updateOrInsert(
['codice_istat' => $rec['codice_istat']],
[
'denominazione' => $rec['denominazione'],
'denominazione_straniera' => $rec['denominazione_straniera'],
'codice_catastale' => $rec['codice_catastale'],
'cap' => $rec['cap'],
'provincia_codice' => $rec['provincia_codice'],
'provincia_denominazione' => $rec['provincia_denominazione'],
'regione_codice' => $rec['regione_codice'],
'regione_denominazione' => $rec['regione_denominazione'],
'updated_at' => Carbon::now(),
'created_at' => DB::raw('COALESCE(created_at, NOW())'),
]
);
return;
}
if (!empty($rec['codice_catastale'])) {
$existing = DB::table('comuni_italiani')->where('codice_catastale', $rec['codice_catastale'])->first();
if ($existing) {
DB::table('comuni_italiani')->where('id', $existing->id)->update([
'denominazione' => $rec['denominazione'],
'denominazione_straniera' => $rec['denominazione_straniera'],
'cap' => $rec['cap'],
'provincia_codice' => $rec['provincia_codice'],
'provincia_denominazione' => $rec['provincia_denominazione'],
'regione_codice' => $rec['regione_codice'],
'regione_denominazione' => $rec['regione_denominazione'],
'updated_at' => Carbon::now(),
]);
} else {
DB::table('comuni_italiani')->insert(array_merge($rec, [
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]));
}
return;
}
// Fallback fragile: denominazione+provincia
if (!empty($rec['denominazione'])) {
$q = DB::table('comuni_italiani')->where('denominazione', $rec['denominazione']);
if (!empty($rec['provincia_codice'])) $q->where('provincia_codice', $rec['provincia_codice']);
$existing = $q->first();
if ($existing) {
DB::table('comuni_italiani')->where('id', $existing->id)->update([
'codice_istat' => $rec['codice_istat'],
'codice_catastale' => $rec['codice_catastale'],
'cap' => $rec['cap'],
'provincia_denominazione' => $rec['provincia_denominazione'],
'regione_codice' => $rec['regione_codice'],
'regione_denominazione' => $rec['regione_denominazione'],
'updated_at' => Carbon::now(),
]);
} else {
DB::table('comuni_italiani')->insert(array_merge($rec, [
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]));
}
}
}
}