Так уж сложилось, что в 1С-Битрикс нет никакой штатной возможности по работе с модификацией структуры БД, кроме как делать это ручками в админке.
На конференциях разработчиков, у сотрудников Битрикса постоянно просят добавить в продукт механизм миграций БД, однако нам постоянно отвечают «завтраками», что может быть, когда-нибудь мы их сделаем.
Ну а работа не стоит на месте, потребность вносить изменения в БД в автоматическом режиме с соблюдением версионности никуда не делась, и даже наоборот - зреет с каждым днем.
Надоело! Прикручиваем миграции к Битриксу сами
Как обычно, любую задачу я начинаю с изучения того, что есть в опенсорсе. Для решения проблемы миграции уже есть несколько библиотек для битрикса, которые успешно применяются на продакшене.
worksolutions/bitrix-module-migrations
На момент написания статьи данный модуль является наиболее продвинутым из тех, что мне удалось найти, с точки зрения интеграции с битриксом. Это полноценный модуль, который можно установить из marketplace. Доступны исходники на Github.
Из плюсов стоит отметить, что модуль обладает как графическим интерфейсом в админке Битрикса, так и интерфейсом командной строки. Он позволяет наглядно видеть, какие миграции, когда и кем были применены, позволяет легко откатить уже выполненные миграции также через веб-интерфейс с полным логированием всех операций. Если возможность использовать «автомиграции»: это такая штука, которая слушает обработчики событий и при изменении схемы данных позволяет записать их изменение в файл с миграцией. Также у модуля есть подробно составленная документация с описанием большинства операций, которые можно выполнять с помощью модуля. А еще у них есть удобный функционал для упрощения написания скриптов миграций, т.н. билдеры, которые реально ускоряют процесс написания своей миграции.
Но для меня этот модуль не подошел. Частично из-за тех же плюсов, которые с другой стороны являются минусами. Да, исходники доступны на гитхабе, но они в windows-1251 (очевидно, для удобства публикации модуля в marketplace). Содержать свой форк в utf-8 будет накладно.
Сами создатели модуля обязывают устанавливать модуль из маркетплейса, т.к. при установке и обновлении производятся определенные операции изменения БД.
Ну и все описанное выше делает невозможным подключение модуля через composer, а также делает невозможным его обновление при отсутствующей лицензии.
В дополнение к этому, я очень опасаюсь, что модуль миграций каким-то образом может заинтересовать администратора сайта, и он может случайно, или намеренно применить или откатить ряд миграций, что может сказаться на функциональности сайта.
Workflow работы с миграциями меня тоже не очень порадовал: версия БД почему-то хранится в файле. А еще хеши, за которыми иногда придется следить.
В связи с этим всем я отказался от использования данного модуля, хотя он почти полностью покрывает мои нужды.
Phinx
Чудесная библиотека для создания миграций. Используется во многих проектах, но не имеет никакой нативной интеграции с битриксом (оно и понятно). Обладает всем необходимым функционалом для работы с БД, конфигурируется с помощью YML или php файлов. Но для упрощения работы с ним в битриксе пришлось бы написать определенный слой, в котором будет осуществляться помощь для создания миграций.
Честно признаться, я и не особо много изучал его возможности, а их у него предостаточно. Это навело на мысль, что возможно мне пока не нужен такой гигант на проекте, пока вокруг него не будет построена инфраструктура, помогающая в более простом и удобном виде создавать миграции, специфичные под Битрикс, а времени на подробное изучение библиотеки пока нет. Но Phinx однозначно заслуживает внимания, отложим его до лучших времен.
arrilot/bitrix-migrations
Эта библиотека оказалась для меня золотой серединой. Сделанная Ильёй Некрасовым из Greensight, простая, в основе которой лежат компоненты symfony и laravel, легко подключается через composer. Работа с библиотекой строится настолько просто и очевидно, что изучение возможностей укладывается в полчаса-час. Для упрощения и ускорения написания миграций для битрикса есть функционал «шаблонов», который содержит куски предустановленного кода. Также, как и в worksolutions/bitrix-module-migrations, есть возможность автоматически следить за изменениями схемы данных некоторых сущностей и создавать файлы миграций.
В общем говоря, простота модуля, его расширяемость, отсутствие административного интерфейса и следование стандартам подкупило меня, и я решил использовать именно его.
Интегрируемся
Я не упомянул еще одного факта, который был также важен при принятии решения. В проекте, на котором мне понадобились миграции, в качестве консольного приложения используется console-jedi, и мне было важно быстро и просто интегрироваться с ним. Благо, это не составило никакого труда.
Библиотека миграций предоставляет перечень следующих команд: install, make, migrate, rollback, templates, status. Каждая команда выполнена с помощью Symfony Console Component. В console-jedi я хотел видеть эти команды в отдельном пространстве имен, чтобы не путать с командами самого console-jedi. Сказано - сделано.
сonsole-jedi позволяет встроить в себя команды из приложения двумя способами. Первый способ - встроить с помощью модуля. В корне вашего битриксового модуля должен находиться файлик cli.php, который должен возвращать массив вида
return [
'commands' => [
//Тут массив с инициализацией ваших команд
]
];
О втором способе я расскажу чуть ниже.
У нас в команде как раз есть подходящий для использования первого способа модуль - maximaster/tools, в который было бы круто прикрутить миграции, и дать возможность всем разработчикам при подключении данного модуля использовать миграции на любом проекте.
Для интеграции в maximaster/tools нужно было сделать несколько простых шагов:
- Добавить зависимость maximaster/tools от arrilot/bitrix-migrations и notamedia/console-jedi
- Написать небольшой класс-адаптер, который позволит инициализировать модуль миграций и консольные команды. Тут я разделил команды на 2 вида - файловые и БДшные, ниже поясню, зачем именно. В методе addNamespaceToCommands я добавил неймспейс migrate для всех инициализированных команд.
namespace Maximaster;
use Arrilot\BitrixMigrations\Commands\MakeCommand;
use Arrilot\BitrixMigrations\Commands\InstallCommand;
use Arrilot\BitrixMigrations\Commands\MigrateCommand;
use Arrilot\BitrixMigrations\Commands\RollbackCommand;
use Arrilot\BitrixMigrations\Commands\TemplatesCommand;
use Arrilot\BitrixMigrations\Commands\StatusCommand;
use Arrilot\BitrixMigrations\Migrator;
use Maximaster\Extend\Arrilot\BitrixMigrations\Storages\BitrixDatabaseStorage;
use Arrilot\BitrixMigrations\TemplatesCollection;
/**
* Класс, который позволяет прицепить команды модуля миграции к console-jedi
* @package Maximaster
*/
class MigrationsAdapter
{
private $migrator = null;
private $storage = null;
private $templates = null;
public function __construct()
{
$config = $this->getConfig();
$this->storage = new BitrixDatabaseStorage($config[ 'table' ]);
$this->templates = new TemplatesCollection();
$this->templates->registerBasicTemplates();
$this->migrator = new Migrator($config, $this->templates, $this->storage);
}
/**
* Получает массив с конфигурацией модуля
* table - название таблицы в БД, которая хранит миграции
* dir - название директории в корне проекта, которая содержит файлы миграций
* @return array
*/
public function getConfig()
{
return array(
'table' => 'maximaster_db_migrations',
'dir' => './migrations',
);
}
/**
* Получает перечень всех команд
* @return \Arrilot\BitrixMigrations\Commands\AbstractCommand[]
*/
public function getCommands()
{
$migrationCommands = array_merge($this->getDatabaseCommands(), $this->getFileCommands());
return $migrationCommands;
}
/**
* Добавляет пространство имен для команд
* @param \Arrilot\BitrixMigrations\Commands\AbstractCommand[] $commands
* @return array
*/
private function addNamespaceToCommands(array $commands)
{
foreach ($commands as &$command) {
$commandName = $command->getName();
$command->setName('migration:' . $commandName);
}
return $commands;
}
/**
* Получает список команд, для выполнения которых требуется наличие подключения к БД
* @return \Arrilot\BitrixMigrations\Commands\AbstractCommand[]
*/
public function getDatabaseCommands()
{
$config = $this->getConfig();
$commands = array(
new InstallCommand($config[ 'table' ], $this->storage),
new MigrateCommand($this->migrator),
new RollbackCommand($this->migrator),
new StatusCommand($this->migrator),
);
return $this->addNamespaceToCommands($commands);
}
/**
* Получает список команд, для выполнения которых НЕ требуется наличие подключения к БД
* @return \Arrilot\BitrixMigrations\Commands\AbstractCommand[]
*/
public function getFileCommands()
{
$commands = array(
new MakeCommand($this->migrator),
new TemplatesCommand($this->templates),
);
return $this->addNamespaceToCommands($commands);
}
}
- Поскольку модуль миграций рассчитывает на то, что ядро уже инициализировано полностью в момент запуска, а console-jedi работает несколько иначе, то нужно было создать небольшой враппер для класса работы с БД из модуля миграций. Единственная его цель - предоставить подключение к БД в случае, если ядро инициализировалось. Исходники можно посмотреть на гитхабе, там все тривиально.
- Подключить команды в cli.php в корне модуля:
<?php
/**
* Регистрируем все команды миграций arrilot/bitrix-migrations
*/
$migrationsConnector = new \Maximaster\MigrationsAdapter();
$migrationsCommands = $migrationsConnector->getCommands();
$config = array(
'commands' => $migrationsCommands
);
return $config;
И вуаля!

Файловые и не файловые команды
Я уже писал в более ранних постах, что мы в команде хостим и ведем разработку проектов на отдельном сервере, однако весь код хранится локально на компьютерах разработчиков и синхронизируется с сервером разработки при изменениях.
Так вот разделение команд на файловые и не файловые необходимо было для того, чтобы дать разработчикам возможность пользоваться файловыми командами миграций на своем локальном ПК даже не имея веб-сервера и битрикса. console-jedi устроен таким образом, что он будет работать и без битрикса, но команды будут доступны не все. Я решил использовать и эту возможность.
maximaster/tools - это не совсем типичный модуль в понятии Битрикса. Он не использует нативную автозагрузку битрикса, благодаря чему его классы тоже можно использовать и вне битрикса. Поэтому подключив модуль через composer, вы получаете тот же модуль миграций и адаптер к нему, которые можно использовать благодаря psr-4.
В jedi есть еще один способ добавления команд - через файл .jedi.php в корне проекта. Схема примерно та же, что и в cli.php но в нем мы зарегистрируем только файловые операции:
use Maximaster\MigrationsAdapter;
return [
'web-dir' => 'htdocs',
'env-dir' => 'environments',
'useModules' => true,
'commands' => (new MigrationsAdapter())->getFileCommands()
];
после чего на локальном компе будут доступны операции миграций - создание файла и просмотр списка шаблонов миграций:

Да, джедай будет ругаться на отсутствие битрикса, но это и ожидалось. Но зато теперь на любом ПК разработчика будут доступны команды, упрощающие создание миграций. Создав файл миграции через migration:make не придется идти по ssh на сервер разработки и выкачивать нужную миграцию (особенно когда их будут сотни и тысячи)
Вот такая получилась полезная интеграция!
Я не сомневаюсь, что и для Phinx и для ws.migrations можно сделать подобную интеграцию. Коллеги из Notamedia (спасибо им за console-jedi), кстати как раз используют Phinx в своих проектах, который интегрирован с джедаем. Данная статья больше о том, каким путем я пошел для подключения миграций в Битрикс, а не о том, каким именно инструментом пользоваться для этого.
Спасибо за внимание.