Миграции базы данных в 1С-Битрикс: быстро, правильно, надежно

Миграции базы данных в 1С-Битрикс.png

Всё, всё, шо нажил непосильным трудом, всё же погибло!
Три магнитофона, три кинокамеры заграничных, три портсигара отечественных, куртка замшевая… Три. Куртки.
И они ещё борются за почётное звание «дома высокой культуры быта», а?..

(с) Иван Васильевич меняет профессию
Если Вы разрабатываете проекты на 1С-Битрикс с привлечением двух и более программистов, то Вам сюда.
ИНТЕРВОЛГА делится с сообществом веб-разработчиков своим крутым инструментом для АВТОМАТИЧЕСКОЙ миграции БД в 1С-Битрикс.

Как настоящие спортсмены, мы сделали три подхода к снаряду. Первый раз пробовали чужие решения . Второй раз — начинали свою разработку на скорую руку. Ну а получилось только на третий раз.

При использовании нашего модуля, время на выполнение релиза и перенос изменения БД, сокращается с нескольких часов до 10-20 минут (при отсутствии конфликтов).

Поддерживаемые сущности

Среди огромного разнообразия данных в 1С-Битрикс: Управление Сайтом для первого раза мы выбрали следующие сущности.

  • В модуле main :

    • Группы пользователей (сущность group )

    • Типы почтовых событий (сущность eventtype )

    • Почтовые события (сущность event )

    • Языки (сущность language )

    • Культура (сущность culture )

    • Сайты (сущность site )

    • Правила подключения шаблонов сайтов (сущность sitetemplate )

    • UF-поля (сущность field )

    • Варианты UF-списков (сущность fieldenum )

  • В модуле highloadblock :

    • ХЛБ (сущность highloadblock )

    • Поля ХЛБ (сущность field )

    • Варианты списков полей ХЛБ (сущность fieldenum )

  • В модуле catalog :

    • Типы цен (сущность pricetype )

  • В модуле sale :

    • Типы плательщиков (сущность persontype )

    • Группы свойств заказа (сущность propertygroup )

    • Свойства заказов (сущность property )

    • Варианты списков свойств заказов (сущность propertyvariant )

  • В модуле iblock :

    • Типы ИБ (сущность type )

    • ИБ (сущность iblock )

    • Свойства ИБ (сущность property )

    • Варианты свойств ИБ (сущность enum )

    • Поля разделов (сущность field )

    • Варианты полей разделов (сущность fieldenum )

    • Формы редактирования элементов и разделов ИБ (сущность form )

Уникальные ID для миграции

Для сопоставления записей между несколькими БД нужно выбрать уникальный ID. Родные числовые ID не подходят на эту роль — ими нельзя управлять и они могут различаться в разных БД.

Аналогичная проблема есть при обмене товарами и заказами между сайтом и 1С. Там она решается с помощью уникального внешнего кода — XML_ID. Вот только не у всех данных в БУС предусмотрено это поле. А у тех, что есть, оно не всегда уникальное. Пришлось нам сделать “надстройку” над системным полем XML ID. В таблице ниже описаны все сущности с их XML ID миграции.

Сущность XML ID миграции
Группа пользователей STRING_ID
Тип почтового события LID + EVENT_NAME
Почтовый шаблон md5(EMAIL_FROM+EMAIL_TO+EVENT_NAME+сайты)
Язык LID
Культура NAME
Сайт LID
Настройка шаблона сайта SITE_ID+TEMPLATE+md5(CONDITION)
UF-поле md5(ENTITY_ID+FIELD_NAME)
Вариант списка UF-поля XML_ID
highload-блок TABLE_NAME
Поле highload-блока md5(highload-блок+FIELD_NAME)
Вариант списка поля highload-блока XML_ID
Тип цены XML_ID
Тип плательщика md5(NAME+сайты)
Группа свойств заказа md5(NAME+Тип плательщика)
Свойство заказа md5(CODE+Тип плательщика)
Вариант свойства заказа md5(VALUE+Свойство заказа)
Тип инфоблока ID
Инфоблок XML_ID
Свойство инфоблока Инфоблок+XML_ID
Вариант свойства инфоблока Инфоблок+XML_ID
Право на инфоблок md5(Инфоблок+Группа)
Форма редактирования Инфоблок+несколько полей формы
Поле раздела инфоблока md5(Инфоблок+FIELD_NAME)
Вариант списка поля раздела инфоблока XML_ID

Конфигурирование модуля

Конфигурацию можно изменить в файле /local/migrato/config.xml . Кстати, папку /local/migrato/ нужно обязательно добавить в репозиторий — помимо конфигурации здесь же будут и XML-файлы экспорта. Файл редактируется только вручную через FTP/SSH/файловый менеджер БУС. Синтаксис файла представлен в таблице:

