Как писать миграции в yii framework 2.0
Наиболее уместный и удобный вариант написания миграций для фреймворка Yii 2.0.
В данной статье вы увидите одну из общепринятых практик написания миграций для популярного фреймворка Yii. Многие проекты блога catine используют данный подход, так как он считается общепринятым в нашей команде разработчиков. Надеюсь, вы используете Linux, как основную операционную систему для разработки. Если же вы используете Windows, то советую вам обратиться к Vagrant и начать использовать unix системы при разработке.
Давайте договоримся, что у нас есть следующая схема данных, которую необходимо реализовать:
Таблица articles
– таблица, которая уже существует в бд, в миграции будем на нее только ссылаться. Эта сущность обозначает новости на сайте, описывается следующим набором полей:
id
– идентификатор, первичный ключtitle
– название новости, текстовое полеcontent
– содержание новости, текстовое поле
Таблица tasks
– задачи для новостей, сущность будет создаваться в миграции. Имеет следующий набор полей:
id
– идентификатор, первичный ключtitle
– текст задачи, текстовое полеsort
– поле для сортировки, при создании равно нулю
Таблица articles_has_tasks
– таблица пересечения задач и новостей, так как у нас связь между таблицами N:M многие ко многим. Имеет следующий набор полей:
task_id
– ссылка на задачуarticle_id
– ссылка на новость
Для создания миграции необходимо перейти в рабочий каталог с установленным yii framework`ом и выполнить команду:
php yii migrate/create название_миграции
В нашем случае необходимо будет выполнить команду php yii migrate/create create_task_table
и в ответ на вопрос ответь yes
.
И после того, как вы увидели заветную надпись New
migration created successfully.
, можно приступить к написанию кода миграции.
Как учит писать нас документация по yii 2.0 миграции:
<?php
use yii\db\Schema;
use yii\db\Migration;
class m160511_031901_create_task_table extends Migration
{
public function safeUp()
{
$this->createTable('tasks', [
'id' => Schema::TYPE_INTEGER . ' NOT NULL',
'lang' => 'CHAR(2) NOT NULL DEFAULT "ru" COLLATE utf8_unicode_ci',
'title' => Schema::TYPE_STRING . ' NOT NULL',
'sort' => Schema::TYPE_INTEGER . ' NOT NULL DEFAULT 0',
'PRIMARY KEY (`id`, `lang`)'
], 'CHARSET=utf8 COLLATE=utf8_general_ci');
$this->createTable('articles_has_tasks', [
'article_id' => Schema::TYPE_INTEGER . ' NOT NULL',
'task_id' => Schema::TYPE_INTEGER . ' NOT NULL',
], 'CHARSET=utf8 COLLATE=utf8_general_ci');
$this->addPrimaryKey('articles_has_tasks' . '_pk', 'articles_has_tasks', ['article_id', 'task_id']);
$this->addForeignKey('task_' . 'articles_has_tasks' . '_fk', 'articles_has_tasks', 'task_id', 'tasks', 'id');
$this->addForeignKey('articles' . '_fk', 'articles_has_tasks', 'article_id', 'articles', 'id');
}
public function safeDown()
{
$this->dropTable('articles_has_tasks');
$this->dropTable('tasks');
}
}
Данная миграция уже будет работать, применяться (команда php yii migrate 1
) и откатываться без ошибок (команда php yii migrate/down 1
), но не всегда понятно какой sql запрос будет сформирован, поэтому советую вам использовать другой подход написания миграции, более приближенный к sql запросам.
Данную миграцию можно было бы написать следующим образом:
<?php
use yii\db\Schema;
use yii\db\Migration;
class m160511_031901_create_task_table extends Migration
{
public function safeUp()
{
$this->createTable('tasks', [
'id' => 'int(11) NOT NULL',
'lang' => 'CHAR(2) NOT NULL DEFAULT "ru" COLLATE utf8_unicode_ci',
'title' => 'char(255) NOT NULL COLLATE utf8_unicode_ci',
'sort' => 'int(11) NOT NULL DEFAULT 0',
'PRIMARY KEY (`id`, `lang`)'
], 'CHARSET=utf8 COLLATE=utf8_general_ci');
$this->createTable('articles_has_tasks', [
'article_id' => 'int(11) NOT NULL',
'task_id' => 'int(11) NOT NULL',
'PRIMARY KEY (`article_id`, `task_id`)',
'FOREIGN KEY (`article_id`) REFERENCES `articles`(`id`)',
'FOREIGN KEY (`task_id`) REFERENCES `tasks`(`id`)'
], 'CHARSET=utf8 COLLATE=utf8_general_ci');
}
public function safeDown()
{
$this->dropTable('articles_has_tasks');
$this->dropTable('tasks');
}
}
Данный подход дает позволяет более точно определить какой запрос будет сформирован при выполнении миграции, что увеличивает понимание в команде разработчиков. Такой код легче всего читать и писать, так как он максимально приближен к sql.
А как быть, если я хочу провести сразу все миграции?
Чтобы провести все миграции, которые когда-либо были созданы, но не были проведены, можно командой: php yii migrate
Вам автоматически будет предложено провести все миграции, которые не были выполнены на данной базе. Информация об этом хранится в самой бд – таблица migration
.
А вот отменить все миграции можно только через команду: php yii migratedown N
, где вместо N
необходимо указать количество миграций, которые необходимо отменить. Если ввести без указания N
, то будет предложено откатить лишь последнюю миграцию.