A free and open-source book on ZF3 for beginners


13.3. Создание миграций

Миграция - это набор изменений, либо обновляющий схему, либо возвращающий ее к предыдущему состоянию. Пустая миграция генерируется следующими командами:

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

Эти команды назначают каталог приложения текущим рабочим каталогом и затем выполняют консольную команду migrations:generate.

DoctrineModule и DoctrineORMModule предоставляют несколько консольных команд, которые можно использовать для различных задач, связанных с поддержкой базы данных (например, генерации или выполнения миграций). Список доступных команд можно посмотреть с помощью команды list:

./vendor/bin/doctrine-module list

После запуска команды migrations:generate созданную миграцию можно будет найти под каталогом APP_DIR/data/Migrations. Имя файла миграции имеет вид VersionYYYYMMDDHHIISS.php, где YYYY - текущий год, MM - текущий месяц, DD - текущий день, а HH, II и SS - соответственно текущие час, минута и секунда.

Если вы откроете созданный файл, то увидите следующее содержимое:

<?php

namespace Migrations;

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

/**
 * Автоматически сгенерированная миграция: измените под ваши нужды!
 */
class Version20160901114333 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // эта миграция up() сгенерирована автоматически, пожалуйста, измените ее под свои нужды

    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // эта миграция down() сгенерирована автоматически, пожалуйста, измените ее под свои нужды

    }
}

Если вы не видите созданную миграцию в NetBeans, откройте меню Source и выберите пункт меню Scan for external changes.

Как видите из фрагмента кода выше, миграция - это обычный PHP-класс, наследуемый от базового класса Doctrine\DBAL\Migrations\AbstractMigration. У каждой миграции должно быть по крайней мере два метода: up() and down(). Метод up() обновляет схему до нового состояния, а метод down() возвращает к предыдущему. Оба этих метода принимают один аргумент типа Doctrine\DBAL\Schema\Schema, который можно использовать для фактического изменения схемы базы данных.

Класс Schema является частью компонента Doctrine\DBAL. За дополнительной информацией о предоставляемых им методах обратитесь к документации DBAL. Либо, что даже лучше, посмотрите на код внутри каталога vendor/doctrine/dbal.

Класс миграции может иметь следующие (переопределенные) методы (таблица 13.1):

Таблица 13.1. Методы, которые может содержать класс миграции
Метод Описание
isTransactional() Если эта функция возвращает true (по умолчанию), вся миграция будет выполнена как одна транзакция; иначе, каждый из SQL-запросов миграции будет выполнен отдельно.
getDescription() Этот метод должен возвращать строку, описывающую миграцию (с какой целью сделано это изменение схемы)
preUp(Schema $schema) Этот метод будет выполнен перед обновлением схемы.
postUp(Schema $schema) Этот метод будет выполнен после обновления схемы.
preDown(Schema $schema) Этот метод будет выполнен перед возвратом схемы к предыдущему состоянию.
postDown(Schema $schema) Этот метод будет выполнен после возврата схемы к предыдущему состоянию.

Базовый класс AbstractMigration также предоставляет следующие полезные методы (таблица 13.2):

Table 13.2. Methods provided by the base migration class
Метод Описание
addSql($sql, array $params = [], array $types = []) Этот метод позволяет выполнить произвольный SQL-запрос.
write($message) Этот метод помощника выводит сообщение (поясняющее или об отладке) на экран.
throwIrreversibleMigrationException($message = null) Этот метод помощника, как правило, вызывается внутри метода down(), чтобы сообщить, что миграцию нельзя отменить.

Как видите из таблицы 13.2, вы также можете изменить схему, вызвав метод addSql(). Этот метод можно использовать для создания таблицы, ее обновления или удаления. Кроме того, его можно использовать, например, для вставки каких-либо данных в таблицы (однако, вставка данных не является изменением схемы).

Миграции Doctrine предназначены для изменений схемы, а не для добавления данных в базу. Впрочем, вставка начальных данных в некоторых случаях весьма полезна.

Теперь, когда вы знаете, как создать миграцию, давайте создадим пару миграций для нашего приложения Blog.

13.3.1. Создание начальной миграции

Начальная миграция будет первой, которую мы создадим. Она будет применена к схеме пустой базы данных и создаст четыре таблицы: post, comment, tag и post_tag.

Измените созданный нами в предыдущем разделе класс миграции, чтобы он выглядел, как показано ниже:

<?php

namespace Migrations;

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

/**
 * Класс миграции. Он либо обновляет схему БД (приводит к новому состоянию), либо
 * возвращает ее к предыдущему состоянию.
 */
class Version20160901114333 extends AbstractMigration
{
    /**
     * Возвращает описание этой миграции.
     */
    public function getDescription()
    {
        $description = 'This is the initial migration which creates blog tables.';
        return $description;
    }
    
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // Создаем таблицу 'post'
        $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');
        
        // Создаем таблицу 'comment'
        $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');
        
        // Создаем таблицу 'tag'
        $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');
        
        // Создаем таблицу 'post_tag'
        $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');
    }
}

Во фрагменте кода выше находятся три метода:

13.3.2. Добавление еще одной миграции

Теперь, предположим, мы решили повысить производительность нашей базы данных, добавив к таблицам индексы.

Если вы хотите более детально узнать о индексах баз данных и о том, почему они так полезны, можете обратиться к отличному руководству Use the Index, Luke.

Кроме того, мы можем повысить целостность данных, добавив внешние ключи. Для этого нужно добавить еще одну миграцию. Сгенерируйте пустую миграцию с помощью консольной команды migrations:generate. Измените код следующим образом:

<?php

namespace Migrations;

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

/**
 * Класс миграции. Он либо обновляет схему БД (приводит к новому состоянию), либо
 * возвращает ее к предыдущему состоянию.
 */
class Version20160901114938 extends AbstractMigration
{
    /**
     * Возвращает описание этой миграции.
     */
    public function getDescription()
    {
        $description = 'This migration adds indexes and foreign key constraints.';
        return $description;
    }
    
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // Добавляем индекс к таблице post
        $table = $schema->getTable('post');
        $table->addIndex(['date_created'], 'date_created_index');
        
        // Добавляем индекс и внешний ключ к таблице comment
        $table = $schema->getTable('comment');
        $table->addIndex(['post_id'], 'post_id_index');
        $table->addForeignKeyConstraint('post', ['post_id'], ['id'], [], 'comment_post_id_fk');
        
        // Добавляем индексы и внешние ключи к таблице 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');       
    }
}

Созданные нами миграции вы можете найти в примере Blog, который идет вместе с этой книгой.


Top