Что такое миграции и зачем они нужны?
Если Вы уже знаете, что такое миграции и зачем они нужны, но не знаете как с ними работать, то переходите к инструкции. Если у Вас еще нет представления о миграциях, то перед инструкцией почитайте пару абзацев.
Давайте представим, что над проектом работает 3 программиста. Каждый из них делает свою часть работы в процессе меняя и дописывая код, выгружает его в систему контроля версий. В процессе изменения исходного кода приложения меняется и структура базы данных. Добавляются новые таблицы и поля, лишнее удаляется и т.д.. Для того что бы отследить изменения в структуре БД, программисты договорились складывать все SQL запросы изменения БД в файл, имеющий имя текущей даты, в одну папку. Теперь у всех при пуле есть последняя версия исходного кода и список файлов с изменениями структуры БД. Перед продолжением работы, что бы не было ошибок, программисту необходимо выполнить все запросы из новых файлов и только после этого продолжить работу. Тим лид (он же главный) при деплое проекта не только будет копировать файлы на боевой сервер, но и импортировать все запросы по изменению структуры БД. Не слишком удобно, правда? Таких подходов с отслеживанием структуры БД есть много вариаций, я описал один из возможных.
Отслеживание изменения структуры базы данных и есть миграции. Каждая миграция - это новая версия БД. Т.е. в нашем случае миграция - обновление структуры базы данных от одной версии к другой.
В Yii реализована поддержка миграций, позволяющая применять изменения в структуре и отменять их.Управление миграциями в Yii осуществляется с помощью консольной команды yiic migrate. Она отвечает за создание, применение, откат, повторное применение и просмотр истории миграций.
Для начала необходимо проверить настройки соединения с
базой данных в файле protected/config/console.php.
<?php
//...
'db' => array(
'connectionString' => 'mysql:host=localhost;dbname=main',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'enableProfiling' => true,
),
//...
Проверьте существование директории protected/migrations и доступна ли она для записи.
Открываем консоль (для Windows Win + R и введите cmd).
Далее переходим в папку проекта
(к примеру: D:/web/home/site.local/www) в директорию protected:
d: cd /web/home/site.local/www/protected
Создаем миграцию
yiic migrate create [migrate_name]
[migrate_name] - это обязательный параметр,
который должен содержать краткое описание миграции
(например, create_comments_table). Этот параметр будет использоваться как часть
имени класса миграции (в имени можно использовать буквы, цифры и нижнее
подчеркивание).
Пример создания миграции, для новой таблицы комментариев:
yiic migrate create create_comments_table
При выполнении этой команды будет создан файл:
m150108_091710_create_comments_table.php в папке
protected/migrations, который будет содержать следующий код:
<?php
class m150108_091710_create_comments_table extends CDbMigration
{
public function up()
{
}
public function down()
{
echo "m150108_091710_create_comments_table does not support migration down.\n";
return false;
}
/*
// Используйте safeUp/safeDown для использования транзакций
public function safeUp()
{
}
public function safeDown()
{
}
*/
}
Имя файла и класса строится по шаблону: m[timestamp]_[migrate_name], где [timestamp] - это время создания миграции в формате yymmdd_hhmmss, а [migrate_name] - это имя указанное в параметре команды.
Рассмотрим методы класса подробнее:
Метод up() должен содержать код, который выполняет миграцию (добавление таблиц, полей, переименование таблиц, полей и т.д.).
Метод down() может содержать код, который будет выполнять
отмену команд, выполненную в методе up()
(откат структуры БД к предыдущей версии). Случается так,
что реализовать откат в методе down() нельзя. Например при удалении данных из
таблицы, вернуть их нет возможности.
В таких случаях миграция считается необратимой, т.е. невозможно вернуть
БД к предыдущему состоянию. В генерируемом Yii примере, метод down()
возвращает false, т.е. откат миграции невозможен.
up() или метод down() возвращают false,
все последующие миграции не будут применены.
В версии 1.1.6 для отмены последующих миграций необходимо выдать исключение.
Для примера рассмотрим создание таблицы комментариев.
<?php
class m150108_091710_create_comments_table extends CDbMigration {
public function up() {
$this->createTable('comments', array(
'id' => 'pk',
'name' => 'string NOT NULL',
'text' => 'text',
));
}
public function down() {
$this->dropTable('comments');
}
}
Список команд для работы с миграциями можете посмотреть здесь:
http://www.yiiframework.com/doc/api/1.1/CDbMigration
Если у Вас возникают сложности при написание запросов с помощью: createTable,
addColumn, dropColumn, dropTable, renameColumn, renameTable и т.д.. Можете использовать
прямые SQL запросы Yii::app()->db->createCommand. Пример:
<?php
class m150108_091710_create_comments_table extends CDbMigration {
public function up() {
$sql = "CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`text` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;";
Yii::app()->db->createCommand($sql)->execute();
}
public function down() {
$sql = "DROP TABLE comments";
Yii::app()->db->createCommand($sql)->execute();
}
}
Применение миграций
yiic migrate
Данная команда выводит список всех новых миграций и вопрос применить ли миграции:
Yii Migration Tool v1.0 (based on Yii v1.1.15)
Creating migration history table "comments" ...done/
Total 1 new migrations to be applied:
m150108_091710_create_news_table
Apply the above migrations& (yes:no) [no]:
При положительном ответе, команда запустит по очереди метод
up() в каждом из классов миграции в порядке их создания
(в данном случае это 1 миграция).
После выполнения команды миграции будет создана таблица
tbl_migration, если она еще не создана
(таблица будет находиться в основной БД указанной в конфигурации db).
В эту таблицу будет внесена запись, которая позволяет узнать, какие миграции
уже применены, а какие нет.
Бывают ситуации в которых необходимо применить одну или несколько новых миграций. Для этого нужно использовать команду:
yiic migrate up [count]
Эта команда выполнит [count] новых миграции. [count] - любое количество применяемых миграций.
Если Вам необходимо привести БД в определенное состояние (версию), то можно использовать следующую команду:
yiic migrate to [version]
[version] - версия к которой необходимо привести базу данных, здесь используется часть имени файла, которая соответствует времени создания миграции (например: 101129_185401). Если указанная миграция уже применена, то будет произведён откат до этой миграции.
Транзакции в миграции
Для сложных миграций с использованием транзакций можно использовать встроенный механизм транзакции явно:
<?php
class m150108_091710_create_comments_table extends CDbMigration
{
public function up()
{
$transaction=$this->getDbConnection()->beginTransaction();
try
{
$this->createTable('comments', array(
'id' => 'pk',
'name' => 'string NOT NULL',
'text' => 'text',
));
$transaction->commit();
}
catch(Exception $e)
{
echo "Exception: ".$e->getMessage()."\n";
$transaction->rollback();
return false;
}
}
//...
}
Или использовать механизм встроенный в миграции.
Для этого вместо метода up() нужно использовать
safeUp() и вместо метода down() используйте safeDown():
<?php
class m150108_091710_create_comments_table extends CDbMigration {
public function safeUp() {
$this->createTable('comments', array(
'id' => 'pk',
'name' => 'string NOT NULL',
'text' => 'text',
));
}
public function safeDown() {
$this->dropTable('comments');
}
}
При выполнении миграции, Yii начнёт транзакцию и выполнит метод safeUp()
или метод safeDown(). Если произойдет ошибка,
сработает откат транзакции и БД вернется к состоянию до начала миграции.
Отмена миграций
Если Вам необходимо отменить миграцию или несколько последних миграций, то можно воспользоваться следующей командой:
yiic migrate down [step]
[step] - необязательный параметр, который задает количество
отменяемых миграций. Если параметр не указан, то отменяется одна
последняя миграция.
Если миграцию невозможно откатить, то будет отдано исключение и откат будет прерван.
Повторное применение миграций
Если во время выполнения миграции возникли какие-то проблемы, можно повторно применить миграцию. Это делается с помощью следующей команды:
yiic migrate redo [step]
[step] - необязательный параметр, который задает количество
миграций, которые необходимо применить еще раз.
Если параметр не указан, то повторно применяется одна последняя миграция.
Просмотр информации о миграциях
Для просмотра истории миграций которые уже применены или еще не применены, есть следующие команды:
yiic migrate history [limit] yiic migrate new [limit]
[limit] - количество отображаемых миграций.
Если этот параметр не указан, то будут показаны все миграции.
history - покажет примененные миграции.
new — список новых миграций, которые еще не применены.
Изменение истории миграций
Если Вам требуется применить миграцию без откатов или применений других миграций, то можно воспользоваться следующей командой:
yiic migrate mark [version]
Команда mark похожа на to, с тем отличием,
что mark изменит таблицу tbl_migration
до указанной версии без применения или отката миграций.
Все, теперь Вы можете попрактиковаться в применении миграций в Yii Framework и существенно облегчить отслеживание изменений структуры базы данных при работе в команде. Удачи!
console.php в зависимости от места запуска читайте здесь:кодер.укр/записи/yii_framework_настройка_конфигурации_console_php_для_локальной_разработки_и_для_сервера
devreadwrite.com



