Phinx es una librería de migraciones de base de datos para PHP que funciona de forma independiente a cualquier framework. Con ella defines los cambios de esquema en clases PHP versionadas, y puedes aplicarlos o revertirlos en cualquier momento.
Instalación
composer require robmorgan/phinx
Configuración
Crea phinx.php en la raíz del proyecto:
<?php
return [
'paths' => [
'migrations' => '%%PHINX_CONFIG_DIR%%/db/migrations',
'seeds' => '%%PHINX_CONFIG_DIR%%/db/seeds',
],
'environments' => [
'default_migration_table' => 'phinxlog',
'default_environment' => 'development',
'development' => [
'adapter' => 'mysql',
'host' => 'localhost',
'name' => 'mi_proyecto',
'user' => 'root',
'pass' => 'secret',
'charset' => 'utf8mb4',
],
'production' => [
'adapter' => 'mysql',
'host' => getenv('DB_HOST'),
'name' => getenv('DB_NAME'),
'user' => getenv('DB_USER'),
'pass' => getenv('DB_PASS'),
'charset' => 'utf8mb4',
],
],
'version_order' => 'creation',
];
?>
Crear una migración
vendor/bin/phinx create CrearTablaProductos
Se genera un fichero como db/migrations/20240601120000_crear_tabla_productos.php:
<?php
use PhinxMigrationAbstractMigration;
class CrearTablaProductos extends AbstractMigration
{
public function change(): void
{
$tabla = $this->table('productos');
$tabla
->addColumn('nombre', 'string', ['limit' => 200])
->addColumn('precio', 'decimal', ['precision' => 10, 'scale' => 2])
->addColumn('stock', 'integer', ['default' => 0])
->addColumn('categoria_id', 'integer')
->addColumn('created_at', 'datetime', ['null' => true])
->addColumn('updated_at', 'datetime', ['null' => true])
->create();
}
}
?>
El método change() es reversible: Phinx sabe cómo deshacer la creación de tabla automáticamente.
Añadir índices únicos y claves foráneas
<?php
class AnadirIndicesProductos extends AbstractMigration
{
public function change(): void
{
$tabla = $this->table('productos');
// Índice único en nombre
$tabla->addIndex(['nombre'], ['unique' => true, 'name' => 'ux_productos_nombre']);
// Clave foránea a categorias
$tabla->addForeignKey(
'categoria_id',
'categorias',
'id',
['delete' => 'CASCADE', 'update' => 'NO_ACTION']
);
$tabla->update();
}
}
?>
Ejecutar y revertir migraciones
# Aplica todas las migraciones pendientes vendor/bin/phinx migrate # Aplica solo hasta una versión específica vendor/bin/phinx migrate -t 20240601120000 # Revertir la última migración vendor/bin/phinx rollback # Revertir hasta un punto vendor/bin/phinx rollback -t 20240601120000 # Ver el estado de las migraciones vendor/bin/phinx status
Migraciones con up() y down() explícitos
Cuando el cambio no es automáticamente reversible (por ejemplo, modificar datos), usa up() y down() por separado:
<?php
class NormalizarEmailsUsuarios extends AbstractMigration
{
public function up(): void
{
$this->execute("UPDATE usuarios SET email = LOWER(email)");
}
public function down(): void
{
// No se puede deshacer una normalización de datos
// Dejamos vacío o lanzamos excepción
$this->output->writeln('Rollback no aplicable para esta migración.');
}
}
?>
Seeds: poblar la base de datos
vendor/bin/phinx seed:create ProductosSeeder
<?php
use PhinxSeedAbstractSeed;
class ProductosSeeder extends AbstractSeed
{
public function run(): void
{
$datos = [
['nombre' => 'Teclado', 'precio' => 49.99, 'stock' => 10, 'categoria_id' => 1],
['nombre' => 'Ratón', 'precio' => 29.99, 'stock' => 25, 'categoria_id' => 1],
['nombre' => 'Monitor', 'precio' => 299.00,'stock' => 5, 'categoria_id' => 2],
];
$this->table('productos')->insert($datos)->saveData();
}
}
?>
# Ejecutar todos los seeds vendor/bin/phinx seed:run # Ejecutar un seed específico vendor/bin/phinx seed:run -s ProductosSeeder
Integración con entornos de producción
# Apuntar a producción vendor/bin/phinx migrate -e production
Errores comunes
- change() con operaciones no reversibles: si añades
dropColumn()dentro dechange(), el rollback fallará. Usaup()/down()explícitos. - Claves foráneas sin índice previo: MySQL requiere que la columna referenciada tenga un índice. Phinx crea el índice automáticamente, pero si la tabla referenciada no existe todavía, ordena bien las migraciones.
- Fichero phinxlog corrupto: si truncas la tabla
phinxloga mano, Phinx perderá el rastro de qué migraciones están aplicadas. Nunca la toques directamente.
