Миграции

Примечание: Миграции доступны с версии 1.1.6.

Как и исходный код, структура базы данных изменяется в процессе разработки и поддержки приложения. К примеру, во время разработки может понадобиться добавить новую таблицу или уже после размещения приложения на сервере добавить индекс или столбец. При этом важно отслеживать изменения в структуре базы данных (называемые миграциями) также, как мы делаем это для нашего исходного кода. Если исходный код и база данных не соответствуют друг другу, скорее всего, всё приложение не будет работать. Именно поэтому в Yii есть поддержка миграций, позволяющая отслеживать изменения в базе данных, применять миграции или откатывать уже применённые.

Ниже приведён пошаговый процесс использования миграций при разработке:

  1. Иван создаёт новую миграцию (например, создающую новую таблицу).
  2. Иван заливает её в систему контроля версий (SVN, GIT или другую).
  3. Андрей обновляется из системы контроля версий и получает новую миграцию.
  4. Андрей применяет миграцию к своей локальной базе данных.

В Yii управление миграциями производится через консольную команду yiic migrate, которая поддерживает создание новых миграций, применение, откат и повторное применение миграций, просмотр истории миграций и новых миграций.

Примечание: При работе с командой migrate рекомендуется использовать yiic приложения (то есть после cd path/to/protected), а не yiic из директории framework. Убедитесь, что директория protected\migrations существует и доступна для записи. Также проверьте настройки соединения с базой данных в protected/config/console.php.

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

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



Обязательный параметр name должен содержать очень краткое описание миграции (например, create_news_table). Как будет показано далее, этот параметр используется как часть имени класса миграции, поэтому использовать можно только буквы, цифры и знаки подчёркивания.



Приведённая команда создаст в директории protected/migrations файл m101129_185401_create_news_table.php, содержащий следующее:



Стоит отметить, что имя класса совпадает с именем файла и строится как m<timestamp>_<name>, где <timestamp> — это время создания миграции в UTC (в формате yymmdd_hhmmss), а <name> — то, что передано в параметре name команды.

Метод up() должен содержать код, выполняющий миграцию, а метод down() может содержать код, отменяющий сделанное в up().

Иногда реализовать down() не получается. К примеру, если в up() из таблицы удаляются данные, в down() вернуть их не получится. В этом случае миграция называется необратимой, что означает невозможность возврата к предыдущему состоянию базы данных. В приведённом выше коде метод down() возвращает false. Это означает невозможность отката миграции.

Информация: Начиная с версии 1.1.7, если метод up() или метод down() возвращают false, все последующие миграции не будут применены. В 1.1.6 для этого было необходимо выкинуть исключение.

Рассмотрим в качестве примера миграцию, создающую таблицу с новостями.



Базовый класс CDbMigration предоставляет набор методов для работы с данными и структурой базы данных. К примеру, при помощи CDbMigration::createTable можно создать новую таблицу, а CDbMigration::insert добавит строку с данными. Все эти методы используют подключение к базе данных, возвращаемое CDbMigration::getDbConnection(), что по умолчанию эквивалентно Yii::app()->db.

Информация: Как вы могли заметить, методы CDbMigration очень похожи на методы CDbCommand. И это на самом деле так. Единственно отличие состоит в том, что методы CDbMigration подсчитывают затрачиваемое на их выполнение время и выводят сообщения о параметрах методов.

Транзакционные миграции

Информация: Данная возможность поддерживается, начиная с версии 1.1.7.

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

Можно начать транзакцию явно и заключить в неё весь код, меняющий базу данных:



А можно сделать это проще, реализовав метод safeUp() вместо up() и safeDown() вместо down():



Yii при применении миграции начнёт транзакцию, а затем выполнит код в safeUp() или safeDown(). Если при этом возникнет какая-либо ошибка, произойдёт откат транзакции, то есть база вернётся в начальное состояние.

Примечание: Не все СУБД полностью поддерживают транзакции и не для всех выражений. В том случае, если поддержки транзакций нет, реализовывать надо up() и down(). В случае использования MySQL некоторые выражения SQL могут вызвать неявное применение транзакции.

Применение миграций

Для того чтобы применить все новые миграции (то есть привести локальную БД в актуальное состояние), следует запустить следующую команду:



Команда покажет список всех новых миграций и, в случае утвердительного ответа, по очереди запустит метод up() в каждом классе миграции в порядке их создания.

После применения миграции в таблицу tbl_migration будет внесена соответствующая запись. Это позволяет узнать, какие миграции уже применены, а какие нет. Если таблица tbl_migration не существует, она будет создана автоматически в базе данных, указанной в компоненте db приложения.

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



При этом применятся три новых миграции. Вместо трёх можно указать любое количество применяемых миграций.

Также можно привести состояние базы данных к определённой версии:



В качестве параметра, указывающего версию, к которой надо привести базу данных, используется часть имени файла, соответствующая времени создании миграции. Если между последней применённой и указанной миграциями несколько миграций, то все они будут применены. Если указанная миграция уже применялась, то будет произведён откат всех миграций, применённых после неё (описано в следующем разделе).

Откат миграций

Для отката одной или нескольких последних применённых миграций можно воспользоваться следующей командой:



где необязательный параметр step задаёт количество миграций, которые надо откатить. По умолчанию откатывается одна последняя применённая миграция.

Как было описано ранее, не все миграции можно откатить. При попытке отката таких миграций будет выброшено исключение и процесс отката будет прерван.

Повторное применение миграций

Повторное примение миграции производится путём последовательного отката и применения. Осуществить это можно следующей командой:



где необязательный параметр step указывает количество миграций, которые необходимо применить ещё раз. По умолчанию повторяется одна последняя миграция.

Просмотр информации о миграциях

Кроме применения и отката миграций, инструмент миграций может отображать историю миграций, а также новые, ещё не применённые миграции.



Здесь параметр limit указывает количество отображаемых миграций. Если limit не указан, показываются все миграции.

Первая команда показывает уже применённые миграции, вторая — миграции, которые ещё не были применены.

Изменение истории миграций

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



Эта команда очень похожа на yiic migrate to, но она лишь изменяет таблицу истории миграций до указанной версии без применения или отката самих миграций.

Настройка команды миграций

Есть несколько способов настроить команду миграций.

Используя параметры командной строки

Команда миграций может быть настроена четыремя опциями:

Для указания опций используется следующий формат:



К примеру, если необходимо мигрировать модуль forum, файлы миграций которого расположены в директории модуля migrations, можно воспользоваться следующей командой:



Стоит отметить, что при передаче через командную строку флагов, таких как interactive, необходимо использовать значения 1 или 0:



Глобальная конфигурация команды

В то время как опции командной строки позволяют нам на лету конфигурировать команду миграций, иногда требуется применить настройки раз и навсегда. К примеру, нам может понадобиться использовать другую таблицу для хранения истории миграций или использовать свой шаблон миграции. Это можно сделать, изменив настройки консольного приложения следующим образом:



Теперь при запуске команды migrate указанные выше настройки будут применены без ввода каких-либо дополнительных параметров.