mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 02:28:35 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			940 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			940 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Migración de Base de Datos
 | |
| ==========================
 | |
| 
 | |
| 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
 | |
|   o también limpiar el cache.
 | |
| 
 | |
| 
 | |
| ## Creando Migraciones <span id="creating-migrations"></span>
 | |
| 
 | |
| 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#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]].
 | |
| 
 | |
| 
 | |
| ## Generar Migraciones <span id="generating-migrations"></span>
 | |
| 
 | |
| Desde la versión 2.0.7 la consola provee una manera muy conveniente de generar migraciones.
 | |
| 
 | |
| Si el nombre de la migración tiene una forma especial, por ejemplo `create_xxx_table` o `drop_xxx_table` entonces el archivo de la migración generada
 | |
| contendrá código extra, en este caso para crear/eliminar tablas.
 | |
| A continuación se describen todas estas variantes.
 | |
| 
 | |
| ### Crear Tabla
 | |
| 
 | |
| ```php
 | |
| yii migrate/create create_post_table
 | |
| ```
 | |
| 
 | |
| esto genera
 | |
| 
 | |
| ```php
 | |
| /**
 | |
|  * Handles the creation for table `post`.
 | |
|  */
 | |
| class m150811_220037_create_post_table extends Migration
 | |
| {
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function up()
 | |
|     {
 | |
|         $this->createTable('post', [
 | |
|             'id' => $this->primaryKey()
 | |
|         ]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function down()
 | |
|     {
 | |
|         $this->dropTable('post');
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| Para crear las columnas en ese momento, las puedes especificar vía la opción `--fields`.
 | |
| 
 | |
| ```php
 | |
| yii migrate/create create_post_table --fields="title:string,body:text"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| /**
 | |
|  * Handles the creation for table `post`.
 | |
|  */
 | |
| class m150811_220037_create_post_table extends Migration
 | |