Подборка адаптивных шаблонов для вашей CMS
Статьи по
Как получить и установить HTTPS сертификат на сайта

Комментарии
Спасибо за статью!
ОтветитьУ меня есть вопрос. Я сделал 2 варианта настроек console.php и в зависимости от места запуска подключается один из них. На компьютере все отлично работает, но когда заливаю все на сервер и пробую выполнить команду на сервере yiic migrate, то выводит ошибку:
-bash: yiic: command not found
В чем может быть проблема?
Попробуйте написать так:
Ответитьphp yiic migrate
Теперь пишет:
Ответитьexception 'CDbException' with message 'CDbConnection failed to open the DB connection: SQLSTATE[28000] [1045] Access denied for user .......
Все разобрался, после использования php yiic migrate, все заработало. Вторая ошибка была из-за неправильно настроенного подключения к базе в console.php для сервера. Еще раз спасибо!
ОтветитьПодскажите пожалуйста, что не так. У меня выдает ошибку при выполнении команды yiic migrate create test:
Ответить"php" не является внутренней или внешней командой, исполняемой программой или пакетный файлом.
Скорее всего у Вас не добавлен PHP в переменные среды. Как это сделать можете посмотреть здесь:
Ответитькодер.укр/записи/windows_и_denwer_добавление_php_в_переменные_среды
я делал так: Z:/usr/local/php5/php.exe yiic migrate create new_table_from_test
ОтветитьОбъяснилте мне пожалуйста, ninja писал о двух файлах конфигурации console.php для пк и для сервера. Я не понял как это реализовать? Или при загрузке кода на сервер нужно менять настройки в console.php для сервера? Но это как то неудобно.
ОтветитьНе учел этот момент в статье. В комментарии много писать, поэтому написал отдельную статью:) Читайте здесь:
Ответитькодер.укр/записи/yii_framework_настройка_конфигурации_console_php_для_локальной_разработки_и_для_сервера
Отлично, все работает! Спасибо за статью.
ОтветитьОтличное дополнение, мне тоже пригодилось
ОтветитьХорошая статья, без лишней воды, все по теме. А главное все работает без шаманства и поиска по другим сайтам, спасибо, добавил в закладки
ОтветитьА можно использовать в миграциях модели? Наподобие:
Ответить$model = new News();
$model->name = '...';
...
$model->save();
Так можно?
Да, можно. Но лучше что-бы миграции жили отдельно, а основной код отдельно. Это делается для того что-бы при изменениях в модели миграции все равно работали, т.к. править существующею миграции - плохо. А то можно так доработать модель что старая миграция перестанет исполняться и отдавать ошибку.
ОтветитьЕсли использовать систему контроля версий, то при возникновении ошибки можно откатиться до версии когда модель не правилась, выполнить миграцию до определенной версии. Далее перейти на текущую версию кода и выполнить миграцию до текущей версии структуры бд
ОтветитьМожно конечно, но это как то слишком усложнено. Лучше делать без моделей
ОтветитьТо есть если я правильно понял, то все изменения в БД надо делать через миграции, а потом их применять? И в самой базе вручную ничего не менять?
ОтветитьЕсли я хочу добавить новую таблицу, то я создают пхп файл миграции, пишу там запрос на создание таблицы. Потом применяю миграцию, так?
Да, все верно
ОтветитьЯ делаю и так и так. Т.е. в зависимости от ситуации, могу добавить миграцию, а потом выполнить ее, а могу добавить поле руками и вставить запрос в миграцию. Проблем пока не возникало.
ОтветитьЯсно, спасибо
ОтветитьПомогите, ввожу в консоль:
Ответитьyiic migrate create my_migrate
и получаю ошибку: 'yiic' is not recognized as an internal or external command, operable program or batch file.
Что я делаю не так?
Вы выполняете команду yiic migrate create my_migrate в папке protected своего проекта? Если нет, то перейдите в нее (z:/home/myproject.local/www/protected)
ОтветитьСпасибо, не зашел в папку protected
ОтветитьЗдравствуйте, а можно в миграцию добавить sql дамп, файл экпорта БД из phpMyAdmin. Чтобы сразу выполнить стартовую миграцию с созданием таблиц и наполнением их данными
ОтветитьА как пропустить определенное количество миграций?
ОтветитьДля этого используйте команду:
Например:
Получим список невыполненных миграций, например:
---
m160921_123540_add_...
m160921_171354_add_...
m160922_091451_add_...
m170113_191621_add_...
m170116_151225_add_...
m170626_132837_add_...
---
Указываем что миграции до m170626_132837_add_... ненужно применять
При выполнении команды
Будет применена миграция m170626_132837_add_... и следующиеОтветить
Спасибо
Ответить