Pull to refresh

Миграции баз данных — обзор библиотеки и ее использование

Reading time 5 min
Views 5.2K
Как вы уже могли прочесть, недавно вышла новая версия CodeIgniter, одним из нововведений которого является библиотека Migration. Один из главных ее разработчиков, Phil Sturgeon был настолько воодушевлен удобством управления версиями баз данных для Rails, что решил создать аналог такого метода для CodeIgniter, и вот, в конце-концов вы можете видеть эту библиотеку в официальной поставке.
Из этой статьи вы получите общее представление о миграциях, а также научитесь их создавать. Во второй же части, мы с вами увидим, как легко они могут быть интегрированы в ваше приложение.
Данная статья будет полезна начинающим пользователям CodeIgniter, но я надеюсь что и более продвинутые коллеги узнают об этой чудесной библиотеке и подчерпнут для себя что-нибудь новое.

Кроме всего прочего, данная библиотека совсем не сложна, и реализовать ее при желании для любой другой платформы не составит большого труда!


Обзор библиотеки


Библиотека Migration позволяет нам хранить в приложении все изменения базы данных, и накатывать или откатывать их при необходимости. Это может быть удобно и для разработки в команде — не надо объяснять вашему коллеге, что надо изменить в базе, чтобы ваш код заработал, так и при выгрузке новых версий сайта на боевой сервер. Ну или, на худой конец, можно всегда быстро откатиться до старой версии, если вы где-то напортачили.

Чтобы понять в общих чертах, как работает библиотека рассмотрим следующий примитивный сценарий:
0. Допустим, у нас есть 0 версия приложения с начальной базой (также версии 0).
1. В ходе разработки мы понимаем, что для реализации нового функционала (например системы подписки на новости) нам необходимо будет внести изменения не только в код приложения, но и в структуру базы данных.
2. Для этого мы в конфиге укажем, что версия базы данных для этой версии кода будет 1 и вместе с новым кодом создадим миграцию 001, указав для нее действия как для апгрейда, так и для даунгрейда базы (на случай если нужно будет откатить версию приложения).
3. Затем мы реализуем какой-либо механизм накатывания обновлений — это может быть и страничка в админке, и решение, использующее CLI, или даже полностью автоматическое обновление при выгрузке из системы контроля версий.
4. Выгружаем новый код проекта на сайт, запускаем миграцию до нужной версии, и вуаля!

А теперь представьте, что вам нужно обновить приложение через 3 версии вперед, или же на тестовом сервере посмотреть как была реализована версия, сделанная пару месяцев назад? Легко, просто изменив код, мигрируйте до нужной версии базы (миграция произойдет постепенно, допустим с 4-й до 1-й сначала накатятся 3-я и 2-я, а затем 1-я версии)!

Вы воодушевились такой возможностью как и я и хотите попробовать? Нет ничего проще!

Практическое использование


Собственно говоря, библиотека совершенно проста в использовании, и для ее внедрения в проект требуется добавить\поправить совсем немного строчек кода.
Весь процесс создания миграций не займет десяток минут времени, а сэкономит вам и вашим коллегам, работающим над этим же проектом прилично.

Создаем класс MY_Migration

Итак, для начала нам будет нужно немного допилить напильником расширить класс Migration.
Зачем? Все очень просто, по умолчанию этот класс не умеет сообщать о том, какие версии базы и кода являются текущими, а реализовывать эти проверки по всему коду не совсем правильно, лучше это сделать в одном месте.
Для этого воспользуемся стандартной методикой расширения классов, используемой в CodeIgniter — создадим файл %site_path%/application/libraries/MY_Migration.php со парой десятков строк кода внутри.
Этот класс добавит к реализации предка еще 2 публичных метода:
	/**
	 * Wrapper function for the protected _get_version.
	 * Get's the database current version
	 *
	 * @access	public
	 * @return	integer	Current DB Migration version
	 */
	public function get_db_version() {	
		return parent::_get_version();
	}
	
	/**
	 * Retrieves current file system version
	 *
	 * @access	public
	 * @return	integer	Current file system Migration version
	 */
	public function get_fs_version() {
		return $this->_migration_version;
	}

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

Как видите, функции являются лишь обертками для protected метода для получения версии базы данных и опять же protected свойства $_migration_version, и вполне наглядно демонстрируют применение инкапсуляции.
Также советую обратить внимание на важный момент: в оригинальном классе Migration стоит ограничение, из-за которого его конструктор выполняется только при инициализации родительского класса.
Поэтому чтобы приложение работало правильно, автоматически инициализируя MY_Migration вместо оригинала, необходимо продублировать конструктор родительского класса, изменив в нем условие на 41 строке:
	public function __construct($config = array()) { 
		# Only run this constructor on main library load
		if (get_parent_class($this) !== FALSE)
		{  
			return;
		}
	###	   Other code here...
	}

на
	public function __construct($config = array()) { 
		# Only run this constructor on main library load
		if (get_parent_class($this) !== FALSE && get_class($this)!='MY_Migration')
		{  
			return;
		}
	###	  Other code here...
	}


Создаем миграцию

Расширив базовый класс, дело остается за малым. Для того, чтобы библиотека могла накатывать или откатывать изменения на базу данных, необходимо создать миграционный файл, содержащий в себе класс-потомок Migration(в нашем случае MY_Migration).
Так как у нас это первая миграция, то создадим следующий файл: %site_path%/application/migrations/001_add_messages.php, содержащий в себе фунции up и down:

<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Migration_Add_messages extends MY_Migration {
	public function up() {
		$this->db->query("
			CREATE TABLE IF NOT EXISTS `email_list` (
				`list_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
				`email` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
			) ENGINE=MyISAM;");
	}
	public function down() {
		$this->db->query("DROP TABLE IF EXISTS `email_list`");
	}
}

Обратите внимание на то, что файлы с миграциями содержат в начале 3-х здачный цифровой порядковый номер версии, на которую они переводят базу данных, а класс, содержащийся в них называется как имя файла, где вместо номера версии стоит Migration_.

Правим конфиг

Наконец, для работы с миграциями нужно немного подправить конфиг в файле %site_path%/application/config/migration.php и включить их, посмотреть правильно ли указаны к ним путь и версия базы данных, требуемой для корректной работы нашего кода (стандартные комментарии вырезаны из листинга):
	$config['migration_enabled'] = TRUE;
	$config['migration_version'] = 1;
	$config['migration_path'] = APPPATH . 'migrations/';

Обратите внимание, что я указал 1-ю версию, что подразумевает, что мы уже сделали функционал рассылок.


Итог


Таким образом, мы немного повысили удобство пользования библиотекой, расширив ее функционал, обошли подводный камень, связанный с проверкой в конструкторе на наследование оригинального класса, а так же научились создавать миграции.
Как вы видите, ничего сложного в создании миграций нет, а, повторюсь, они могут сэкономить вам существенное количество времени. Более того, их внедрение в текущий проект так же не должно вызвать каких-либо сложностей. Кстати, как раз внедрению и будет посвящена моя вторая статья, которая появится в самое ближайшее время.

Скачать архив с полными исходниками

Вторая часть: Миграции баз данных — интеграция с вашим приложением

PS: Не хватает кармы для публикации в блог CodeIgniter, так что пока публикую обще-php-шный блог
UPD: Добрые анонимы налили немного кармы, перенес в блог CodeIgniter
Tags:
Hubs:
+36
Comments 22
Comments Comments 22

Articles