Durante el curso de desarrollo y mantenimiento de una aplicación con base de datos, la estructura de dicha base de datos
evoluciona tanto como el código fuente. Por ejemplo, durante el desarrollo de una aplicación,
una nueva tabla podría ser necesaria; una vez que la aplicación se encuentra en producción, podría descrubrirse
que debería crearse un índice para mejorar el tiempo de ejecución de una consulta; y así sucesivamente. Debido a los cambios en la estructura de la base de datos
a menudo se requieren cambios en el código, Yii soporta la característica llamada *migración de base de datos*, la cual permite
tener un seguimiento de esos cambios en término de *migración de base de datos*, cuyo versionado es controlado
junto al del código fuente.
Los siguientes pasos muestran cómo una migración puede ser utilizada por un equipo durante el desarrollo:
1. Tim crea una nueva migración (por ej. crea una nueva table, cambia la definición de una columna, etc.).
2. Tim hace un commit con la nueva migración al sistema de control de versiones (por ej. Git, Mercurial).
3. Doug actualiza su repositorio desde el sistema de control de versiones y recibe la nueva migración.
4. Doug aplica dicha migración a su base de datos local de desarrollo, de ese modo sincronizando su base de datos
y reflejando los cambios que hizo Tim.
Los siguientes pasos muestran cómo hacer una puesta en producción con una migración de base de datos:
1. Scott crea un tag de lanzamiento en el repositorio del proyecto que contiene algunas migraciones de base de datos.
2. Scott actualiza el código fuente en el servidor de producción con el tag de lanzamiento.
3. Scott aplica cualquier migración de base de datos acumulada a la base de datos de producción.
Yii provee un grupo de herramientas de línea de comandos que te permite:
* crear nuevas migraciones;
* aplicar migraciones;
* revertir migraciones;
* re-aplicar migraciones;
* mostrar el historial y estado de migraciones.
Todas esas herramientas son accesibles a través del comando `yii migrate`. En esta sección describiremos en detalle
cómo lograr varias tareas utilizando dichas herramientas. Puedes a su vez ver el uso de cada herramienta a través del comando
de ayuda `yii help migrate`.
> Tip: las migraciones pueden no sólo afectar un esquema de base de datos sino también ajustar datos existentes para que encajen en el nuevo esquema, crear herencia RBAC
Para crear una nueva migración, ejecuta el siguiente comando:
```
yii migrate/create <name>
```
El argumento requerido `name` da una pequeña descripción de la nueva migración. Por ejemplo, si
la migración se trata acerca de crear una nueva tabla llamada *news*, podrías utilizar el nombre `create_news_table`
y ejecutar el siguiente comando:
```
yii migrate/create create_news_table
```
> Note: Debido a que el argumento `name` será utilizado como parte del nombre de clase de la migración generada,
sólo debería contener letras, dígitos, y/o guines bajos.
El comando anterior un nuevo archivo de clase PHP llamado `m150101_185401_create_news_table.php`
en el directorio `@app/migrations`. El archivo contendrá el siguiente código, que principalmente declara
una clase de tipo migración `m150101_185401_create_news_table` con el siguiente esqueleto de código:
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
}
public function down()
{
echo "m101129_185401_create_news_table cannot be reverted.\n";
return false;
}
/*
// Use safeUp/safeDown to run migration code within a transaction
public function safeUp()
{
}
public function safeDown()
{
}
*/
}
```
Cada migración de base de datos es definida como una clase PHP que extiende de [[yii\db\Migration]]. La nombre de clase
de la migración es generado automáticamente en el formato `m<YYMMDD_HHMMSS>_<Name>`, donde
*`<YYMMDD_HHMMSS>` se refiere a la marca de tiempo UTC en la cual el comando de migración fue ejecutado.
*`<Name>` es el mismo valor del argumento `name` provisto al ejecutar el comando.
En la clase de la migración, se espera que tu escribas código en el método `up()`, que realiza los cambios en la base de datos.
Podrías también querer introducir código en el método `down()`, que debería revertir los cambios realizados por `up()`. El método `up()` es llamado
cuando actualizas la base de datos con esta migración, mientras que el método `down()` es llamado cuando reviertes dicha migración.
El siguiente código muestra cómo podrías implementar la clase de migración para crear la tabla `news`:
```php
<?php
use yii\db\Schema;
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
$this->createTable('news', [
'id' => Schema::TYPE_PK,
'title' => Schema::TYPE_STRING . ' NOT NULL',
'content' => Schema::TYPE_TEXT,
]);
}
public function down()
{
$this->dropTable('news');
}
}
```
> Info: No todas las migraciones son reversibles. Por ejemplo, si el método `up()` elimina un registro en una tabla, podrías
no ser capáz de recuperarla en el método `down()`. A veces, podrías ser simplemente demasiado perezoso para implementar
el método `down()`, debido a que no es muy común revertir migraciones de base de datos. En este caso, deberías devolver
`false` en el método `down()` para indicar que dicha migración no es reversible.
La clase de migración de base de datos [[yii\db\Migration]] expone una conexión a la base de datos mediante la propiedad [[yii\db\Migration::db|db]].
Puedes utilizar esto para manipular el esquema de la base de datos utilizando métodos como se describen en
[Trabajando con Esquemas de Base de Datos](db-dao.md#working-with-database-schema-).
En vez de utilizar tipos físicos, al crear tablas o columnas deberías utilizar los *tipos abstractos*
así las migraciones son independientes de algún DBMS específico. La clase [[yii\db\Schema]] define
un grupo de constantes que representan los tipos abstractos soportados. Dichas constantes son llamadas utilizando el formato
de `TYPE_<Name>`. Por ejemplo, `TYPE_PK` se refiere al tipo clave primaria auto-incremental; `TYPE_STRING`
se refiere al tipo string. Cuando se aplica una migración a una base de datos en particular, los tipos abstractos
serán traducidos a los tipos físicos correspondientes. En el caso de MySQL, `TYPE_PK` será transformado
en `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY`, mientras `TYPE_STRING` se vuelve `varchar(255)`.
Puedes agregar restricciones adicionales al utilizar tipos abstractos. En el ejemplo anterior, ` NOT NULL` es agregado
a `Schema::TYPE_STRING` para especificar que la columna no puede ser null.
> Info: El mapeo entre tipos abstractos y tipos físicos es especificado en
la propiedad [[yii\db\QueryBuilder::$typeMap|$typeMap]] en cada clase concreta `QueryBuilder`.
Desde la versión 2.0.6, puedes hacer uso del recientemente introducido generador de esquemas, el cual provee una forma más conveniente de definir las columnas.
De esta manera, la migración anterior podría ser escrita así:
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
$this->createTable('news', [
'id' => $this->primaryKey(),
'title' => $this->string()->notNull(),
'content' => $this->text(),
]);
}
public function down()
{
$this->dropTable('news');
}
}
```
Existe una lista de todos los métodos disponibles para la definición de tipos de columna en la API de la documentación de [[yii\db\SchemaBuilderTrait]].
Con esta configuración, cada vez que ejecutes un comando de migración, la tabla `backend_migration`
será utilizada para registrar el historial de migraciones. No necesitarás volver a especificarla con la opción `migrationTable`
de la línea de comandos.
## Migrar Múltiples Bases de Datos <span id="migrating-multiple-databases"></span>
Por defecto, las migraciones son aplicadas en la misma base de datos especificada en el [componente de aplicación](structure-application-components.md) `db`.
Si quieres que sean aplicadas en una base de datos diferente, puedes especificar la opción `db` como se muestra a continuación,
```
yii migrate --db=db2
```
El comando anterior aplicará las migraciones en la base de datos `db2`.
A veces puede suceder que quieras aplicar *algunas* de las migraciones a una base de datos, mientras algunas otras
a una base de datos distinta. Para lograr esto, al implementar una clase de migración debes especificar explícitamente el ID del componente DB
que la migración debe utilizar, como a continuación:
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function init()
{
$this->db = 'db2';
parent::init();
}
}
```
La migración anterior se aplicará a `db2`, incluso si especificas una base de datos diferente en la opción `db` de la
línea de comandos. Ten en cuenta que el historial aún será registrado in la base de datos especificada en la opción `db` de la línea de comandos.
Si tienes múltiples migraciones que utilizan la misma base de datos, es recomandable que crees una clase base de migración
con el código `init()` mostrado. Entonces cada clase de migración puede extender de esa clase base.
> Tip: Aparte de definir la propiedad [[yii\db\Migration::db|db]], puedes también operar en diferentes bases de datos
creando nuevas conexiones de base de datos en tus clases de migración. También puedes utilizar [métodos DAO](db-dao.md)
con esas conexiones para manipular diferentes bases de datos.
Another strategy that you can take to migrate multiple databases is to keep migrations for different databases in
different migration paths. Then you can migrate these databases in separate commands like the following:
Otra estrategia que puedes seguir para migrar múltiples bases de datos es mantener las migraciones para diferentes bases de datos en
distintas rutas de migración. Entonces podrías migrar esas bases de datos en comandos separados como a continuación: