File manager - Edit - /var/www/html/homologBancodetalentos/app/Console/Commands/TalentBankLegacyMigrateCommand.php
Back
<?php namespace App\Console\Commands; use App\Support\TalentBank\IntegrationLog; use App\Support\TalentBank\LegacyMigrationImporter; use App\Support\TalentBank\LegacySqlDumpImporter; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; use Symfony\Component\Console\Helper\ProgressBar; use Throwable; class TalentBankLegacyMigrateCommand extends Command { protected $signature = 'talent-bank:legacy-migrate {--sql-dump= : Caminho do arquivo .sql a importar (modo dump). Omita para usar conexão legada direta.} {--domain=all : Domínio a migrar: candidates|companies|jobs|applications|all} {--from-date= : Migrar apenas registros com updated_at >= YYYY-MM-DD (candidates/companies/jobs)} {--legacy-connection= : Conexão Laravel ao banco legado (ignorado se --sql-dump for informado)} {--target-connection= : Conexão Laravel ao banco alvo BT (padrão: config target_connection)} {--batch-size= : Registros por chunk (padrão: config batch_size ou 500)} {--report= : Caminho do arquivo JSON de relatório} {--stdout : Imprime o JSON completo no stdout ao final} {--force : Executa sem confirmação interativa} {--keep-temp-db : Mantém o banco temporário após a migração (sobrescreve config)}'; protected $description = 'Migra dados legado→BT (candidates, companies, vagas, candidaturas). Aceita dump .sql ou conexão direta. Re-execuções são seguras (idempotente).'; private const VALID_DOMAINS = ['candidates', 'companies', 'jobs', 'applications', 'all']; private const DOMAIN_LABELS = [ 'candidates' => 'Candidatos', 'companies' => 'Empresas', 'job_listings' => 'Vagas', 'job_applications' => 'Candidaturas', ]; /** @var array<string, ProgressBar> */ private array $bars = []; public function handle(): int { $this->newLine(); $this->line('╔══════════════════════════════════════════════════════╗'); $this->line('║ Migração Legado → Banco de Talentos ║'); $this->line('╚══════════════════════════════════════════════════════╝'); $this->newLine(); // ── 1. Validar --domain ────────────────────────────────────────────── $domain = (string) $this->option('domain'); if (! in_array($domain, self::VALID_DOMAINS, true)) { $this->error('--domain inválido. Opções: ' . implode('|', self::VALID_DOMAINS)); return self::FAILURE; } // ── 2. Resolver parâmetros ─────────────────────────────────────────── $sqlDump = $this->option('sql-dump') ? (string) $this->option('sql-dump') : null; $fromDate = $this->option('from-date') ? (string) $this->option('from-date') : null; $targetConn = (string) ($this->option('target-connection') ?: config('talent_bank_legacy_import.target_connection')); $batchSize = max(1, (int) ($this->option('batch-size') ?: config('talent_bank_legacy_import.batch_size', 500))); $keepTemp = (bool) $this->option('keep-temp-db'); $tables = (array) config('talent_bank_legacy_import.tables', []); // Modo dump vs. conexão direta $useDump = $sqlDump !== null; $legacyConn = $useDump ? 'mysql_bt_legacy' : (string) ($this->option('legacy-connection') ?: config('talent_bank_legacy_import.connection')); // ── 3. Sumário antes de confirmar ──────────────────────────────────── $this->info('Configuração:'); $this->line(" Modo: " . ($useDump ? 'dump SQL' : 'conexão direta')); if ($useDump) { $this->line(" Arquivo dump: {$sqlDump}"); } $this->line(" Domínio: {$domain}"); $this->line(" Conexão legada: {$legacyConn}"); $this->line(" Conexão alvo: {$targetConn}"); $this->line(" Chunk size: {$batchSize}"); if ($fromDate) { $this->line(" Filtro data: >= {$fromDate}"); } $this->newLine(); // ── 4. Confirmação interativa ──────────────────────────────────────── if (! $this->option('force') && ! $this->confirm('Confirma o início da migração?', false)) { $this->line('Migração cancelada pelo usuário.'); return self::SUCCESS; } // ── 5. Importar dump SQL (se aplicável) ────────────────────────────── $dumpImporter = null; if ($useDump) { $exitCode = $this->runDumpImport($sqlDump, $keepTemp, $dumpImporter); if ($exitCode !== self::SUCCESS) { return $exitCode; } } // ── 6. Executar migração de domínios ───────────────────────────────── $importer = new LegacyMigrationImporter( legacyConnection: $legacyConn, targetConnection: $targetConn, tables: $tables, fromDate: $fromDate, batchSize: $batchSize, ); $importer->setProgressCallback(function ( string $domainKey, int $processed, int $total, int $inserted, int $updated, int $skipped, int $errors, ): void { $this->updateProgressBar($domainKey, $processed, $total, $inserted, $updated, $skipped, $errors); }); $this->newLine(); $this->info('── Iniciando migração ──────────────────────────────────'); $this->newLine(); try { $report = match ($domain) { 'candidates' => $importer->importCandidates(), 'companies' => $importer->importCompanies(), 'jobs' => $importer->importJobs(), 'applications' => $importer->importApplications(), default => $importer->importAll(), }; } catch (Throwable $e) { $this->finishAllBars(); $this->newLine(2); $this->error('Erro fatal durante a migração: ' . $e->getMessage()); if ($dumpImporter !== null && ! $keepTemp) { $dumpImporter->cleanup(); } return self::FAILURE; } $this->finishAllBars(); $this->newLine(2); // ── 7. Limpar banco temporário ─────────────────────────────────────── if ($dumpImporter !== null && ! $keepTemp) { $this->line('Removendo banco temporário...'); $dumpImporter->cleanup(); $this->line('Banco temporário removido.'); } elseif ($dumpImporter !== null && $keepTemp) { $this->warn("Banco temporário mantido: `{$dumpImporter->getTempDatabase()}`"); } // ── 8. Salvar relatório JSON ───────────────────────────────────────── $reportPath = $this->resolveReportPath(); File::ensureDirectoryExists(dirname($reportPath)); File::put($reportPath, json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE)); // ── 9. Log de integração ───────────────────────────────────────────── IntegrationLog::info('talent_bank.legacy_migration', 'migrate_completed', [ 'domain' => $domain, 'legacy_connection' => $legacyConn, 'target_connection' => $targetConn, 'total_errors' => $report['total_errors'] ?? 0, 'used_dump' => $useDump, ]); // ── 10. Exibir tabela de resultados ────────────────────────────────── $this->newLine(); $this->info('── Resultado ───────────────────────────────────────────'); $this->newLine(); $this->printStats($report['stats'] ?? []); $this->newLine(); $this->line("Relatório gravado em: {$reportPath}"); if ($this->option('stdout')) { $this->newLine(); $this->line(json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE)); } $totalErrors = (int) ($report['total_errors'] ?? 0); if ($totalErrors > 0) { $this->newLine(); $this->warn("Migração concluída com {$totalErrors} erro(s). Consulte o relatório JSON para detalhes."); return self::FAILURE; } $this->info('Migração concluída com sucesso.'); return self::SUCCESS; } // ───────────────────────────────────────────────────────────────────────── // Dump import // ───────────────────────────────────────────────────────────────────────── private function runDumpImport(string $sqlDump, bool $keepTemp, ?LegacySqlDumpImporter &$dumpImporter): int { $tempDb = (string) config('talent_bank_legacy_import.temp_database', 'bt_legacy_import_temp'); $dropAfter = $keepTemp ? false : (bool) config('talent_bank_legacy_import.drop_temp_database_after_import', true); $dumpImporter = new LegacySqlDumpImporter( sqlPath: $sqlDump, tempDatabase: $tempDb, dropAfter: $dropAfter, ); $this->info('── Importando dump SQL ─────────────────────────────────'); $this->newLine(); try { $dumpImporter->import(function (string $step, string $message): void { $this->line(" [{$step}] {$message}"); }); } catch (Throwable $e) { $this->newLine(); $this->error('Falha ao importar o dump SQL: ' . $e->getMessage()); return self::FAILURE; } $this->newLine(); return self::SUCCESS; } // ───────────────────────────────────────────────────────────────────────── // Barra de progresso por domínio // ───────────────────────────────────────────────────────────────────────── private function updateProgressBar( string $domainKey, int $processed, int $total, int $inserted, int $updated, int $skipped, int $errors, ): void { $label = self::DOMAIN_LABELS[$domainKey] ?? $domainKey; $safeTotal = max(1, $total); if (! isset($this->bars[$domainKey])) { $this->line(" {$label}:"); $bar = $this->output->createProgressBar($safeTotal); $bar->setFormat(" %current%/%max% [%bar%] %percent:3s%% %message%"); $bar->setMessage('aguardando...'); $bar->start(); $this->bars[$domainKey] = $bar; } $bar = $this->bars[$domainKey]; $bar->setMaxSteps($safeTotal); $bar->setMessage("+{$inserted} ins ~{$updated} atu -{$skipped} ig !{$errors} err"); $bar->setProgress(min($processed, $safeTotal)); if ($total > 0 && $processed >= $total) { $bar->finish(); $this->newLine(); } } private function finishAllBars(): void { foreach ($this->bars as $bar) { $bar->finish(); } if (! empty($this->bars)) { $this->newLine(); } } // ───────────────────────────────────────────────────────────────────────── // Helpers // ───────────────────────────────────────────────────────────────────────── private function resolveReportPath(): string { $opt = $this->option('report'); if (! is_string($opt) || trim($opt) === '') { return storage_path('app/talent_bank_legacy_migrate_' . now()->format('Y-m-d_His') . '.json'); } $rp = trim($opt); $isAbsolute = str_starts_with($rp, '/') || preg_match('#^[A-Za-z]:[/\\\\]#', $rp); return $isAbsolute ? $rp : base_path(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $rp)); } /** @param array<string, array{inserted:int, updated:int, skipped:int, errors:list<mixed>}> $stats */ private function printStats(array $stats): void { $rows = []; foreach ($stats as $domainKey => $s) { $label = self::DOMAIN_LABELS[$domainKey] ?? $domainKey; $errCount = count($s['errors'] ?? []); $rows[] = [ $label, $s['inserted'] ?? 0, $s['updated'] ?? 0, $s['skipped'] ?? 0, $errCount > 0 ? "<fg=red>{$errCount}</>" : '0', ]; } $this->table( ['Domínio', 'Inseridos', 'Atualizados', 'Ignorados', 'Erros'], $rows ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings