logFile = $logFile ?? $defaultLogDir . '/migration_' . date('Ymd_His') . '.log'; $this->verbose = $verbose; // Créer le dossier parent si nécessaire $dir = dirname($this->logFile); if (!is_dir($dir)) { mkdir($dir, 0755, true); } // Vérifier que le fichier est accessible en écriture if (!is_writable(dirname($this->logFile))) { throw new Exception("Log directory is not writable: " . dirname($this->logFile)); } } /** * Log un message avec niveau INFO */ public function info(string $message): void { $this->log($message, 'INFO'); } /** * Log un message avec niveau SUCCESS */ public function success(string $message): void { $this->log($message, 'SUCCESS'); } /** * Log un message avec niveau WARNING */ public function warning(string $message): void { $this->log($message, 'WARNING'); } /** * Log un message avec niveau ERROR */ public function error(string $message): void { $this->log($message, 'ERROR'); } /** * Log un message avec niveau DEBUG */ public function debug(string $message): void { $this->log($message, 'DEBUG'); } /** * Log une ligne de séparation */ public function separator(): void { $this->log(str_repeat('=', 80), 'INFO'); } /** * Log générique * * @param string $message Message à logger * @param string $level Niveau: INFO, SUCCESS, WARNING, ERROR, DEBUG */ private function log(string $message, string $level = 'INFO'): void { $timestamp = date('Y-m-d H:i:s'); $logLine = "[{$timestamp}] [{$level}] {$message}\n"; // Écriture dans le fichier file_put_contents($this->logFile, $logLine, FILE_APPEND); // Affichage à l'écran si verbose if ($this->verbose) { $this->printColored($message, $level); } } /** * Affiche un message coloré selon le niveau */ private function printColored(string $message, string $level): void { $colors = [ 'INFO' => "\033[0;37m", // Blanc 'SUCCESS' => "\033[0;32m", // Vert 'WARNING' => "\033[0;33m", // Jaune 'ERROR' => "\033[0;31m", // Rouge 'DEBUG' => "\033[0;36m" // Cyan ]; $reset = "\033[0m"; $color = $colors[$level] ?? $colors['INFO']; echo $color . $message . $reset . "\n"; } /** * Retourne le chemin du fichier de log */ public function getLogFile(): string { return $this->logFile; } /** * Log des statistiques de migration * * @param array $stats Tableau associatif [table => count] */ public function logStats(array $stats): void { $this->separator(); $this->info("📊 Statistiques de migration:"); foreach ($stats as $table => $count) { $this->info(" - {$table}: {$count} enregistrement(s)"); } $this->separator(); } /** * Log une ligne spéciale pour parsing automatique * Format: #STATS# KEY1:VAL1 KEY2:VAL2 ... */ public function logParsableStats(array $stats): void { $pairs = []; foreach ($stats as $key => $value) { $pairs[] = strtoupper($key) . ':' . $value; } $line = '#STATS# ' . implode(' ', $pairs); $this->log($line, 'INFO'); } /** * Affiche et log un récapitulatif complet de migration * * @param array $summary Tableau de statistiques hiérarchique */ public function logMigrationSummary(array $summary): void { $this->separator(); $this->separator(); $this->info("📊 RÉCAPITULATIF DE LA MIGRATION"); $this->separator(); // Entité if (isset($summary['entity'])) { $this->info("Entité: {$summary['entity']['name']} (ID: {$summary['entity']['id']})"); } $this->info("Date: " . date('Y-m-d H:i:s')); $this->info(""); // Nombre total d'opérations $totalOperations = count($summary['operations'] ?? []); $this->success("Opérations migrées: {$totalOperations}"); $this->info(""); // Détail par opération $operationNum = 1; foreach ($summary['operations'] ?? [] as $operation) { $this->info("Opération #{$operationNum}: \"{$operation['name']}\" (ID: {$operation['id']})"); $this->info(" ├─ Utilisateurs: {$operation['users']}"); $this->info(" ├─ Secteurs: {$operation['sectors']}"); $this->info(" ├─ Passages totaux: {$operation['total_passages']}"); if (!empty($operation['sectors_detail'])) { $this->info(" └─ Détail par secteur:"); $sectorCount = count($operation['sectors_detail']); $sectorNum = 0; foreach ($operation['sectors_detail'] as $sector) { $sectorNum++; $isLast = ($sectorNum === $sectorCount); $prefix = $isLast ? " └─" : " ├─"; $this->info("{$prefix} {$sector['name']} (ID: {$sector['id']})"); $this->info(" " . ($isLast ? " " : "│") . " ├─ Utilisateurs affectés: {$sector['users']}"); $this->info(" " . ($isLast ? " " : "│") . " └─ Passages: {$sector['passages']}"); } } $this->info(""); $operationNum++; } $this->separator(); } }