A free and open-source book on ZF3 for beginners

Translation into this language is not yet finished. You can help this project by translating the chapters and contributing your changes.

13.3. Crear Migraciones

Una migración es un conjunto de cambios que actualizan o deshacen la actualización en el esquema a su próximo o anterior estado respectivamente. Podemos generar una migración nueva y vacía con la ayuda del siguiente comando:

cd APP_DIR
./vendor/bin/doctrine-module migrations:generate

Los comandos de arriba nos mueven hasta el directorio de la aplicación estableciéndolo como el directorio de trabajo y luego ejecuta el comando de consola migrations:generate.

DoctrineModule y DoctrineORMModule proveen varios comandos de consola que podemos usar para varias de las tareas de mantenimiento de la base de datos (como generar y ejecutar migraciones). Para ver una lista completa de los comandos disponibles podemos usar el comando list:

./vendor/bin/doctrine-module list

Una vez que ejecutemos el comando migrations:generate seremos capaces de encontrar la migración creada recientemente dentro de la carpeta APP_DIR/data/Migrations. El archivo tiene un nombre como VersionYYYYMMDDHHIISS.php, donde YYYY es el año, MM es el mes, DD es el día, HH, II y SS` representan respectivamente la hora, los minutos y los segundos del momento de creación.

Si vemos el contenido del archivo creado recientemente encontraremos el siguiente contenido:

<?php

namespace Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20160901114333 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs

    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs

    }
}

Si no vemos la migración recién creada en el IDE NetBeans necesitaremos abrir el menú Source y hacer clic en el elemento del menú llamado Scan for external changes.

Como podemos ver en el código de arriba una migración es una clase PHP normal que hereda de la clase base Doctrine\DBAL\Migrations\AbstractMigration. Cada migración deber tener al menos dos métodos: up() y down(). El método up() actualiza el esquema al nuevo estado y el método down() regresa el esquema a su estado anterior. Ambos métodos up() y down() reciben solo un argumento de tipo Doctrine\DBAL\Schema\Schema que se pueden usar para las modificaciones del esquema de base de datos actual.

La clase Schema es parte del componente Doctrine\DBAL. Para más información sobre los métodos que ella provee podemos revisar la documentación de Doctrine DBAL. Otra manera, que es incluso mejor, es revisar el código fuente que está dentro del directorio vendor/doctrine/dbal.

Una clase de migración puede tener opcionalmente los siguientes métodos (sobrecargados) (tabla 13.1):

Tabla 13.1. Métodos que una clase de migración puede tener
Método Descripción
isTransactional() Si la función regresa true (defecto) la migración se ejecutará en una transacción de lo contrario un estado no transaccional se usará para ejecutar cada una de las sentencias SQL de la migración.
getDescription() Este método debería regresar una cadena de caracteres que describe la migración (el propósito del cambio en el esquema)
preUp(Schema $schema) Este método se ejecutará antes de actualizar el esquema.
postUp(Schema $schema) Este método se ejecutará después de actualizar el esquema.
preDown(Schema $schema) Este método se ejecutará antes de deshacer una migración en el esquema.
postDown(Schema $schema) Este método se ejecutará después de deshacer una migración en el esquema.

Además, la clase base AbstractMigration provee los siguientes métodos útiles (tabla 13.2):

Tabla 13.2. Métodos provistos por la clase base `AbstractMigration`
Método Descripción
addSql($sql, array $params = [], array $types = []) Este método permite ejecutar una
                                                    | sentencia SQL arbitraria.              |
write($message) Este método de ayuda imprime un mensaje en la pantalla (un mensaje de detección de fallas o explicativo).
throwIrreversibleMigrationException($message = null) Este método de ayuda se usa generalmente dentro del método down() para señalar que la migración no se puede deshacer.

Como se ve en la tabla 13.2 se puede modificar el esquema llamando al método addSql(). Este método se puede usar para crear una tabla, actualizar una tabla o remover una tabla. Además, se puede usar para insertar algunos datos en la tabla, aunque, insertar datos no es un cambio en el esquema.

Las migraciones de Doctrine se diseñaron para cambios en el esquema no para insertar datos en la base de datos. Sin embargo, insertar algunos datos iniciales es la base de datos es en ocasiones útil.

Ahora que sabemos como crear migraciones vamos a crear un par de ellas para nuestro Blog de ejemplo.

13.3.1. Crear la Primera Migración

La primera migración que crearemos es la migración inicial. Esta migración se aplicará al esquema de base de datos vacío y creara las tablas: post, comment, tag and post_tag.

Modificamos la clase de migración que hemos creado en la sección anterior para que se vea como se muestra a continuación:

Modify the migration class we have created in the following section to look like below:

<?php

namespace Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;

/**
 * A migration class. It either upgrades the databases schema (moves it to new state)
 * or downgrades it to the previous state.
 */
class Version20160901114333 extends AbstractMigration
{
    /**
     * Returns the description of this migration.
     */
    public function getDescription()
    {
        $description = 'This is the initial migration which creates blog tables.';
        return $description;
    }

    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // Create 'post' table
        $table = $schema->createTable('post');
        $table->addColumn('id', 'integer', ['autoincrement'=>true]);
        $table->addColumn('title', 'text', ['notnull'=>true]);
        $table->addColumn('content', 'text', ['notnull'=>true]);
        $table->addColumn('status', 'integer', ['notnull'=>true]);
        $table->addColumn('date_created', 'datetime', ['notnull'=>true]);
        $table->setPrimaryKey(['id']);
        $table->addOption('engine' , 'InnoDB');

        // Create 'comment' table
        $table = $schema->createTable('comment');
        $table->addColumn('id', 'integer', ['autoincrement'=>true]);
        $table->addColumn('post_id', 'integer', ['notnull'=>true]);
        $table->addColumn('content', 'text', ['notnull'=>true]);
        $table->addColumn('author', 'string', ['notnull'=>true, 'lenght'=>128]);
        $table->addColumn('date_created', 'datetime', ['notnull'=>true]);
        $table->setPrimaryKey(['id']);
        $table->addOption('engine' , 'InnoDB');

        // Create 'tag' table
        $table = $schema->createTable('tag');
        $table->addColumn('id', 'integer', ['autoincrement'=>true]);
        $table->addColumn('name', 'string', ['notnull'=>true, 'lenght'=>128]);
        $table->setPrimaryKey(['id']);
        $table->addOption('engine' , 'InnoDB');

        // Create 'post_tag' table
        $table = $schema->createTable('post_tag');
        $table->addColumn('id', 'integer', ['autoincrement'=>true]);
        $table->addColumn('post_id', 'integer', ['notnull'=>true]);
        $table->addColumn('tag_id', 'integer', ['notnull'=>true]);
        $table->setPrimaryKey(['id']);
        $table->addOption('engine' , 'InnoDB');
    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        $schema->dropTable('post_tag');
        $schema->dropTable('tag');
        $schema->dropTable('comment');
        $schema->dropTable('post');
    }
}

En el código de arriba tenemos tres métodos:

13.3.2. Agregar otra Migración

Ahora supongamos que deseamos mejorar el rendimiento de nuestra base de datos agregando indices a nuestras tablas.

Si queremos aprender sobre índices de base de datos con mayor profundidad y por que los son tan útiles, revisa este excelente tutorial El uso de los Indices, Luke.

Podemos mejorar la integridad de los datos agregando llaves foráneas. Para hacer esto tenemos que agregar otra migración. Generamos otra migración con el comando de consola migrations:generate y modificamos el código hasta que quede de la siguiente manera:

<?php

namespace Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;

/**
 * A migration class. It either upgrades the databases schema (moves it to new state)
 * or downgrades it to the previous state.
 */
class Version20160901114938 extends AbstractMigration
{
    /**
     * Returns the description of this migration.
     */
    public function getDescription()
    {
        $description = 'This migration adds indexes and foreign key constraints.';
        return $description;
    }

    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // Add index to post table
        $table = $schema->getTable('post');
        $table->addIndex(['date_created'], 'date_created_index');

        // Add index and foreign key to comment table
        $table = $schema->getTable('comment');
        $table->addIndex(['post_id'], 'post_id_index');
        $table->addForeignKeyConstraint('post', ['post_id'], ['id'], [], 'comment_post_id_fk');

        // Add indexes and foreign keys to post_tag table
        $table = $schema->getTable('post_tag');
        $table->addIndex(['post_id'], 'post_id_index');
        $table->addIndex(['tag_id'], 'tag_id_index');
        $table->addForeignKeyConstraint('post', ['post_id'], ['id'], [], 'post_tag_post_id_fk');
        $table->addForeignKeyConstraint('tag', ['tag_id'], ['id'], [], 'post_tag_tag_id_fk');
    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        $table = $schema->getTable('post_tag');
        $table->removeForeignKey('post_tag_post_id_fk');
        $table->removeForeignKey('post_tag_tag_id_fk');
        $table->dropIndex('post_id_index');
        $table->dropIndex('tag_id_index');

        $table = $schema->getTable('comment');
        $table->dropIndex('post_id_index');
        $table->removeForeignKey('comment_post_id_fk');

        $table = $schema->getTable('post');
        $table->dropIndex('date_created_index');
    }
}

Podemos encontrar las migraciones que hemos creado en el ejemplo Blog que acompaña a este libro.


Top