Узел Родительский узел Описание
<config> - Корневой
<module> <config> Настройки миграции модуля
<name> <module> Название модуля
<entity> <module> Сущность для миграции
<name> <entity> Название сущности
<options> <config> Мигрируемые настройки
<exclude> <options> Регулярное выражение для исключения настроек из миграций  

Команды модуля

Для устранения проблем с таймаутом сервера (и чтобы придать тёплую ламповую атмосферу) вся работа с модулем после установки вынесена в командную строку. Точка входа:   <папка модуля>/intervolga.migrato/tools/run.php (в примерах для краткости будет обозначена как run.php ).

Интерфейс модуля в командной строке

Синтаксис простой:
$ php run.php команда [опции]

Доступные команды:

  1. validate (проверка XML ID)
  2. autofix (автоматическое исправление ошибок XML ID)
  3. export (экспорт данных из БД в XML)
  4. import (импорт данных из XML в БД)
  5. log (вывод логов последней запущенной команды)

Служебные команды (для разработчиков новых сущностей):

  1. generate (генерация демо-контента)
  2. unittest (тестирование модуля)

Доступные опции:

  1. -W или --win (изменить кодировку на win-1251)
  2. -U или --utf (изменить кодировку на UTF-8)
  3. -F или --fails (расширенный вывод ошибок после выполнения команды)
  4. -v (краткий отчёт по работе команды)
  5. -vv (подробный отчёт по работе команды)

Проверка XML ID (команда validate)

