¿Qué son las Migraciones?
Las migraciones son archivos PHP que describen cambios en el esquema de base de datos. Permiten versionar tu base de datos de forma similar a como Git versiona tu código.
💡 Ventajas de las Migraciones
• Control de versiones del esquema de BD
• Despliegues consistentes entre entornos
• Rollback en caso de problemas
• Historial completo de cambios
Regla de Oro: Doble Trabajo
En Perfex CRM, cada cambio de base de datos requiere actualizar DOS archivos:
- Migración en
migrations/XXX_version_XXX.php - install.php - El estado consolidado de todas las migraciones
⚠️ ¿Por qué doble trabajo?
El install.php se ejecuta en instalaciones nuevas (no hay migraciones previas). Las migraciones se ejecutan en actualizaciones (ya existe la BD). Si solo actualizas uno, tendrás inconsistencias.
Estructura de una Migración
Las migraciones deben seguir el patrón de nomenclatura y extender App_module_migration:
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
* Migración: Añadir tabla de auditoría
* Versión: 2.3.5
* Fecha: 2025-12-18
*/
class Migration_Version_235 extends App_module_migration
{
/**
* Ejecutar migración (actualización)
*/
public function up()
{
$CI = &get_instance();
// Verificar si la tabla NO existe antes de crear
if (!$CI->db->table_exists(db_prefix() . 'mi_modulo_audit')) {
$CI->db->query("
CREATE TABLE `" . db_prefix() . "mi_modulo_audit` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`action` VARCHAR(50) NOT NULL,
`entity_type` VARCHAR(50) NOT NULL,
`entity_id` INT(11) NOT NULL,
`staff_id` INT(11) NOT NULL,
`old_value` TEXT,
`new_value` TEXT,
`datecreated` DATETIME NOT NULL,
PRIMARY KEY (`id`),
INDEX `idx_entity` (`entity_type`, `entity_id`),
INDEX `idx_staff` (`staff_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
}
// Añadir columna a tabla existente
if (!$CI->db->field_exists('last_audit_date', db_prefix() . 'mi_modulo_items')) {
$CI->db->query("
ALTER TABLE `" . db_prefix() . "mi_modulo_items`
ADD COLUMN `last_audit_date` DATETIME NULL AFTER `datecreated`;
");
}
}
/**
* Revertir migración (rollback)
*/
public function down()
{
$CI = &get_instance();
// Eliminar tabla
if ($CI->db->table_exists(db_prefix() . 'mi_modulo_audit')) {
$CI->db->query('DROP TABLE `' . db_prefix() . 'mi_modulo_audit`');
}
// Eliminar columna
if ($CI->db->field_exists('last_audit_date', db_prefix() . 'mi_modulo_items')) {
$CI->db->query("
ALTER TABLE `" . db_prefix() . "mi_modulo_items`
DROP COLUMN `last_audit_date`;
");
}
}
}
Paso a Paso: Crear una Migración
1Crear el archivo de migración
El nombre debe seguir el patrón: {version}_version_{version}.php
# Ejemplo: versión 2.3.5
modules/mi_modulo/migrations/235_version_235.php
2Actualizar install.php
Añade los mismos cambios de esquema al archivo de instalación:
// install.php - Añadir al final
// v2.3.5 - Tabla de auditoría
if (!$CI->db->table_exists(db_prefix() . 'mi_modulo_audit')) {
$CI->db->query("
CREATE TABLE `" . db_prefix() . "mi_modulo_audit` (
...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
}
3Actualizar versión del módulo
En mi_modulo.php, actualiza en DOS lugares:
// Línea ~11 (comentario header)
/*
* Version: 2.3.5 ← ACTUALIZAR
*/
// Línea ~20 (constante)
define('MI_MODULO_VERSION', '2.3.5'); // ← ACTUALIZAR
4Actualizar CHANGELOG.md
## [2.3.5] - 2025-12-18
### Añadido
- Nueva tabla de auditoría para tracking de cambios
- Campo `last_audit_date` en items
Verificación de Migraciones
Perfex almacena la versión actual de cada módulo en tblmodules:
# Verificar versión actual del módulo
mysql -u root mi_base_de_datos -e "
SELECT module_name, installed_version
FROM tblmodules
WHERE module_name = 'mi_modulo';
"
🚨 Error Común: Versión no actualizada
Si la migración no se ejecuta, verifica que installed_version en tblmodules sea menor que la nueva versión. Perfex solo ejecuta migraciones con número mayor al instalado.
Operaciones Comunes
Añadir columna
if (!$CI->db->field_exists('nueva_columna', db_prefix() . 'tabla')) {
$CI->db->query("
ALTER TABLE `" . db_prefix() . "tabla`
ADD COLUMN `nueva_columna` VARCHAR(255) NULL DEFAULT NULL;
");
}
Modificar columna
$CI->db->query("
ALTER TABLE `" . db_prefix() . "tabla`
MODIFY COLUMN `columna` TEXT NOT NULL;
");
Añadir índice
// Verificar si el índice no existe
$index = $CI->db->query("
SHOW INDEX FROM `" . db_prefix() . "tabla`
WHERE Key_name = 'idx_columna'
")->row();
if (!$index) {
$CI->db->query("
CREATE INDEX `idx_columna` ON `" . db_prefix() . "tabla` (`columna`);
");
}
Checklist de Migraciones
✅ Antes de hacer commit
□ ¿Creé la migración con el nombre correcto?
□ ¿Actualicé install.php con los mismos cambios?
□ ¿Actualicé la versión en mi_modulo.php (2 lugares)?
□ ¿Actualicé CHANGELOG.md?
□ ¿Usé db_prefix() en todas las queries?
□ ¿Verifiqué existencia antes de crear/modificar?