# πŸ—ƒοΈ CONNESSIONE DATABASE MDB - Configurazione Import ## πŸ“‹ **Setup Connessione Microsoft Access (.mdb)** ### **1. Prerequisiti Sistema** ```bash # Ubuntu/Debian - Installazione driver MDB sudo apt-get update sudo apt-get install mdbtools unixodbc unixodbc-dev sudo apt-get install libmdbodbc1 # Per PHP - Estensioni necessarie sudo apt-get install php-odbc php-pdo ``` ### **2. Configurazione ODBC** ```ini # /etc/odbc.ini [Gescon_Stabili] Description=Database Gescon Stabili Driver=MDBTools Database=/path/to/stabili.mdb Readonly=yes ``` ### **3. Test Connessione** ```bash # Test connessione ODBC isql -v Gescon_Stabili # Test con mdb-tools mdb-tables /path/to/stabili.mdb mdb-schema /path/to/stabili.mdb ``` --- ## πŸ”„ **Script PHP Import MDB** ### **Classe MDBImporter** ```php mdbPath = $mdbPath; $this->batchSize = $batchSize; } /** * Connessione al database MDB */ public function connect(): bool { try { // Prova prima con ODBC $dsn = "odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ={$this->mdbPath};"; $this->connection = new PDO($dsn); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); Log::info("Connessione MDB stabilita", ['file' => $this->mdbPath]); return true; } catch (PDOException $e) { // Fallback con mdb-tools Log::warning("Connessione ODBC fallita, utilizzo mdb-tools", [ 'error' => $e->getMessage() ]); return $this->connectWithMdbTools(); } } /** * Fallback con mdb-tools per sistemi Linux */ protected function connectWithMdbTools(): bool { if (!file_exists($this->mdbPath)) { Log::error("File MDB non trovato", ['path' => $this->mdbPath]); return false; } // Test con mdb-tables $output = shell_exec("mdb-tables -1 '{$this->mdbPath}' 2>/dev/null"); if (strpos($output, 'Stabili') !== false) { Log::info("Connessione MDB-Tools stabilita", ['tables' => trim($output)]); return true; } return false; } /** * Importa tabella Stabili */ public function importStabili(): array { $risultato = [ 'importati' => 0, 'errori' => 0, 'duplicati' => 0, 'dettagli' => [] ]; try { $stabiliData = $this->readStabiliFromMDB(); Log::info("Lettura MDB completata", [ 'records_found' => count($stabiliData) ]); foreach (array_chunk($stabiliData, $this->batchSize) as $batch) { $batchResult = $this->processBatch($batch); $risultato['importati'] += $batchResult['importati']; $risultato['errori'] += $batchResult['errori']; $risultato['duplicati'] += $batchResult['duplicati']; $risultato['dettagli'] = array_merge($risultato['dettagli'], $batchResult['dettagli']); } } catch (\Exception $e) { Log::error("Errore import MDB", ['error' => $e->getMessage()]); $risultato['errori']++; $risultato['dettagli'][] = [ 'tipo' => 'errore_critico', 'messaggio' => $e->getMessage() ]; } return $risultato; } /** * Legge dati dalla tabella Stabili */ protected function readStabiliFromMDB(): array { if ($this->connection) { return $this->readWithPDO(); } else { return $this->readWithMdbTools(); } } /** * Lettura con PDO/ODBC */ protected function readWithPDO(): array { $sql = "SELECT * FROM Stabili ORDER BY cod_stabile"; $stmt = $this->connection->prepare($sql); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } /** * Lettura con mdb-tools */ protected function readWithMdbTools(): array { $command = "mdb-export '{$this->mdbPath}' Stabili"; $csvOutput = shell_exec($command); if (!$csvOutput) { throw new \Exception("Impossibile leggere tabella Stabili da MDB"); } // Parsing CSV output $lines = explode("\n", trim($csvOutput)); $headers = str_getcsv(array_shift($lines)); $data = []; foreach ($lines as $line) { if (trim($line)) { $values = str_getcsv($line); $data[] = array_combine($headers, $values); } } return $data; } /** * Processa batch di record */ protected function processBatch(array $batch): array { $risultato = [ 'importati' => 0, 'errori' => 0, 'duplicati' => 0, 'dettagli' => [] ]; foreach ($batch as $record) { try { $recordResult = $this->processStabileRecord($record); if ($recordResult['success']) { if ($recordResult['type'] === 'created') { $risultato['importati']++; } else { $risultato['duplicati']++; } } else { $risultato['errori']++; } $risultato['dettagli'][] = $recordResult; } catch (\Exception $e) { $risultato['errori']++; $risultato['dettagli'][] = [ 'success' => false, 'cod_stabile' => $record['cod_stabile'] ?? 'N/A', 'error' => $e->getMessage() ]; } } return $risultato; } /** * Processa singolo record Stabile */ protected function processStabileRecord(array $record): array { $codStabile = $record['cod_stabile']; // Controlla duplicati $esistente = Stabile::where('cod_stabile_old', $codStabile)->first(); if ($esistente) { return [ 'success' => true, 'type' => 'duplicate', 'cod_stabile' => $codStabile, 'message' => 'Record giΓ  esistente' ]; } // Mapping dati $stabileData = $this->mapStabileData($record); // Validazione $validation = $this->validateStabileData($stabileData); if (!$validation['valid']) { return [ 'success' => false, 'cod_stabile' => $codStabile, 'error' => 'Validazione fallita: ' . implode(', ', $validation['errors']) ]; } // Creazione record $stabile = Stabile::create($stabileData); return [ 'success' => true, 'type' => 'created', 'cod_stabile' => $codStabile, 'netgescon_id' => $stabile->id, 'message' => 'Importato con successo' ]; } /** * Mapping dati da MDB a NetGescon */ protected function mapStabileData(array $mdbRecord): array { // Trova comune $comune = ComuneItaliano::where('nome', $mdbRecord['citta']) ->where('provincia', $mdbRecord['provincia']) ->first(); // Trova amministratore $amministratore = null; if (!empty($mdbRecord['cf_amministratore'])) { $amministratore = User::where('codice_fiscale', $mdbRecord['cf_amministratore'])->first(); } // Prepara dati bancari JSON $datiBancari = [ 'iban_principale' => $mdbRecord['iban_bancario'] ?? null, 'iban_postale' => $mdbRecord['iban_postale'] ?? null, 'banca_denominazione' => $mdbRecord['banca'] ?? null, 'abi' => $mdbRecord['abi'] ?? null, 'cab' => $mdbRecord['cab'] ?? null, 'cc_postale' => $mdbRecord['conto_postale'] ?? null ]; // Prepara dati catastali JSON $datiCatastali = [ 'foglio' => $mdbRecord['AC_Foglio'] ?? null, 'particella' => $mdbRecord['AC_partic'] ?? null ]; // Prepara configurazione rate JSON $configRate = [ 'ordinarie' => [ 'q1' => ($mdbRecord['ORD_trimestre1'] ?? false) === true, 'q2' => ($mdbRecord['ORD_trimestre2'] ?? false) === true, 'q3' => ($mdbRecord['ORD_trimestre3'] ?? false) === true, 'q4' => ($mdbRecord['ORD_trimestre4'] ?? false) === true ], 'riserva' => [ 'q1' => ($mdbRecord['RIS_trimestre1'] ?? false) === true, 'q2' => ($mdbRecord['RIS_trimestre2'] ?? false) === true, 'q3' => ($mdbRecord['RIS_trimestre3'] ?? false) === true, 'q4' => ($mdbRecord['RIS_trimestre4'] ?? false) === true ] ]; return [ 'cod_stabile_old' => $mdbRecord['cod_stabile'], 'directory_name' => $mdbRecord['nome_directory'] ?? null, 'denominazione' => $mdbRecord['denominazione'], 'indirizzo' => $mdbRecord['indirizzo'], 'cap' => $mdbRecord['cap'], 'citta' => $mdbRecord['citta'], 'provincia' => $mdbRecord['provincia'], 'codice_fiscale' => $mdbRecord['codice_fiscale'] ?? null, 'comune_id' => $comune?->id, 'amministratore_id' => $amministratore?->id, 'totale_unita_immobiliari' => (int)($mdbRecord['num_condomini'] ?? 0), 'numero_scale' => (int)($mdbRecord['num_scale'] ?? 0), 'data_nomina_amministratore' => $this->parseDate($mdbRecord['data_nomina'] ?? null), 'dati_bancari' => json_encode($datiBancari), 'dati_catastali' => json_encode($datiCatastali), 'configurazione_rate' => json_encode($configRate), 'note_migrazione' => $mdbRecord['note'] ?? null, 'stato_attivo' => ($mdbRecord['attivo'] ?? true) === true, 'data_creazione_old' => $this->parseDate($mdbRecord['data_creazione'] ?? null), 'data_modifica_old' => $this->parseDate($mdbRecord['data_modifica'] ?? null), 'migrazione_completata_at' => now() ]; } /** * Validazione dati stabile */ protected function validateStabileData(array $data): array { $errors = []; if (empty($data['denominazione'])) { $errors[] = 'Denominazione obbligatoria'; } if (empty($data['indirizzo'])) { $errors[] = 'Indirizzo obbligatorio'; } if (empty($data['cap']) || !preg_match('/^\d{5}$/', $data['cap'])) { $errors[] = 'CAP non valido'; } if (empty($data['citta'])) { $errors[] = 'CittΓ  obbligatoria'; } if (empty($data['provincia']) || strlen($data['provincia']) !== 2) { $errors[] = 'Provincia non valida'; } return [ 'valid' => empty($errors), 'errors' => $errors ]; } /** * Parse date da formato MDB */ protected function parseDate($dateString): ?string { if (empty($dateString)) { return null; } try { $date = new \DateTime($dateString); return $date->format('Y-m-d'); } catch (\Exception $e) { return null; } } /** * Chiude connessione */ public function disconnect(): void { $this->connection = null; } } ``` --- ## πŸš€ **Comando Artisan Import** ```php argument('file'); $batchSize = (int)$this->option('batch-size'); $validateOnly = $this->option('validate-only'); $force = $this->option('force'); $this->info("πŸ—ƒοΈ Avvio import stabili da MDB"); $this->info("File: {$filePath}"); $this->info("Batch size: {$batchSize}"); if (!file_exists($filePath)) { $this->error("File MDB non trovato: {$filePath}"); return 1; } try { $importer = new MDBImporter($filePath, $batchSize); $this->info("πŸ”Œ Connessione al database MDB..."); if (!$importer->connect()) { $this->error("Impossibile connettersi al database MDB"); return 1; } $this->info("βœ… Connessione stabilita"); if ($validateOnly) { $this->info("πŸ” ModalitΓ  validazione - nessun dato verrΓ  importato"); // TODO: Implementare validazione $this->info("βœ… Validazione completata"); return 0; } if (!$force && !$this->confirm('Procedere con l\'import?')) { $this->info("Import annullato"); return 0; } $this->info("πŸ“¦ Avvio import in transazione..."); DB::beginTransaction(); try { $risultato = $importer->importStabili(); $this->newLine(); $this->info("πŸ“Š RISULTATI IMPORT:"); $this->info("βœ… Importati: {$risultato['importati']}"); $this->info("πŸ”„ Duplicati: {$risultato['duplicati']}"); $this->info("❌ Errori: {$risultato['errori']}"); if ($risultato['errori'] > 0) { $this->warn("⚠️ Import completato con errori"); if (!$force) { $this->error("Import interrotto per errori. Usa --force per procedere"); DB::rollback(); return 1; } } DB::commit(); $this->info("βœ… Import completato con successo"); // Mostra dettagli se richiesto if ($this->option('verbose')) { $this->showDetails($risultato['dettagli']); } } catch (\Exception $e) { DB::rollback(); $this->error("Errore durante import: " . $e->getMessage()); return 1; } } catch (\Exception $e) { $this->error("Errore critico: " . $e->getMessage()); return 1; } finally { $importer->disconnect(); } return 0; } protected function showDetails(array $dettagli): void { $this->newLine(); $this->info("πŸ“‹ DETTAGLI IMPORT:"); foreach ($dettagli as $dettaglio) { $status = $dettaglio['success'] ? 'βœ…' : '❌'; $this->line("{$status} {$dettaglio['cod_stabile']}: {$dettaglio['message'] ?? $dettaglio['error'] ?? 'N/A'}"); } } } ``` --- ## πŸ”§ **Script di Test e Validazione** ```bash #!/bin/bash # test-mdb-connection.sh echo "πŸ§ͺ Test connessione database MDB" MDB_FILE="$1" if [ -z "$MDB_FILE" ]; then echo "❌ Specificare il path del file MDB" echo "Uso: $0 /path/to/stabili.mdb" exit 1 fi if [ ! -f "$MDB_FILE" ]; then echo "❌ File non trovato: $MDB_FILE" exit 1 fi echo "πŸ“ File: $MDB_FILE" # Test 1: mdb-tools echo "πŸ” Test 1: Verifica tabelle con mdb-tools" if command -v mdb-tables >/dev/null 2>&1; then echo "Tabelle trovate:" mdb-tables -1 "$MDB_FILE" echo -e "\nπŸ“Š Schema tabella Stabili:" mdb-schema "$MDB_FILE" -T Stabili echo -e "\nπŸ“ˆ Conteggio record:" mdb-export "$MDB_FILE" Stabili | wc -l else echo "⚠️ mdb-tools non installato" fi # Test 2: ODBC echo -e "\nπŸ” Test 2: Verifica connessione ODBC" if command -v isql >/dev/null 2>&1; then echo "SELECT COUNT(*) FROM Stabili;" | isql -v "Driver={Microsoft Access Driver (*.mdb)};DBQ=$MDB_FILE;" 2>/dev/null if [ $? -eq 0 ]; then echo "βœ… Connessione ODBC riuscita" else echo "⚠️ Connessione ODBC fallita" fi else echo "⚠️ isql non disponibile" fi # Test 3: Preview dati echo -e "\nπŸ“‹ Preview primi 5 record:" mdb-export "$MDB_FILE" Stabili | head -6 echo -e "\nβœ… Test completato" ```