Модуль читает config.xml и проверяет, чтобы у всех экземпляров сущностей были заданы корректные XML ID. Команда ничего не изменяет в БД. Критерии корректного XML ID:

  1. Не пустой.
  2. Не целиком числовой.
  3. Попадает под регулярное выражение /^[a-z0-9\-_#.]+$/i (допустимы буквы латинского алфавита, цифры, тире, подчёркивание, решётка, точка).
  4. XML ID не должен повторяться в пределах сущности .

Автоматическое исправление ошибок XML ID (команда autofix)

Исправление ошибок XML ID — ответственный шаг, потому и вынесен в отдельную команду. Внимание: процесс может привести к модификации БД . Для всех найденных ошибок XML ID вызывается генератор XML_ID, создающий уникальный код сущности.

Экспорт в *.xml-файлы (команда export)

  1. Модуль записывает текущие настройки всех перечисленных модулей в файлы. Файлы складываются в /local/migrato/<название модуля>/option.xml .
  2. Модуль проверяет XML ID. Работа продолжается только если нет ошибок.
  3. Для каждой записи из перечисленных сущностей модуль создаёт файл: /local/migrato/<название модуля>/<название сущности>/data-<xml id>.xml
  4. Если данные были удалены — в соответствующем файле проставляется атрибут deleted=true в узле <data>

Импорт из *.xml-файлов (команда import)

  1. Модуль выполняет разбор и импорт настроек в БД.
  2. Модуль проводит проверку данных. Работа продолжается только если нет ошибок.
  3. Модуль читает data-файлы и импортирует записи.
  4. Модуль проверяет, остались ли сущности с неразрешёнными зависимостями. Если они есть — это ошибка.
  5. Модуль удаляет файлы, помеченные атрибутом deleted=true .
  6. Модуль проставляет ссылки в данных.
  7. Обновление поискового индекса, urlrewrite, сброс кэша // Вы ведь не забываете делать все это при релизах :) ?

Вывод логов предыдущей команды (команда log)

Если при выполнении одной из предыдущих команд произошла ошибка, увидеть их можно командой log . Использовав опцию --fails можно отфильтровать все записи, оставив только сообщения об ошибках. Если же вам удобнее работать с БД, то все ошибки сохраняются в таблице intervolga_migrato_log .

Генерация демо-контента (команда для разработчиков generate)

Помните, трава раньше была зеленее, мороженое вкуснее а модуль DEFA Tools был бесплатным? Его генератор демо-контента мы воспроизводить, конечно, не стали, но добавить по 2 записи в каждую сущности команда generate может. Команда полезна для разработчиков новых сущностей.

Тестирование модуля (команда для разработчиков unittest)

Вторая команда, полезная для разработчиков (и тестировщиков). Исполняется сценарий.

  1. export
  2. Файлы XML копируются в /local/migrato_old/
  3. import
  4. export
  5. diff папок /local/migrato/ и /local/migrato_old/

Если все сущности работают правильно, diff будет пустым. Если же нет — это значит, что в коде сущности есть ошибка и она импортируется в базу неправильно.

Формат XML файлов

Синтаксис XML-файлов миграции настроек модулей

Узел Родительский узел Описание
<options> - Родительский узел
<option> <options> Настройка
<name> <option> Название настройки
<value> <option> Значение настройки
<site> <option> Сайт, для которого задано значение

Синтаксис XML-файлов миграции данных

Узел Родительский узел Описание
<data> - Родительский узел. Атрибут deleted говорит, что данные были удалены
<xml_id> <data> XML ID данных
<dependency> <data> Узел зависимости
<reference> <data> Узел ссылки
<field> <data> Узел простого поля
<name> <dependency>

<reference>
<field>
Название поля
<value> <dependency>
<reference>
<field>
Значение поля

Как пользоваться модулем

Чтобы начать использовать модуль необходимо на боевом сайте создать оригинальный слепок БД:

  1. Установить модуль intervolga.migrato
  2. Настроить /local/migrato/config.xml
  3. validate
    1. autofix при необходимости или ручное исправление XML ID в БД
  4. export
  5. Добавить папку /local/migrato/ в git (он же у вас уже есть)
  6. git commit & git push
  7. Снять бекап с prod и развернуть на dev1, dev2 ...

Чтобы подготовить миграцию на песочнице devX после окончания работы над задачей:

  1. validate
    1. autofix при необходимости или ручное исправление XML ID в БД
  2. export
  3. git commit & git push

Выполнить миграцию (релиз) на боевом сайте:

  1. validate
    1. autofix при необходимости
  2. export (вдруг на бою были неучтённые в git’е изменения?)
    1. git commit при необходимости
  3. git pull
    1. разрешение конфликтов, если возникли
    2. git push , если возникли конфликты
  4. import

Использование XML ID вместо ID в коде

Пытливый читатель-программист может задать вопрос: как же теперь писать код, если использовать ID — плохо, а XML ID миграции не всегда совпадает с XML ID сущности?

Модуль предоставляет API для получения ID по XML ID:
\Intervolga\Migrato\Data\BaseData::getPublicId($xmlId)

Метод использует кеширование, так что о производительности не стоит беспокоиться.

Если вы используете константы для обращения к сущностям по ID, то вам только и нужно — сделать следующую замену.

Было

Стало


А вот второе изменение принять будет не так просто. Визуальный редактор БУСа при работе с компонентами генерирует код, в котором явно фигурируют “магические” неуникальные числовые ID.


Вот за такое хочется Битрикс от души поругать. Генерация кода зашита очень глубоко и кастомизировать её нет никакой возможности. Мы не стали придумывать хитрых способов подмены такого кода и просто ввели правило — визуальным редактором для редактирования компонентов не пользуемся. Программист один раз настраивает компонент, потом заменяет ID на XML ID миграции и никаких няш-мяш. Если знаете способ лучше — расскажите в комментариях, с радостью примем на вооружение.

Выполнение примера из других модулей

И, напоследок, выполнение общего примера нашим модулем. Сразу после установки проверили все записи на наличие внешних ключей и исправили ошибки:

Теперь можно создавать dev сайты для разработчиков - клонируем prod и обязательно делаем первый снимок базы данных (выполняем команду экспорт).

После того, как каждый программист выполнит свою задачу на своем сайте, он делает экспорт. Так как изменения были произведены только в ИБ модуле, то и экспортировать другие модули нет смысла (Настройка config файла).

После программист делает коммит экспортируемых файлов, и перед тем как вытолкнуть файлы на удаленный репозиторий необходимо проверить, может другой программист выполнил задание быстрее (git pull).
На этом шаге, возможна ситуация возникновения конфликта. Что же, тут есть 2 пути, смотря как Вам удобней работать. Если у вас git на серверах разработки, при конфликте появится такое предупреждение:

Открываете файл, например с помощью vim (vi local/migato/iblock/type/...) и выбираете, кто из программистов не врет.

После этого индексируете файлы и коммитете.

Есть еще второй путь, если у вас гит только на локальной машине, и синхронизируете все файлы с помощью гита, но на локальной машине. На примере показано возникновение конфликта в IDE PHPStorm.

merge_migration_article

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

После того, как все программисты вытолкнули свои изменения, версия базы данных в системе управления версий стабилизируется. Это значит, что наступило время делать релиз. После которого, чтобы обновить любой сайт (будь то сайт для разработки или prod), достаточно трех глобальный вещей:

  • Выполнить pull
  • Проверить config файл (какие именно модули и сущности нам нужны)
  • Выполнить импорт данных

В результате, каждый сайт имеет актуальную версию базы данных со всеми изменениями. Будь то удаление, создание или изменение записи с конфликтами или без, наш модуль превосходно справился с поставленными задачами.

Вместо выводов

Инструмент для миграции изменений БД жизненно необходим при ответственной командной работе над проектами. До сегодняшнего дня эта задача в мире 1С-Битрикс решалась очень плохо.

Мы же разработали промышленное решение этой задачи и отдаем его бесплатно всем желающим. Пользуйтесь, предлагайте улучшения, участвуйте в развитии, мы будем рады. Чтобы получить ссылку на установку модуля миграций для Битрикс, “поделитесь” статьей в соцсетях и укажите ссылку в форму под статьей. Ссылка на репозиторий с документацией придет вам на почту.
Я «поделился» статьей, прошу прислать файл