Migraciones
¿Qué hace internamente?
El comando:
Obtiene el SchemaManager de Doctrine
Ejecuta cada método createXTable()
Verifica si la tabla existe
La crea solo si no existe
$schemaManager = $this->connection->createSchemaManager();
📋 Tablas que se crean 1️⃣ Tabla anidada
Define la configuración de tablas anidadas / subgrillas.
Uso típico:
CRUDs con relaciones padre → hijo
Configuración visual y funcional de subtablas
Campos clave:
nivel_db
tabla_db
consulta_crear_tabla
activate_nested_table_db
2️⃣ Tabla menu
Define los menús principales del sistema.
Campos importantes:
nombre_menu
url_menu
icono_menu
orden_menu
3️⃣ Tabla submenu
Define los submenús asociados a un menú.
Relación lógica:
submenu.id_menu → menu.id_menu
Campos clave:
nombre_submenu
url_submenu
orden_submenu
4️⃣ Tabla usuario
Tabla principal de usuarios del sistema.
Incluye:
Autenticación
Roles
Avatares
Tokens
Índices importantes:
email (único)
usuario (único)
5️⃣ Tabla usuario_menu
Controla qué menús ve cada usuario.
Campos:
id_usuario
id_menu
visibilidad_menu
Usada para:
Permisos
Menús dinámicos
6️⃣ Tabla usuario_submenu
Controla submenús visibles por usuario.
Permite:
Seguridad granular
Ocultar subopciones
7️⃣ Tabla modulos
⚠️ Tabla central del framework
Define completamente el comportamiento de cada CRUD.
Incluye configuración para:
Queries
Formularios
Grillas
Filtros
Búsqueda
Recaptcha
PDFs
Callbacks
Relaciones (INNER / LEFT JOIN)
👉 Esta tabla permite un CRUD declarativo sin código.
🔒 Seguridad del sistema
Las migraciones no borran datos
No alteran tablas existentes
Evitan colisiones por nombres duplicados
🛠️ Cómo crear nuevas tablas (migraciones personalizadas)
El sistema de migraciones está diseñado para que cada tabla se cree mediante un método dedicado, manteniendo el código claro, mantenible e idempotente.
A continuación se explica paso a paso cómo crear una nueva tabla dentro de este sistema.
1️⃣ Crear un método por tabla
Cada tabla debe tener su propio método privado dentro del comando:
private function createProductosTable($schemaManager, OutputInterface $output): void
🔹 El nombre debe comenzar con create y terminar con Table por convención.
2️⃣ Definir el nombre de la tabla
Dentro del método, define el nombre de la tabla:
$tableName = 'productos';
Verificar si la tabla ya existe
Esto evita errores y hace que la migración sea segura de ejecutar múltiples veces:
if (in_array($tableName, $schemaManager->listTableNames())) {
$output->writeln("ℹ La tabla <comment>$tableName</comment> ya existe.");
return;
}
✔ Esta es la clave para que la migración sea idempotente.
4️⃣ Crear la instancia de la tabla
Usa Doctrine DBAL para definir la estructura:
$table = new Table($tableName);
5️⃣ Agregar columnas
Cada columna se define con addColumn:
$table->addColumn('id', 'integer', [
'autoincrement' => true,
'unsigned' => true
]);
$table->addColumn('nombre', 'string', ['length' => 150]);
$table->addColumn('precio', 'decimal', ['precision' => 10, 'scale' => 2]);
$table->addColumn('activo', 'boolean', ['notnull' => false]);
Tipos comunes:
integer
string
text
boolean
decimal
date, datetime
6️⃣ Definir la clave primaria
Toda tabla debe tener una primary key:
$table->setPrimaryKey(['id']);
7️⃣ Agregar índices (opcional pero recomendado)
$table->addUniqueIndex(['nombre'], 'uniq_productos_nombre');
$table->addIndex(['activo'], 'idx_productos_activo');
8️⃣ Crear la tabla físicamente
Finalmente, se ejecuta la creación:
$schemaManager->createTable($table);
$output->writeln("✔ Tabla <info>$tableName</info> creada.");
9️⃣ Manejar errores
Envuelve todo en un bloque try/catch:
try {
// definición de la tabla
} catch (SchemaException $e) {
$output->writeln("<error>Error en $tableName: {$e->getMessage()}</error>");
}
🔟 Registrar la migración
Para que la tabla se cree, debes llamar el método desde execute():
$this->createProductosTable($schemaManager, $output);
Si no se llama aquí, la migración no se ejecutará.
🧪 Ejemplo completo
private function createProductosTable($schemaManager, OutputInterface $output): void
{
$tableName = 'productos';
try {
if (in_array($tableName, $schemaManager->listTableNames())) {
$output->writeln("ℹ La tabla <comment>$tableName</comment> ya existe.");
return;
}
$table = new Table($tableName);
$table->addColumn('id', 'integer', [
'autoincrement' => true,
'unsigned' => true
]);
$table->addColumn('nombre', 'string', ['length' => 150]);
$table->addColumn('precio', 'decimal', ['precision' => 10, 'scale' => 2]);
$table->addColumn('activo', 'boolean', ['notnull' => false]);
$table->setPrimaryKey(['id']);
$schemaManager->createTable($table);
$output->writeln("✔ Tabla <info>$tableName</info> creada.");
} catch (SchemaException $e) {
$output->writeln("<error>Error en $tableName: {$e->getMessage()}</error>");
}
}
▶️ Cómo ejecutar las migraciones
Desde la raíz del proyecto ejecuta:
php arco database:migrate
Salida esperada
Creando tabla anidada...
✔ Tabla anidada creada.
ℹ La tabla menu ya existe.
✔ Migraciones completadas.