| {
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function up()
 | |
|     {
 | |
|         $this->createTable('post', [
 | |
|             'id' => $this->primaryKey(),
 | |
|             'title' => $this->string(),
 | |
|             'body' => $this->text(),
 | |
|         ]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function down()
 | |
|     {
 | |
|         $this->dropTable('post');
 | |
|     }
 | |
| }
 | |
| 
 | |
| ```
 | |
| 
 | |
| Puedes especificar más parámetros para las columnas.
 | |
| 
 | |
| ```php
 | |
| yii migrate/create create_post_table --fields="title:string(12):notNull:unique,body:text"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| /**
 | |
|  * Handles the creation for table `post`.
 | |
|  */
 | |
| class m150811_220037_create_post_table extends Migration
 | |
| {
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function up()
 | |
|     {
 | |
|         $this->createTable('post', [
 | |
|             'id' => $this->primaryKey(),
 | |
|             'title' => $this->string(12)->notNull()->unique(),
 | |
|             'body' => $this->text()
 | |
|         ]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function down()
 | |
|     {
 | |
|         $this->dropTable('post');
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| > Note: la clave primaria es automáticamente agragada y llamada `id` por defecto. Si quieres utilizar otro nombre puedes
 | |
| > especificarlo así `--fields="name:primaryKey"`.
 | |
| 
 | |
| #### Claves Foráneas
 | |
| 
 | |
| Desde 2.0.8 el generador soporta claves foráneas utilizando la palabra clave `foreignKey`.
 | |
| 
 | |
| ```php
 | |
| yii migrate/create create_post_table --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| /**
 | |
|  * Handles the creation for table `post`.
 | |
|  * Has foreign keys to the tables:
 | |
|  *
 | |
|  * - `user`
 | |
|  * - `category`
 | |
|  */
 | |
| class m160328_040430_create_post_table extends Migration
 | |
| {
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function up()
 | |
|     {
 | |
|         $this->createTable('post', [
 | |
|             'id' => $this->primaryKey(),
 | |
|             'author_id' => $this->integer()->notNull(),
 | |
|             'category_id' => $this->integer()->defaultValue(1),
 | |
|             'title' => $this->string(),
 | |
|             'body' => $this->text(),
 | |
|         ]);
 | |
| 
 | |
|         // creates index for column `author_id`
 | |
|         $this->createIndex(
 | |
|             'idx-post-author_id',
 | |
|             'post',
 | |
|             'author_id'
 | |
|         );
 | |
| 
 | |
|         // add foreign key for table `user`
 | |
|         $this->addForeignKey(
 | |
|             'fk-post-author_id',
 | |
|             'post',
 | |
|             'author_id',
 | |
|             'user',
 | |
|             'id',
 | |
|             'CASCADE'
 | |
|         );
 | |
| 
 | |
|         // creates index for column `category_id`
 | |
|         $this->createIndex(
 | |
|             'idx-post-category_id',
 | |
|             'post',
 | |
|             'category_id'
 | |
|         );
 | |
| 
 | |
|         // add foreign key for table `category`
 | |
|         $this->addForeignKey(
 | |
|             'fk-post-category_id',
 | |
|             'post',
 | |
|             'category_id',
 | |
|             'category',
 | |
|             'id',
 | |
|             'CASCADE'
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function down()
 | |
|     {
 | |
|         // drops foreign key for table `user`
 | |
|         $this->dropForeignKey(
 | |
|             'fk-post-author_id',
 | |
|             'post'
 | |
|         );
 | |
| 
 | |
|         // drops index for column `author_id`
 | |
|         $this->dropIndex(
 | |
|             'idx-post-author_id',
 | |
|             'post'
 | |
|         );
 | |
| 
 | |
|         // drops foreign key for table `category`
 | |
|         $this->dropForeignKey(
 | |
|             'fk-post-category_id',
 | |
|             'post'
 | |
|         );
 | |
| 
 | |
|         // drops index for column `category_id`
 | |
|         $this->dropIndex(
 | |
|             'idx-post-category_id',
 | |
|             'post'
 | |
|         );
 | |
| 
 | |
|         $this->dropTable('post');
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| La posición de la palabra clave `foreignKey` en la descripción de la columna
 | |
| no cambia el código generado. Esto significa:
 | |
| 
 | |
| - `author_id:integer:notNull:foreignKey(user)`
 | |
| - `author_id:integer:foreignKey(user):notNull`
 | |
| - `author_id:foreignKey(user):integer:notNull`
 | |
| 
 | |
| Todas generan el mismo código.
 | |
| 
 | |
| La palabra clave `foreignKey` puede tomar un parámetro entre paréntesis el cual
 | |
| será el nombre de la tabla relacionada por la clave foránea generada. Si no se pasa ningún parámetro
 | |
| el nombre de la tabla será deducido en base al nombre de la columna.
 | |
| 
 | |
| En el ejemplo anterior `author_id:integer:notNull:foreignKey(user)` generará
 | |
| una columna llamada `author_id` con una clave foránea a la tabla `user` mientras
 | |
| `category_id:integer:defaultValue(1):foreignKey` generará
 | |
| `category_id` con una clave foránea a la tabla `category`.
 | |
| 
 | |
| ### Eliminar Tabla
 | |
| 
 | |
| ```php
 | |
| yii migrate/create drop_post_table --fields="title:string(12):notNull:unique,body:text"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| class m150811_220037_drop_post_table extends Migration
 | |
| {
 | |
|     public function up()
 | |
|     {
 | |
|         $this->dropTable('post');
 | |
|     }
 | |
| 
 | |
|     public function down()
 | |
|     {
 | |
|         $this->createTable('post', [
 | |
|             'id' => $this->primaryKey(),
 | |
|             'title' => $this->string(12)->notNull()->unique(),
 | |
|             'body' => $this->text()
 | |
|         ]);
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Agregar Columna
 | |
| 
 | |
| Si el nombre de la migración está en la forma `add_xxx_column_to_yyy_table` entonces el archivo generado contendrá
 | |
| las declaraciones `addColumn` y `dropColumn` necesarias.
 | |
| 
 | |
| Para agregar una columna:
 | |
| 
 | |
| ```php
 | |
| yii migrate/create add_position_column_to_post_table --fields="position:integer"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| class m150811_220037_add_position_column_to_post_table extends Migration
 | |
| {
 | |
|     public function up()
 | |
|     {
 | |
|         $this->addColumn('post', 'position', $this->integer());
 | |
|     }
 | |
| 
 | |
|     public function down()
 | |
|     {
 | |
|         $this->dropColumn('post', 'position');
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Eliminar Columna
 | |
| 
 | |
| Si el nombre de la migración está en la forma `drop_xxx_column_from_yyy_table` entonces el archivo generado contendrá
 | |
| las declaraciones `addColumn` y `dropColumn` necesarias.
 | |
| 
 | |
| ```php
 | |
| yii migrate/create drop_position_column_from_post_table --fields="position:integer"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| class m150811_220037_drop_position_column_from_post_table extends Migration
 | |
| {
 | |
|     public function up()
 | |
|     {
 | |
|         $this->dropColumn('post', 'position');
 | |
|     }
 | |
| 
 | |
|     public function down()
 | |
|     {
 | |
|         $this->addColumn('post', 'position', $this->integer());
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Agregar Tabla de Unión
 | |
| 
 | |
| Si el nombre de la migración está en la forma `create_junction_table_for_xxx_and_yyy_tables` entonces se generará el código necesario
 | |
| para una tabla de unión.
 | |
| 
 | |
| ```php
 | |
| yii migrate/create create_junction_table_for_post_and_tag_tables --fields="created_at:dateTime"
 | |
| ```
 | |
| 
 | |
| genera
 | |
| 
 | |
| ```php
 | |
| /**
 | |
|  * Handles the creation for table `post_tag`.
 | |
|  * Has foreign keys to the tables:
 | |
|  *
 | |
|  * - `post`
 | |
|  * - `tag`
 | |
|  */
 | |
| class m160328_041642_create_junction_table_for_post_and_tag_tables extends Migration
 | |
| {
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function up()
 | |
|     {
 | |
|         $this->createTable('post_tag', [
 | |
|             'post_id' => $this->integer(),
 | |
|             'tag_id' => $this->integer(),
 | |
|             'created_at' => $this->dateTime(),
 | |
|             'PRIMARY KEY(post_id, tag_id)',
 | |
|         ]);
 | |
| 
 | |
|         // creates index for column `post_id`
 | |
|         $this->createIndex(
 | |
|             'idx-post_tag-post_id',
 | |
|             'post_tag',
 | |
|             'post_id'
 | |
|         );
 | |
| 
 | |
|         // add foreign key for table `post`
 | |
|         $this->addForeignKey(
 | |
|             'fk-post_tag-post_id',
 | |
|             'post_tag',
 | |
|             'post_id',
 | |
|             'post',
 | |
|             'id',
 | |
|             'CASCADE'
 | |
|         );
 | |
| 
 | |
|         // creates index for column `tag_id`
 | |
|         $this->createIndex(
 | |
|             'idx-post_tag-tag_id',
 | |
|             'post_tag',
 | |
|             'tag_id'
 | |
|         );
 | |
| 
 | |
|         // add foreign key for table `tag`
 | |
|         $this->addForeignKey(
 | |
|             'fk-post_tag-tag_id',
 | |
|             'post_tag',
 | |
|             'tag_id',
 | |
|             'tag',
 | |
|             'id',
 | |
|             'CASCADE'
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * {@inheritdoc}
 | |
|      */
 | |
|     public function down()
 | |
|     {
 | |
|         // drops foreign key for table `post`
 | |
|         $this->dropForeignKey(
 | |
|             'fk-post_tag-post_id',
 | |
|             'post_tag'
 | |
|         );
 | |
| 
 | |
|         // drops index for column `post_id`
 | |
|         $this->dropIndex(
 | |
|             'idx-post_tag-post_id',
 | |
|             'post_tag'
 | |
|         );
 | |
| 
 | |
|         // drops foreign key for table `tag`
 | |
|         $this->dropForeignKey(
 | |
|             'fk-post_tag-tag_id',
 | |
|             'post_tag'
 | |
|         );
 | |
| 
 | |
|         // drops index for column `tag_id`
 | |
|         $this->dropIndex(
 | |
|             'idx-post_tag-tag_id',
 | |
|             'post_tag'
 | |
|         );
 | |
| 
 | |
|         $this->dropTable('post_tag');
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Migraciones Transaccionales <span id="transactional-migrations"></span>
 | |
| 
 | |
| Al ejecutar migraciones complejas de BD, es importante asegurarse que todas las migraciones funcionen o fallen como una unidad
 | |
| así la base de datos puede mantener integridad y consistencia. Para alcanzar este objetivo, se recomienda que
 | |
| encierres las operación de la BD de cada migración en una [transacción](db-dao.md#performing-transactions).
 | |
| 
 | |
| Una manera simple de implementar migraciones transaccionales es poniendo el código de las migraciones en los métodos `safeUp()` y `safeDown()`.
 | |
| Estos métodos se diferencias con `up()` y `down()` en que son encerrados implícitamente en una transacción.
 | |
| Como resultado, si alguna de las operaciones dentro de estos métodos falla, todas las operaciones previas son automáticamente revertidas.
 | |
| 
 | |
| En el siguiente ejemplo, además de crear la tabla `news` también insertamos un registro inicial dentro de la dicha tabla.
 | |
| 
 | |
| ```php
 | |
| <?php
 | |
| 
 | |
| use yii\db\Migration;
 | |
| 
 | |
| class m150101_185401_create_news_table extends Migration
 | |
| {
 | |
|     public function safeUp()
 | |
|     {
 | |
|         $this->createTable('news', [
 | |
|             'id' => $this->primaryKey(),
 | |
|             'title' => $this->string()->notNull(),
 | |
|             'content' => $this->text(),
 | |
|         ]);
 | |
| 
 | |
|         $this->insert('news', [
 | |
|             'title' => 'test 1',
 | |
|             'content' => 'content 1',
 | |
|         ]);
 | |
|     }
 | |
| 
 | |
|     public function safeDown()
 | |
|     {
 | |
|         $this->delete('news', ['id' => 1]);
 | |
|         $this->dropTable('news');
 | |
|     }
 | |
| }
 | |
| ```
 | |
| 
 | |
| Ten en cuenta que usualmente cuando ejecutas múltiples operaciones en la BD en `safeUp()`, deberías revertir su orden de ejecución
 | |
| en `safeDown()`. En el ejemplo anterior primero creamos la tabla y luego insertamos la finla en `safeUp()`; mientras
 | |
| que en `safeDown()` primero eliminamos el registro y posteriormente eliminamos la tabla.
 | |
| 
 | |
| > Note: No todos los DBMS soportan transacciones. Y algunas consultas a la BD no pueden ser puestas en transacciones. Para algunos ejemplos,
 | |
|   por favor lee acerca de [commits implícitos](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html). En estos casos,
 | |
|   deberías igualmente implementar `up()` y `down()`.
 | |
| 
 | |
| 
 | |
| ### Métodos de Acceso a la Base de Datos <span id="db-accessing-methods"></span>
 | |
| 
 | |
| La clase base [[yii\db\Migration]] provee un grupo de métodos que te permiten acceder y manipular bases de datos.
 | |
| Podrías encontrar que estos métodos son nombrados de forma similar a los [métodos DAO](db-dao.md) provistos por la clase [[yii\db\Command]].
 | |
| Por ejemplo, el método [[yii\db\Migration::createTable()]] te permite crear una nueva tabla,
 | |
| tal como lo hace [[yii\db\Command::createTable()]].
 | |
| 
 | |
| El beneficio de utilizar lo métodos provistos por [[yii\db\Migration]] es que no necesitas explícitamente
 | |
| crear instancias de [[yii\db\Command]], y la ejecución de cada método mostrará automáticamente mensajes útiles
 | |
| diciéndote qué operaciones de la base de datos se realizaron y cuánto tiempo tomaron.
 | |
| 
 | |
| Debajo hay una lista de todos los métodos de acceso a la base de datos:
 | |
| 
 | |
| * [[yii\db\Migration::execute()|execute()]]: ejecuta una declaración SQL
 | |
| * [[yii\db\Migration::insert()|insert()]]: inserta un único registro
 | |
| * [[yii\db\Migration::batchInsert()|batchInsert()]]: inserta múltiples registros
 | |
| * [[yii\db\Migration::update()|update()]]: actualiza registros
 | |
| * [[yii\db\Migration::delete()|delete()]]: elimina registros
 | |
| * [[yii\db\Migration::createTable()|createTable()]]: crea una nueva tabla
 | |
| * [[yii\db\Migration::renameTable()|renameTable()]]: renombra una tabla
 | |
| * [[yii\db\Migration::dropTable()|dropTable()]]: elimina una tabla
 | |
| * [[yii\db\Migration::truncateTable()|truncateTable()]]: elimina todos los registros de una tabla
 | |
| * [[yii\db\Migration::addColumn()|addColumn()]]: agrega una columna
 | |
| * [[yii\db\Migration::renameColumn()|renameColumn()]]: renombra una columna
 | |
| * [[yii\db\Migration::dropColumn()|dropColumn()]]: elimina una columna
 | |
| * [[yii\db\Migration::alterColumn()|alterColumn()]]: modifica una columna
 | |
| * [[yii\db\Migration::addPrimaryKey()|addPrimaryKey()]]: agrega una clave primaria
 | |
| * [[yii\db\Migration::dropPrimaryKey()|dropPrimaryKey()]]: elimina una clave primaria
 | |
| * [[yii\db\Migration::addForeignKey()|addForeignKey()]]: agrega una clave foránea
 | |
| * [[yii\db\Migration::dropForeignKey()|dropForeignKey()]]: elimina una clave foránea
 | |
| * [[yii\db\Migration::createIndex()|createIndex()]]: crea un índice
 | |
| * [[yii\db\Migration::dropIndex()|dropIndex()]]: elimina un índice
 | |
| * [[yii\db\Migration::addCommentOnColumn()|addCommentOnColumn()]]: agrega un comentario a una columna
 | |
| * [[yii\db\Migration::dropCommentFromColumn()|dropCommentFromColumn()]]: elimina un comentario de una columna
 | |
| * [[yii\db\Migration::addCommentOnTable()|addCommentOnTable()]]: agrega un comentario a una tabla
 | |
| * [[yii\db\Migration::dropCommentFromTable()|dropCommentFromTable()]]: elimina un comentario de una tabla
 | |
| 
 | |
| > Info: [[yii\db\Migration]] no provee un método de consulta a la base de datos. Esto es porque normalmente no necesitas
 | |
|   mostrar mensajes detallados al traer datos de una base de datos. También se debe a que puedes utilizar el poderoso
 | |
|   [Query Builder](db-query-builder.md) para generar y ejecutar consultas complejas.
 | |
| 
 | |
| > Note: Al manipular datos utilizando una migración podrías encontrar que utilizando tus clases [Active Record](db-active-record.md)
 | |
| > para esto podría ser útil ya que algo de la lógica ya está implementada ahí. Ten en cuenta de todos modos, que en contraste con
 | |
| > el código escrito en las migraciones, cuya naturaleza es permanecer constante por siempre, la lógica de la aplicación está sujeta a cambios.
 | |
| > Entonces al utilizar Active Record en migraciones, los cambios en la lógica en la capa Active Record podrían accidentalmente romper
 | |
| > migraciones existentes. Por esta razón, el código de las migraciones debería permanecer independiente de determinada lógica de la aplicación
 | |
| > tal como clases Active Record.
 | |
| 
 | |
| 
 | |
| ## Aplicar Migraciones <span id="applying-migrations"></span>
 | |
| 
 | |
| To upgrade a database to its latest structure, you should apply all available new migrations using the following command:
 | |
| Para actualizar una base de datos a su última estructura, deberías aplicar todas las nuevas migraciones utilizando el siguiente comando:
 | |
| 
 | |
| ```
 | |
| yii migrate
 | |
| ```
 | |
| 
 | |
| Este comando listará todas las migraciones que no han sido aplicadas hasta el momento. Si confirmas que quieres aplicar
 | |
| dichas migraciones, se correrá el método `up()` o `safeUp()` en cada clase de migración nueva, una tras otra,
 | |
| en el orden de su valor de marca temporal. Si alguna de las migraciones falla, el comando terminará su ejecución sin aplicar
 | |
| el resto de las migraciones.
 | |
| 
 | |
| > Tip: En caso de no disponer de la línea de comandos en el servidor, podrías intentar utilizar
 | |
| > la extensión [web shell](https://github.com/samdark/yii2-webshell).
 | |
| 
 | |
| Por cada migración aplicada correctamente, el comando insertará un registro en la base de datos, en la tabla llamada
 | |
| `migration` para registrar la correcta aplicación de la migración. Esto permitirá a la herramienta de migración identificar
 | |
| cuáles migraciones han sido aplicadas y cuáles no.
 | |
| 
 | |
| > Info: La herramienta de migración creará automáticamente la tabla  `migration` en la base de datos especificada
 | |
|   en la opción [[yii\console\controllers\MigrateController::db|db]] del comando. Por defecto, la base de datos
 | |
|   es especificada en el [componente de aplicación](structure-application-components.md) `db`.
 | |
| 
 | |
| A veces, podrías sólo querer aplicar una o algunas pocas migraciones, en vez de todas las migraciones disponibles.
 | |
| Puedes hacer esto el número de migraciones que quieres aplicar al ejecutar el comando.
 | |
| Por ejemplo, el siguiente comando intentará aplicar las tres siguientes migraciones disponibles:
 | |
| 
 | |
| ```
 | |
| yii migrate 3
 | |
| ```
 | |
| 
 | |
| Puedes además explícitamente especificar una migración en particular a la cual la base de datos debería migrar
 | |
| utilizando el comando `migrate/to` de acuerdo a uno de los siguientes formatos:
 | |
| 
 | |
| ```
 | |
| yii migrate/to 150101_185401                      # utiliza la marca temporal para especificar la migración
 | |
| yii migrate/to "2015-01-01 18:54:01"              # utiliza un string que puede ser analizado por strtotime()
 | |
| yii migrate/to m150101_185401_create_news_table   # utiliza el nombre completo
 | |
| yii migrate/to 1392853618                         # utiliza el tiempo UNIX
 | |
| ```
 | |
| 
 | |
| Si hubiera migraciones previas a la especificada sin aplicar, estas serán aplicadas antes de que la migración especificada
 | |
| sea aplicada.
 | |
| 
 | |
| Si la migración especificada ha sido aplicada previamente, cualquier migración aplicada posteriormente será revertida.
 | |
| 
 | |
| 
 | |
| ## Revertir Migraciones <span id="reverting-migrations"></span>
 | |
| 
 | |
| Para revertir (deshacer) una o varias migraciones ya aplicadas, puedes ejecutar el siguiente comando:
 | |
| 
 | |
| ```
 | |
| yii migrate/down     # revierte la más reciente migración aplicada
 | |
| yii migrate/down 3   # revierte las 3 últimas migraciones aplicadas
 | |
| ```
 | |
| 
 | |
| > Note: No todas las migraciones son reversibles. Intentar revertir tales migraciones producirá un error y detendrá
 | |
|   completamente el proceso de reversión.
 | |
| 
 | |
| 
 | |
| ## Rehacer Migraciones <span id="redoing-migrations"></span>
 | |
| 
 | |
| Rehacer (re-ejecutar) migraciones significa primero revertir las migraciones especificadas y luego aplicarlas nuevamente. Esto puede hacerse
 | |
| de esta manera:
 | |
| 
 | |
| ```
 | |
| yii migrate/redo        # rehace la más reciente migración aplicada
 | |
| yii migrate/redo 3      # rehace las 3 últimas migraciones aplicadas
 | |
| ```
 | |
| 
 | |
| > Note: Si una migración no es reversible, no tendrás posibilidades de rehacerla.
 | |
| 
 | |
| 
 | |
| ## Listar Migraciones <span id="listing-migrations"></span>
 | |
| 
 | |
| Para listar cuáles migraciones han sido aplicadas y cuáles no, puedes utilizar los siguientes comandos:
 | |
| 
 | |
| ```
 | |
| yii migrate/history     # muestra las últimas 10 migraciones aplicadas
 | |
| yii migrate/history 5   # muestra las últimas 5 migraciones aplicadas
 | |
| yii migrate/history all # muestra todas las migraciones aplicadas
 | |
| 
 | |
| yii migrate/new         # muestra las primeras 10 nuevas migraciones
 | |
| yii migrate/new 5       # muestra las primeras 5 nuevas migraciones
 | |
| yii migrate/new all     # muestra todas las nuevas migraciones
 | |
| ```
 | |
| 
 | |
| 
 | |
| ## Modificar el Historial de Migraciones <span id="modifying-migration-history"></span>
 | |
| 
 | |
| En vez de aplicar o revertir migraciones, a veces simplemente quieres marcar que tu base de datos
 | |
| ha sido actualizada a una migración en particular. Esto sucede normalmente cuando cambias manualmente la base de datos
 | |
| a un estado particular y no quieres que la/s migración/es de ese cambio sean re-aplicadas posteriormente. Puedes alcanzar este objetivo
 | |
| con el siguiente comando:
 | |
| 
 | |
| ```
 | |
| yii migrate/mark 150101_185401                      # utiliza la marca temporal para especificar la migración
 | |
| yii migrate/mark "2015-01-01 18:54:01"              # utiliza un string que puede ser analizado por strtotime()
 | |
| yii migrate/mark m150101_185401_create_news_table   # utiliza el nombre completo
 | |
| yii migrate/mark 1392853618                         # utiliza el tiempo UNIX
 | |
| ```
 | |
| 
 | |
| El comando modificará la tabla `migration` agregando o eliminado ciertos registros para indicar que en la base de datos
 | |
| han sido aplicadas las migraciones hasta la especificada. Ninguna migración será aplicada ni revertida por este comando.
 | |
| 
 | |
| 
 | |
| ## Personalizar Migraciones <span id="customizing-migrations"></span>
 | |
| 
 | |
| Hay varias maneras de personalizar el comando de migración.
 | |
| 
 | |
| 
 | |
| ### Utilizar Opciones de la Línea de Comandos <span id="using-command-line-options"></span>
 | |
| 
 | |
| El comando de migración trae algunas opciones de línea de comandos que pueden ser utilizadas para personalizar su comportamiento:
 | |
| 
 | |
| * `interactive`: boolean (por defecto `true`), especificar si se debe ejecutar la migración en modo interactivo.
 | |
|   Cuando se indica `true`, se le pedirá confirmación al usuario antes de ejecutar ciertas acciones.
 | |
|   Puedes querer definirlo como `false` si el comando está siendo utilizado como un proceso de fondo.
 | |
| 
 | |
| * `migrationPath`: string (por defecto `@app/migrations`), especifica el directorio que contiene todos los archivos
 | |
|   de clase de las migraciones. Este puede ser especificado tanto como una ruta a un directorio un [alias](concept-aliases.md) de ruta.
 | |
|   Ten en cuenta que el directorio debe existir, o el comando disparará un error.
 | |
| 
 | |
| * `migrationTable`: string (por defecto `migration`), especifica el nombre de la tabla de la base de datos que almacena
 | |
|   información del historial de migraciones. Dicha tabla será creada por el comando en caso de que no exista.
 | |
|   Puedes también crearla manualmente utilizando la estructura `version varchar(255) primary key, apply_time integer`.
 | |
| 
 | |
| * `db`: string (por defecto `db`), especifica el ID del [componente de aplicación](structure-application-components.md) de la base de datos.
 | |
|   Esto representa la base de datos que será migrada en este comando.
 | |
| 
 | |
| * `templateFile`: string (por defecto `@yii/views/migration.php`), especifica la ruta al template
 | |
|   utilizado para generar el esqueleto de los archivos de clases de migración. Puede ser especificado tanto como una ruta a un archivo
 | |
|   como una [alias](concept-aliases.md) de una ruta. El template es un archivo PHP en el cual puedes utilizar una variable predefinida
 | |
|   llamada `$className` para obtener el nombre de clase de la migración.
 | |
| 
 | |
| * `generatorTemplateFiles`: array (por defecto `[
 | |
|         'create_table' => '@yii/views/createTableMigration.php',
 | |
|         'drop_table' => '@yii/views/dropTableMigration.php',
 | |
|         'add_column' => '@yii/views/addColumnMigration.php',
 | |
|         'drop_column' => '@yii/views/dropColumnMigration.php',
 | |
|         'create_junction' => '@yii/views/createTableMigration.php'
 | |
|   ]`), especifica los templates utilizados para generar las migraciones. Ver "[Generar Migraciones](#generating-migrations)"
 | |
|   para más detalles.
 | |
| 
 | |
| * `fields`: array de strings de definiciones de columna utilizado por el código de migración. Por defecto `[]`. El formato de cada
 | |
|   definición es `COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR`. Por ejemplo, `--fields=name:string(12):notNull` produce
 | |
|   una columna string de tamaño 12 que es not `null`.
 | |
| 
 | |
| El siguiente ejemplo muestra cómo se pueden utilizar estas opciones.
 | |
| 
 | |
| Por ejemplo, si queremos migrar un módulo `forum` cuyos arhivos de migración
 | |
| están ubicados dentro del directorio `migrations` del módulo, podemos utilizar el siguientedocs/guide-es/db-migrations.md
 | |
| comando:
 | |
| 
 | |
| ```
 | |
| # realiza las migraciones de un módulo forum sin interacción del usuario
 | |
| yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0
 | |
| ```
 | |
| 
 | |
| 
 | |
| ### Configurar el Comando Globalmente <span id="configuring-command-globally"></span>
 | |
| 
 | |
| En vez de introducir los valores de las opciones cada vez que ejecutas un comandod e migración, podrías configurarlos
 | |
| de una vez por todas en la configuración de la aplicación como se muestra a continuación:
 | |
| 
 | |
| ```php
 | |
| return [
 | |
|     'controllerMap' => [
 | |
|         'migrate' => [
 | |
|             'class' => 'yii\console\controllers\MigrateController',
 | |
|             'migrationTable' => 'backend_migration',
 | |
|         ],
 | |
|     ],
 | |
| ];
 | |
| ```
 | |
| 
 | |
| 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:
 | |
| 
 | |
| ```
 | |
| yii migrate --migrationPath=@app/migrations/db1 --db=db1
 | |
| yii migrate --migrationPath=@app/migrations/db2 --db=db2
 | |
| ...
 | |
| ```
 | |
| 
 | |
| El primer comando aplicará las migraciones que se encuentran en `@app/migrations/db1` en la base de datos `db1`, el segundo comando
 | |
| aplicará las migraciones que se encuentran en `@app/migrations/db2` en `db2`, y así sucesivamente.
 | 
