File manager - Edit - /var/www/html/transparencia/database/seeders/ImportObrasSeeder.php
Back
<?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; use Maatwebsite\Excel\Facades\Excel; use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate; class ImportObrasSeeder extends Seeder { private const PLANILHA = 'temp/Obras-relatorio.xlsx'; public function run(): void { DB::table('obras')->truncate(); $fullPath = base_path(self::PLANILHA); if (!is_file($fullPath)) { $this->command?->error('Arquivo não encontrado: ' . self::PLANILHA); return; } $rows = Excel::toArray([], $fullPath)[0] ?? []; if ($rows === []) { $this->command?->warn('Planilha vazia.'); return; } $payload = []; // Skip index 0 ("INFORMAÇÕES DE OBRAS") and index 1 (headers) foreach ($rows as $index => $row) { if ($index < 2) { continue; } $processo = $this->cleanCell($row[0] ?? null); $objetoRaw = $this->cleanCell($row[1] ?? null); $situacao = $this->cleanCell($row[2] ?? null); $inicio = $this->parseDateCell($row[3] ?? null); $termino = $this->parseDateCell($row[4] ?? null); $conclusao = $this->parseDateCell($row[5] ?? null); $empresa = $this->cleanCell($row[6] ?? null); $valorContratado = $this->parseCurrency($row[7] ?? null); $valorPago = $this->parseCurrency($row[8] ?? null); $percentual = $this->cleanCell($row[9] ?? null); $quantitativo = $this->cleanCell($row[10] ?? null); $precoUnitario = $this->cleanCell($row[11] ?? null); $totaisContratados = $this->cleanCell($row[12] ?? null); $paralisacaoFundamentacao = $this->cleanCell($row[13] ?? null); $recomecar = $this->cleanCell($row[14] ?? null); $contrato = $this->cleanCell($row[15] ?? null); if ($this->isFullRowEmpty([ $processo, $objetoRaw, $situacao, $inicio, $termino, $conclusao, $empresa, $valorContratado, $valorPago, $percentual, $quantitativo, $precoUnitario, $totaisContratados, $paralisacaoFundamentacao, $recomecar, $contrato ])) { continue; } // Transform data: // 1. Title Case standardizer for Portuguese on Objeto column $objetoParsed = $this->toPortugueseTitleCase($objetoRaw); // 2. Extract and standardize Bairro from Objeto $bairro = $this->extractBairro($objetoRaw); // 3. Extract years for filters $anoInicio = $inicio ? (int) date('Y', strtotime($inicio)) : null; $anoTermino = null; if ($conclusao) { $anoTermino = (int) date('Y', strtotime($conclusao)); } elseif ($termino) { $anoTermino = (int) date('Y', strtotime($termino)); } $payload[] = [ 'processo' => $processo ? mb_substr($processo, 0, 100) : null, 'objeto' => $objetoParsed, 'bairro' => $bairro ? mb_substr($bairro, 0, 100) : null, 'situacao' => $situacao ? mb_substr($situacao, 0, 100) : null, 'data_inicio' => $inicio, 'data_prevista_termino' => $termino, 'data_conclusao' => $conclusao, 'ano_inicio' => $anoInicio, 'ano_termino' => $anoTermino, 'empresa' => $empresa ? mb_substr($empresa, 0, 255) : null, 'valor_contratado' => $valorContratado, 'valor_pago' => $valorPago, 'percentual_concluido' => $percentual ? mb_substr($percentual, 0, 50) : null, 'quantitativo' => $quantitativo ? mb_substr($quantitativo, 0, 255) : null, 'preco_unitario' => $precoUnitario ? mb_substr($precoUnitario, 0, 255) : null, 'totais_contratados' => $totaisContratados ? mb_substr($totaisContratados, 0, 255) : null, 'data_paralisacao_fundamentacao' => $paralisacaoFundamentacao, 'data_recomecar' => $recomecar ? mb_substr($recomecar, 0, 255) : null, 'contrato' => $contrato, 'created_at' => now(), 'updated_at' => now(), ]; } if ($payload === []) { $this->command?->warn('Nenhum registro de obras foi montado para importação.'); return; } foreach (array_chunk($payload, 500) as $chunk) { DB::table('obras')->insert($chunk); } $this->command?->info(count($payload) . ' registros de obras importados.'); } private function cleanCell(mixed $value): ?string { if ($value === null) { return null; } $value = preg_replace("/\r\n|\r/", "\n", trim((string) $value)); $value = preg_replace('/[ \t]+/u', ' ', $value); $value = trim((string) $value); return $value === '' ? null : $value; } private function parseDateCell(mixed $value): ?string { if ($value === null) { return null; } $trimmed = trim((string) $value); if ($trimmed === '' || $trimmed === '-') { return null; } if (is_numeric($trimmed)) { $n = (float) $trimmed; if ($n <= 0) { return null; } try { return ExcelDate::excelToDateTimeObject($n)->format('Y-m-d'); } catch (\Throwable) { return null; } } // Check if it's in d/m/Y or d/m/y format if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/', $trimmed, $matches)) { $day = (int)$matches[1]; $month = (int)$matches[2]; $year = (int)$matches[3]; if ($year < 100) { $year += 2000; } return sprintf('%04d-%02d-%02d', $year, $month, $day); } try { $ts = strtotime(str_replace('/', '-', $trimmed)); if ($ts !== false) { return date('Y-m-d', $ts); } } catch (\Throwable) { return null; } return null; } private function parseCurrency(mixed $val): float { if ($val === null) { return 0.0; } $val = str_replace('R$', '', (string) $val); $val = trim($val); if ($val === '' || $val === '-') { return 0.0; } if (str_contains($val, ',') && str_contains($val, '.')) { if (strrpos($val, ',') > strrpos($val, '.')) { $val = str_replace('.', '', $val); $val = str_replace(',', '.', $val); } else { $val = str_replace(',', '', $val); } } elseif (str_contains($val, ',')) { $val = str_replace(',', '.', $val); } $val = preg_replace('/[^\d\.\-]/', '', $val); return (float) $val; } private function isFullRowEmpty(array $values): bool { foreach ($values as $value) { if ($value !== null && $value !== 0.0 && trim((string) $value) !== '') { return false; } } return true; } private function toPortugueseTitleCase(?string $string): ?string { if (empty($string)) { return null; } $string = mb_strtolower(trim($string), 'UTF-8'); $exceptions = [ 'de', 'di', 'do', 'da', 'dos', 'das', 'no', 'na', 'nos', 'nas', 'em', 'para', 'com', 'por', 'e', 'ou', 'a', 'o', 'as', 'os', 'um', 'uma', 'uns', 'umas', 'ao', 'aos', 'à', 'às', 'pelo', 'pela', 'pelos', 'pelas' ]; $acronyms = [ 'eta' => 'ETA', 'cbuq' => 'CBUQ', 'sn' => 'S/Nº', 's/nº' => 'S/Nº', 's/n°' => 'S/Nº', 'snº' => 'S/Nº', 'ideas' => 'IDEAS', 'hsvp' => 'HSVP', 'masp' => 'MASP', 'jbk' => 'JBK', 'pncp' => 'PNCP', 'tce' => 'TCE', 'e-tce' => 'e-TCE', 'vc' => 'VC', 'vp' => 'VP', ]; $words = preg_split('/([\s\-\–\/\(\)\[\]\,\.\:\;\’\'\"º°]+)/u', $string, -1, PREG_SPLIT_DELIM_CAPTURE); $isFirst = true; foreach ($words as $i => $w) { if (preg_match('/^[a-z0-9à-ÿ]+/ui', $w)) { $lowerW = mb_strtolower($w, 'UTF-8'); if (isset($acronyms[$lowerW])) { $words[$i] = $acronyms[$lowerW]; } elseif ($isFirst || !in_array($lowerW, $exceptions)) { $words[$i] = mb_convert_case($w, MB_CASE_TITLE, "UTF-8"); } $isFirst = false; } } $result = implode('', $words); $result = str_replace([ 'Angra Dos Reis', 'Cemei', 'Membro Aditivo', 'S/nº', 'S/n°', 'S/n', 'S/a', 'Ltda' ], [ 'Angra dos Reis', 'CEMEI', 'Termo Aditivo', 'S/Nº', 'S/Nº', 'S/Nº', 'S/A', 'LTDA' ], $result); return $result; } private function extractBairro(?string $objeto): ?string { if (empty($objeto)) { return 'Não Identificado'; } $objeto = trim($objeto); // Predefined standardized neighborhood mappings in Angra dos Reis $knownBairros = [ 'Monsuaba' => 'Monsuaba', 'Jacuecanga' => 'Jacuecanga', 'Jacuacanga' => 'Jacuecanga', 'Frade' => 'Frade', 'Campo Belo' => 'Campo Belo', 'Parque Belém' => 'Parque Belém', 'Marinas' => 'Marinas', 'Areal' => 'Areal', 'Perez' => 'Morro do Perez', 'Parque Mambucaba' => 'Parque Mambucaba', 'Mambucaba' => 'Mambucaba', 'Village' => 'Village', 'Japuíba' => 'Japuíba', 'Balneário' => 'Balneário', 'Bonfim' => 'Bonfim', 'Bracuí' => 'Bracuí', 'Bracuhy' => 'Bracuí', 'Camorim' => 'Camorim', 'Caputera' => 'Caputera', 'Garatucaia' => 'Garatucaia', 'Gipoia' => 'Gipoia', 'Ilha Grande' => 'Ilha Grande', 'Abraão' => 'Abraão', 'Monção' => 'Monção', 'Retiro' => 'Retiro', 'Serra D\'Água' => 'Serra D\'Água', 'Vila Nova' => 'Vila Nova', 'Verolme' => 'Verolme', 'Banqueta' => 'Banqueta', 'Biscaia' => 'Biscaia', 'Zungú' => 'Zungú', 'Praia do Anil' => 'Praia do Anil', 'Centro' => 'Centro', 'Itinga' => 'Itinga', 'Caixa D\'Água' => 'Morro da Caixa D\'Água', 'Caixa D’Água' => 'Morro da Caixa D\'Água' ]; foreach ($knownBairros as $kb => $standardName) { if (mb_stripos($objeto, $kb) !== false) { return $standardName; } } // Regex fallbacks: // 1. Explicit BAIRRO if (preg_match('/(?:NO\s+|O\s+)?BAIRRO\s+(?:DO\s+|DA\s+|DE\s+|D\'\s+)?([A-ZÀ-Ý0-9\s\'\"’\-]+?)(?:, MUNICÍPIO| –| -|\.|\(|,|$)/ui', $objeto, $matches)) { return mb_convert_case(trim($matches[1]), MB_CASE_TITLE, "UTF-8"); } // 2. Explicit MORRO if (preg_match('/(?:NO\s+|DO\s+|O\s+)?MORRO\s+(?:DA\s+|DO\s+|DE\s+|D\'\s+)?([A-ZÀ-Ý0-9\s\'\"’\-]+?)(?:, MUNICÍPIO| –| -|\.|\(|,|$)/ui', $objeto, $matches)) { return 'Morro ' . mb_convert_case(trim($matches[1]), MB_CASE_TITLE, "UTF-8"); } // 3. Explicit DISTRITO if (preg_match('/DISTRITO\s+(?:DE\s+)?([A-ZÀ-Ý0-9\s\'\"’\-]+?)(?:, MUNICÍPIO| –| -|\.|\(|,|$)/ui', $objeto, $matches)) { return mb_convert_case(trim($matches[1]), MB_CASE_TITLE, "UTF-8"); } // 4. Before municipio suffix if (preg_match('/(?:\-\s+|–\s+)([^,\-\–\:]+),\s+MUNICÍPIO\s+DE\s+ANGRA\s+DOS\s+REIS/ui', $objeto, $matches)) { return mb_convert_case(trim($matches[1]), MB_CASE_TITLE, "UTF-8"); } return 'Não Identificado'; } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings