Примітка: Міграції доступні з версії 1.1.6.
Як і початковий код, структура бази даних змінюється в процесі розробки та підтримки додатку. Приміром, під час розробки може знадобитися додати нову таблицю або вже після розміщення додатка на сервері додати індекс або стовпець. При цьому важливо відстежувати зміни в структурі бази даних (звані міграціями) також, як ми робимо це для нашого початкового коду. Якщо початковий код і база даних не відповідають один одному, швидше за все все додаток не буде працювати. Саме тому в Yii є підтримка міграцій, що дозволяє відстежувати зміни в базі даних, застосовувати міграції або відкочувати вже застосовані.
Нижче наведено поетапний процес як ми можемо використовувати міграції бази даних при розробці:
У Yii управління міграціями проводиться через консольну команду yiic migrate
, яка підтримує створення нових міграцій,
застосування, відкат і повторне застосування міграцій, перегляд історії міграцій і нових міграцій.
Примітка: При роботі з командою
migrate
рекомендується використовувати yiic програми (тобто післяcd path/to/protected
), а не yiic з директоріїframework
. Переконайтеся, що директоріяprotected/migrations
існує і доступна для запису. Також перевірте налаштування зʼєднання з базою даних вprotected/config/console.php
.
Для створення нової міграції (наприклад, яка створює таблицю для новин), ми повинні ввести в консолі:
yiic migrate create <name>
Обовʼязковий параметр name
повинен містити дуже короткий опис міграції (таке, як, наприклад, create_news_table
).
Як буде показано далі, цей параметр використовується як частина імені класу міграції,
тому використовувати можна тільки букви, цифри та знаки підкреслення.
yiic migrate create create_news_table
Наведена команда створить в директорії protected/migrations
файл m101129_185401_create_news_table.php
, який містить наступне:
class m101129_185401_create_news_table extends CDbMigration
{
public function up()
{
}
public function down()
{
echo "m101129_185401_create_news_table does not support migration down.\n";
return false;
}
/*
// якщо потрібно виконати зміни в транзакції, використовуйте safeUp/safeDown
// замість up/down
public function safeUp()
{
}
public function safeDown()
{
}
*/
}
Варто відзначити, що імʼя класу збігається з іменем файлу і будується як 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 для цього було необхідно викинути виняток.
Розглянемо як приклад міграцію, яка створює таблицю з новинами.
class m101129_185401_create_news_table extends CDbMigration
{
public function up()
{
$this->createTable('tbl_news', array(
'id' => 'pk',
'title' => 'string NOT NULL',
'content' => 'text',
));
}
public function down()
{
$this->dropTable('tbl_news');
}
}
Базовий клас CDbMigration надає набір методів для роботи з даними і структурою бази даних.
Приміром, за допомогою CDbMigration::createTable можна створити нову таблицю, а CDbMigration::insert додасть рядок з даними.
Всі ці методи використовують підключення до бази даних, що повертає CDbMigration::getDbConnection(),
що за замовчуванням еквівалентно Yii::app()->db
.
Інформація: Як ви могли помітити, методи CDbMigration дуже схожі на методи CDbCommand. І це насправді так. Єдина відмінність у тому, що методи CDbMigration підраховують витрачений час на їх виконання і виводять повідомлення про параметри методів.
Інформація: Дана можливість підтримується починаючи з версії 1.1.7.
При застосуванні складних міграцій для дотримання цілісності та звʼязності потрібно або виконати всі запити, або, якщо запит не виконався, скасувати попередні запити. Для досягнення цієї мети можна використовувати транзакції.
Можна почати транзакцію явно і заключити в неї весь код, який змінює базу даних:
class m101129_185401_create_news_table extends CDbMigration
{
public function up()
{
$transaction=$this->getDbConnection()->beginTransaction();
try
{
$this->createTable('tbl_news', array(
'id' => 'pk',
'title' => 'string NOT NULL',
'content' => 'text',
));
$transaction->commit();
}
catch(Exception $e)
{
echo "Exception: ".$e->getMessage()."\n";
$transaction->rollback();
return false;
}
}
// …схожий код для down()
}
А можна зробити це простіше, реалізувавши метод safeUp()
замість up()
і safeDown()
замість down()
:
class m101129_185401_create_news_table extends CDbMigration
{
public function safeUp()
{
$this->createTable('tbl_news', array(
'id' => 'pk',
'title' => 'string NOT NULL',
'content' => 'text',
));
}
public function safeDown()
{
$this->dropTable('tbl_news');
}
}
Yii при застосуванні міграції почне транзакцію і, потім, виконає код в safeUp()
або safeDown()
.
Якщо при цьому виникне яка-небудь помилка, відбудеться відкат транзакції, тобто база повернеться у початковий стан.
Примітка: Не всі СУБД повністю підтримують транзакції і не для всіх виразів. У тому випадку, якщо підтримки транзакцій немає, реалізовувати треба
up()
іdown()
. У разі MySQL та MariaDB, деякі вирази SQL можуть викликати неявне застосування транзакції (детальніше про це у документації до MySQL та MariaDB).
Для того, щоб застосувати всі нові міграції (тобто привести локальну БД в актуальний стан), слід запустити наступну команду:
yiic migrate
Команда відобразить перелік всіх нових міграцій і, у випадку позитивної відповіді,
по черзі запустить метод up()
у кожному класі міграції в порядку його створення.
Після застосування міграції у таблицю tbl_migration
буде внесений відповідний запис.
Це дозволяє дізнатися, які міграції вже застосовані, а які ні. Якщо таблиця tbl_migration
не існує,
вона буде створена автоматично в базі даних, зазначеної у компоненті db
додатка.
Іноді потрібно застосувати лише одну або декілька нових міграцій. Для цього можна використовувати наступну команду:
yiic migrate up 3
При цьому застосовується три нові міграції. Замість трьох можна вказати будь-яку кількість застосовуваних міграцій.
Також можна привести стан бази даних до певної версії:
yiic migrate to 101129_185401
У якості параметра, що вказує версію, до якої потрібно привести базу даних, використовується частина імені файлу, що відповідає часу створення міграції. Якщо між останньою застосованою і вказаною міграціями кілька міграцій, то всі вони будуть застосовані. Якщо зазначена міграція вже застосовувалася, то буде проведений відкат всіх міграцій, застосованих після неї (описано в наступному розділі).
Для відкату однієї або декількох останніх застосованих міграцій можна скористатися наступною командою:
yiic migrate down
де необовʼязковий параметр step
задає кількість міграцій, які треба відкотити.
За замовчуванням відкочується одна остання застосована міграція.
Як було описано раніше, не всі міграції можна відкотити. При спробі відкату таких міграцій буде викинуто виключення і процес відкату буде перерваний.
Повторне застосування міграції проводиться шляхом послідовного відкату і застосування. Здійснити це можна наступною командою:
yiic migrate redo
де необовʼязковий параметр step
вказує кількість міграцій, які необхідно застосувати ще раз.
За замовчуванням повторюється одна остання міграція.
Крім застосування і відкату міграцій, інструмент міграцій може відображати історію міграцій і нові, ще не застосовані міграції.
yiic migrate history
yiic migrate new
Тут параметр limit
вказує кількість міграцій, що відображаються. Якщо limit
не вказаний, відображаються всі міграції.
Перша команда показує вже застосовані міграції, друга - міграції, які ще не були застосовані.
Іноді потрібно змінити історію міграцій так, щоб поточна версія була замінена на вказану без застосування або відкату міграцій. Часто це потрібно при створенні нової міграції. Для цього можна використовувати наступну команду:
yiic migrate mark 101129_185401
Ця команда дуже схожа на yiic migrate to
, але вона лише змінює таблицю історії міграцій до зазначеної
версії без застосування або відкату самих міграцій.
Є кілька способів налаштувати команду міграцій.
Команда міграцій може бути налаштована чотирма опціями:
interactive
: чи використовувати інтерактивний режим. За замовчуванням true, тобто при застосуванні міграції буде виводитися підтвердження.
Якщо параметр виставлений у false, то міграції можна застосувати у фоновому режимі;
migrationPath
: вказує директорію, в якій зберігаються всі файли міграцій. Шлях повинен вказуватися у форматі псевдоніма
і відповідна йому директорія повинна існувати. Якщо параметр не вказаний,
буде використана піддиректорії migrations
, що знаходиться всередині директорії з додатком;
migrationTable
: вказує імʼя таблиці в базі даних, яка зберігає історію міграцій. За замовчуванням воно дорівнює tbl_migration
.
Структура таблиці наступна: version varchar(255) primary key, apply_time integer
;
connectionID
: вказує ідентифікатор компонента бази даних. За умовчанням це 'db';
templateFile
: вказує шлях до файлу, який використовується як шаблон для генерації класів міграцій.
Шлях повинен вказуватися як псевдонім (тобто як application.migrations.template
).
Якщо шлях не заданий, буде використовуватися внутрішній шаблон.
У шаблоні токен {ClassName}
буде замінений імʼям класу міграції.
Для зазначення опцій використовується наступний формат:
yiic migrate up --option1=value1 --option2=value2 ...
Наприклад, якщо необхідно мігрувати модуль forum
, файли міграцій якого розташовані у директорії модуля migrations
,
можна скористатися наступною командою:
yiic migrate up --migrationPath=ext.forum.migrations
Варто відзначити, що при передачі через командний рядок прапорів,
таких як interactive
, необхідно використовувати значення 1
або 0
:
yiic migrate --interactive=0
У той час, як опції командного рядка дозволяють нам на льоту конфігурувати команду міграцій, іноді потрібно застосувати налаштування раз і назавжди. Приміром, нам може знадобитися використовувати іншу таблицю для зберігання історії міграцій або використовувати свій шаблон міграції. Це можна зробити, змінивши налаштування консольного додатку наступним чином:
return array(
......
'commandMap'=>array(
'migrate'=>array(
'class'=>'system.cli.commands.MigrateCommand',
'migrationPath'=>'application.migrations',
'migrationTable'=>'tbl_migration',
'connectionID'=>'db',
'templateFile'=>'application.migrations.template',
),
......
),
......
);
Тепер, при запуску команди migrate
, зазначені вище налаштування будуть застосовані
без введення яких-небудь додаткових параметрів.