File manager - Edit - /var/www/html/portalHomolog/database/seeders/CleanOrphansSeeder.php
Back
<?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; /** * Seeder responsável por identificar e remover automaticamente * todos os registros órfãos em todo o banco de dados. * * Este seeder: * - Lê dinamicamente o esquema do banco de dados MySQL * - Identifica todas as foreign keys existentes * - Gera e executa queries SQL para remover registros órfãos * - Registra no log cada limpeza realizada * * @package Database\Seeders */ class CleanOrphansSeeder extends Seeder { /** * Nome do banco de dados atual * * @var string */ protected string $databaseName; /** * Lista de foreign keys encontradas * * @var array */ protected array $foreignKeys = []; /** * Total de registros removidos * * @var int */ protected int $totalRemoved = 0; /** * Run the database seeds. * * @return void */ public function run(): void { $this->info('Iniciando limpeza de registros órfãos...'); try { // Obtém o nome do banco de dados atual $this->databaseName = DB::connection()->getDatabaseName(); // Busca todas as foreign keys $this->fetchForeignKeys(); if (empty($this->foreignKeys)) { $this->info('Nenhuma foreign key encontrada no banco de dados.'); return; } $this->info("Encontradas " . count($this->foreignKeys) . " foreign key(s) para verificar."); // Ordena as foreign keys por dependência (tabelas filhas primeiro) $this->sortForeignKeysByDependency(); // Executa a limpeza para cada foreign key foreach ($this->foreignKeys as $fk) { $this->cleanOrphanRecords($fk); } $this->info("Limpeza concluída! Total de registros removidos: {$this->totalRemoved}"); } catch (\Exception $e) { $this->error("Erro durante a limpeza de registros órfãos: " . $e->getMessage()); Log::error('CleanOrphansSeeder: Erro ao executar limpeza', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); throw $e; } } /** * Busca todas as foreign keys do banco de dados * * @return void */ protected function fetchForeignKeys(): void { $query = " SELECT kcu.TABLE_SCHEMA, kcu.TABLE_NAME AS child_table, kcu.COLUMN_NAME AS child_column, kcu.CONSTRAINT_NAME, kcu.REFERENCED_TABLE_NAME AS parent_table, kcu.REFERENCED_COLUMN_NAME AS parent_column FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu WHERE kcu.TABLE_SCHEMA = ? AND kcu.REFERENCED_TABLE_NAME IS NOT NULL AND kcu.REFERENCED_COLUMN_NAME IS NOT NULL ORDER BY kcu.TABLE_NAME, kcu.CONSTRAINT_NAME "; $this->foreignKeys = DB::select($query, [$this->databaseName]); } /** * Ordena as foreign keys por dependência * Tabelas que são referenciadas por outras devem ser processadas por último * * @return void */ protected function sortForeignKeysByDependency(): void { // Cria um mapa de dependências $dependencyMap = []; $tableOrder = []; foreach ($this->foreignKeys as $fk) { $childTable = $fk->child_table; $parentTable = $fk->parent_table; if (!isset($dependencyMap[$childTable])) { $dependencyMap[$childTable] = []; $tableOrder[$childTable] = 0; } $dependencyMap[$childTable][] = $parentTable; } // Ordena usando topological sort simples // Tabelas que não são referenciadas por outras vêm primeiro usort($this->foreignKeys, function ($a, $b) use ($dependencyMap) { $aIsReferenced = $this->isTableReferenced($a->child_table); $bIsReferenced = $this->isTableReferenced($b->child_table); // Se uma tabela é referenciada e a outra não, a não referenciada vem primeiro if ($aIsReferenced && !$bIsReferenced) { return 1; } if (!$aIsReferenced && $bIsReferenced) { return -1; } // Caso contrário, mantém a ordem original return 0; }); } /** * Verifica se uma tabela é referenciada por alguma foreign key * * @param string $tableName * @return bool */ protected function isTableReferenced(string $tableName): bool { foreach ($this->foreignKeys as $fk) { if ($fk->parent_table === $tableName) { return true; } } return false; } /** * Limpa registros órfãos para uma foreign key específica * * @param object $foreignKey * @return void */ protected function cleanOrphanRecords(object $foreignKey): void { $childTable = $foreignKey->child_table; $childColumn = $foreignKey->child_column; $parentTable = $foreignKey->parent_table; $parentColumn = $foreignKey->parent_column; try { // Gera a query SQL para deletar registros órfãos $sql = " DELETE child FROM `{$childTable}` AS child LEFT JOIN `{$parentTable}` AS parent ON child.`{$childColumn}` = parent.`{$parentColumn}` WHERE parent.`{$parentColumn}` IS NULL "; // Executa a query e obtém o número de linhas afetadas // Usando affectingStatement para queries DELETE com JOIN $affectedRows = DB::affectingStatement($sql); if ($affectedRows > 0) { $this->totalRemoved += $affectedRows; $message = sprintf( "Removidos %d registro(s) órfão(s) da tabela '%s' (FK: %s -> %s.%s)", $affectedRows, $childTable, $childColumn, $parentTable, $parentColumn ); $this->info($message); // Registra no log do Laravel Log::info('CleanOrphansSeeder: Registros órfãos removidos', [ 'child_table' => $childTable, 'child_column' => $childColumn, 'parent_table' => $parentTable, 'parent_column' => $parentColumn, 'removed_count' => $affectedRows ]); } else { $this->line("Nenhum registro órfão encontrado em '{$childTable}' (FK: {$childColumn} -> {$parentTable}.{$parentColumn})"); } } catch (\Exception $e) { $errorMessage = sprintf( "Erro ao limpar registros órfãos da tabela '%s' (FK: %s -> %s.%s): %s", $childTable, $childColumn, $parentTable, $parentColumn, $e->getMessage() ); $this->error($errorMessage); Log::error('CleanOrphansSeeder: Erro ao limpar registros órfãos', [ 'child_table' => $childTable, 'child_column' => $childColumn, 'parent_table' => $parentTable, 'parent_column' => $parentColumn, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); // Continua processando outras foreign keys mesmo se uma falhar } } /** * Exibe mensagem informativa no console * * @param string $message * @return void */ protected function info(string $message): void { if (isset($this->command)) { $this->command->info($message); } else { echo $message . PHP_EOL; } } /** * Exibe mensagem de erro no console * * @param string $message * @return void */ protected function error(string $message): void { if (isset($this->command)) { $this->command->error($message); } else { echo "ERRO: " . $message . PHP_EOL; } } /** * Exibe mensagem de linha no console * * @param string $message * @return void */ protected function line(string $message): void { if (isset($this->command)) { $this->command->line($message); } else { echo $message . PHP_EOL; } } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings