- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD) * DEV: Clés TEST Pierre (mode test) * REC: Clés TEST Client (mode test) * PROD: Clés LIVE Client (mode live) - Ajout de la gestion des bases de données immeubles/bâtiments * Configuration buildings_database pour DEV/REC/PROD * Service BuildingService pour enrichissement des adresses - Optimisations pages et améliorations ergonomie - Mises à jour des dépendances Composer - Nettoyage des fichiers obsolètes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
220 lines
6.2 KiB
PHP
220 lines
6.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Gestion des logs de migration
|
|
*
|
|
* Écrit dans un fichier et affiche à l'écran avec timestamps
|
|
*/
|
|
class MigrationLogger
|
|
{
|
|
private $logFile;
|
|
private $verbose;
|
|
|
|
/**
|
|
* Constructeur
|
|
*
|
|
* @param string|null $logFile Chemin du fichier de log (null = auto-généré)
|
|
* @param bool $verbose Afficher les logs à l'écran
|
|
*/
|
|
public function __construct(?string $logFile = null, bool $verbose = true)
|
|
{
|
|
// Définir le répertoire de logs par défaut (migration2/logs/)
|
|
$defaultLogDir = dirname(__DIR__, 2) . '/logs';
|
|
$this->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();
|
|
}
|
|
}
|