Files
whatsapp/database/migrate.php
T
Lizandro Guarnizo 7000464d36 fix(migrate): robustecer parser SQL y no registrar migración si hubo errores
- Eliminar comentarios de bloque /* */ antes de parsear
- Limpiar líneas vacías y comentarios -- sentencia por sentencia
- Agregar 'Duplicate key name' y 'Multiple primary key defined' a errores ignorables
- Solo registrar en tabla migrations si no hubo errores reales
- Si una sentencia falla, continuar con las demás pero marcar had_error=true
2026-03-12 09:27:46 -05:00

167 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Sistema de migraciones automáticas
* Se ejecuta al iniciar el contenedor Docker
* Fecha: 3 de febrero de 2026
*/
// No mostrar errores en pantalla
error_reporting(E_ALL);
ini_set('display_errors', '0');
echo "🔍 Iniciando sistema de migraciones...\n";
// Cargar configuración
if (!file_exists(__DIR__ . '/../config/config.php')) {
echo "❌ Error: config.php no encontrado\n";
exit(1);
}
require_once __DIR__ . '/../config/config.php';
try {
$db = Database::getInstance();
echo "✅ Conexión a base de datos establecida\n";
// Crear tabla de control de migraciones si no existe
$db->execute("
CREATE TABLE IF NOT EXISTS migrations (
id INT AUTO_INCREMENT PRIMARY KEY,
filename VARCHAR(255) NOT NULL UNIQUE,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_filename (filename)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
echo "✅ Tabla de control de migraciones verificada\n";
// Obtener lista de migraciones ejecutadas
$executed = $db->fetchAll("SELECT filename FROM migrations");
$executedFiles = array_column($executed, 'filename');
// Buscar archivos .sql en database/ Y en migrations/ (carpeta raíz del proyecto)
$dbFiles = glob(__DIR__ . '/*.sql') ?: [];
$migrationsFiles = glob(__DIR__ . '/../migrations/*.sql') ?: [];
// Unir y ordenar por nombre de archivo (orden cronológico por prefijo)
$allFiles = array_unique(array_merge($dbFiles, $migrationsFiles));
usort($allFiles, fn($a, $b) => strcmp(basename($a), basename($b)));
$migrationFiles = $allFiles;
if (empty($migrationFiles)) {
echo "️ No se encontraron archivos de migración\n";
exit(0);
}
echo "📋 Encontrados " . count($migrationFiles) . " archivos de migración\n";
echo " (database/: " . count($dbFiles) . ", migrations/: " . count($migrationsFiles) . ")\n\n";
$executed_count = 0;
$skipped_count = 0;
foreach ($migrationFiles as $file) {
$filename = basename($file);
// Saltar archivo de backup completo
if (strpos($filename, 'backup') !== false) {
continue;
}
// Verificar si ya fue ejecutada
if (in_array($filename, $executedFiles)) {
echo "⏭️ Saltando $filename (ya ejecutada)\n";
$skipped_count++;
continue;
}
echo "🔄 Ejecutando migración: $filename\n";
try {
$sql = file_get_contents($file);
// Eliminar comentarios de bloque /* ... */
$sql = preg_replace('/\/\*.*?\*\//s', '', $sql);
// Dividir en sentencias por ; y limpiar
$rawStatements = explode(';', $sql);
$statements = [];
foreach ($rawStatements as $stmt) {
// Eliminar líneas de comentario -- y líneas vacías
$lines = explode("\n", $stmt);
$cleaned = [];
foreach ($lines as $line) {
$trimmed = trim($line);
if ($trimmed !== '' && strpos($trimmed, '--') !== 0) {
$cleaned[] = $line;
}
}
$stmt = trim(implode("\n", $cleaned));
if ($stmt !== '') {
$statements[] = $stmt;
}
}
$stmt_count = 0;
$had_error = false;
foreach ($statements as $stmt) {
try {
$db->execute($stmt);
$stmt_count++;
} catch (Exception $e) {
$msg = $e->getMessage();
// Ignorar errores de "ya existe" — son idempotentes
$ignorable = [
'Duplicate column',
'already exists',
'Duplicate key name',
'Multiple primary key defined',
];
$ignore = false;
foreach ($ignorable as $pattern) {
if (strpos($msg, $pattern) !== false) {
$ignore = true;
break;
}
}
if ($ignore) {
echo " ⚠ Ya existe (ignorado): " . substr($msg, 0, 80) . "\n";
continue;
}
echo " ✗ Error en sentencia: $msg\n";
$had_error = true;
// Continuar con las demás sentencias del archivo
}
}
if (!$had_error) {
// Registrar migración como ejecutada solo si no hubo errores reales
$db->execute(
"INSERT INTO migrations (filename) VALUES (?)",
[$filename]
);
echo " ✓ Ejecutadas $stmt_count sentencias SQL — registrada\n";
} else {
echo " ⚠ Migración con errores — NO registrada (se reintentará en el próximo deploy)\n";
}
$executed_count++;
} catch (Exception $e) {
echo " ✗ Error fatal en $filename: " . $e->getMessage() . "\n";
// Continuar con la siguiente migración
}
}
echo "\n";
echo "═══════════════════════════════════════════\n";
echo "✅ Migraciones completadas\n";
echo " - Ejecutadas: $executed_count\n";
echo " - Saltadas: $skipped_count\n";
echo "═══════════════════════════════════════════\n";
} catch (Exception $e) {
echo "❌ Error fatal en sistema de migraciones: " . $e->getMessage() . "\n";
exit(1);
}
exit(0);