Усовершенствования в управлении схемой базы данных

Еще когда мы рассказывали о нововведениях "под капотом" XenForo 2.4, мы упомянули, что сосредоточимся на инструментах для разработчиков и функциях, которые уже стали стандартом в других фреймворках, таких как Laravel. Сегодняшний выпуск HYS посвящен очень важному аспекту в этом плане: миграциям схемы базы данных.

Если вы когда-либо использовали миграции практически в любом другом современном фреймворке, всё это покажется вам очень знакомым. Если нет — не беспокойтесь, концепция проста.

Что такое миграция?​

Миграция — это небольшой файл, описывающий одно изменение в базе данных. Добавление таблицы, добавление столбца, изменение индекса, преобразование некоторых данных — что-то в этом роде. Каждая миграция имеет метод up(), который вносит изменение, и, опционально, метод down(), который его отменяет.

Миграции хранятся в каталоге _migrations вашего дополнения; они именуются с использованием временной метки, поэтому всегда запускаются в том порядке, в котором были написаны, а XenForo регистрирует каждую из них по мере выполнения. Это означает, что XenForo всегда точно знает, какие изменения уже внесены в форум, а какие ещё предстоит внести.

Выполнение миграции​

Для этого появилась новая команда make:

Код:
php cmd.php xf-make:migration --addon=Demo/Portal add_view_count

В результате у вас появится новый файл, например, src/addons/Demo/Portal/_migrations/2026_10_08_141500_add_view_count.php. Заполните методы up() и down(), используя привычный вам менеджер схем:
PHP:
<?php

declare(strict_types=1);

use XF\Db\Migration\AbstractMigration;
use XF\Db\Schema\Alter;

return new class extends AbstractMigration
{
    public function up(): void
    {
        $this->alterTable('xf_demo_portal_item', function (Alter $table): void
        {
            $table->addColumn('view_count', 'int')->setDefault(0);
        });
    }

    public function down(): void
    {
        $this->alterTable('xf_demo_portal_item', function (Alter $table): void
        {
            $table->dropColumns('view_count');
        });
    }
};
И это всё. Никаких методов обновления, названных по идентификаторам версий, никакой необходимости запоминать, на каком этапе вы находитесь, и, как и во всём, что использует менеджер схем и конструктор запросов, это работает независимо от того, используете ли вы MySQL или SQLite.

Запуск миграций​

Для администраторов миграции просто запускаются в рамках установки или обновления дополнения — именно там, где сегодня запускаются этапы обновления, будь то в панели управления администратора, в командной строке или при пакетной установке.

Для разработчиков предусмотрено несколько команд командной строки, которые упростят работу:
  • xf-migrate:run запускает все ожидающие выполнения миграции
  • xf-migrate:status показывает, какие миграции уже выполнены, а какие находятся в очереди
  • xf-migrate:rollback отменяет последнюю партию миграций — это нужно, если вам требуется повторить миграцию, которую вы ещё пишете
Кроме того, миграции не привязаны к номеру версии вашего дополнения. Каждая из них отслеживается отдельно, поэтому вы можете добавить миграцию, запустить её, откорректировать, отменить и запустить заново, не повышая при этом номер версии каждый раз. Если у дополнения есть ожидающая выполнения миграция, XenForo предложит обновить его, даже если версия не изменилась.

Более масштабные изменения​

Некоторые изменения затрагивают большой объём данных — например, заполнение нового столбца для каждой строки. Вместо того чтобы пытаться выполнить всё за один раз и надеяться, что запрос не превысит лимит времени, в миграции можно реализовать метод batch() и обрабатывать данные по частям:
PHP:
public function batch(MigrationBatch $batch): bool
{
    $ids = \XF::query('xf_demo_portal_item')
        ->select('item_id')
        ->where('item_id', '>', $batch->position)
        ->orderBy('item_id')
        ->limit(500)
        ->fetchAllColumn();

    if (!$ids)
    {
        return true;
    }

    // ... update this batch of rows ...

    $batch->advance(end($ids));

    return false;
}
Ход выполнения сохраняется после каждой транзакции, поэтому в случае прерывания обновления процесс возобновляется с того места, на котором остановился. Если вам нужно запустить какую-либо задачу вне самого процесса миграции, в рамках миграции также можно поставить задачи в очередь: либо для выполнения до повторной активации дополнения (insertImmediateUpgradeJob()), либо для последующего выполнения в фоновом режиме (insertPostUpgradeJob()).

Что это значит для администраторов?​

Что очень важно — практически ничего :) Установка и обновление работают точно так же, как и сейчас. Главное, что вы, возможно, заметите, — это то, что крупные обновления стали чуть более терпимыми к сбоям, поскольку выполняются небольшими шагами и возобновляются, если что-то их прерывает.

Что это значит для разработчиков?
Прежде всего, ничто из того, что у вас есть сегодня, не перестанет работать. Ваш класс Setup, его этапы установки и обновления работают точно так же, как и раньше, и вы можете начать использовать миграции, когда будете готовы.

Несколько моментов, о которых стоит знать, когда вы это сделаете:
  • При новой установке сначала выполняются этапы установки из вашего Setup, а затем поверх них запускаются ваши миграции. Поэтому самый простой подход — оставить код установки как есть и вносить любые будущие изменения в виде миграций. Совершенно новому дополнению вообще не нужны этапы установки — оно может состоять исключительно из миграций.
  • Если ваш код установки уже создаёт вашу последнюю схему, вы можете вернуть true из метода installIncludesMigrations() в вашем классе Setup, и ваши миграции будут помечены как выполненные при установке, а не запущены.
  • Деинсталляция по-прежнему осуществляется через Setup::uninstall(). Миграции не отменяются при удалении дополнения.
  • Как только у вашего дополнения появятся миграции, xf-addon:build-release не позволит вам добавлять новые шаги обновления для выпускаемой версии. Шаги обновления всегда запускаются до миграций, поэтому смешивание этих двух процессов может привести к тому, что шаг обновления запустится до изменения, на котором он основан.

Одновременная поддержка XenForo 2.3 и 2.4​

XenForo 2.3 не распознает процесс миграции, поэтому просто проигнорирует ваш каталог _migrations. Если одна версия вашего дополнения поддерживает как 2.3, так и 2.4, любые изменения в базе данных по-прежнему должны быть реализованы в виде шагов обновления, чтобы форумы на версии 2.3 также получили их. Шаги обновления продолжают работать в версии 2.4, поэтому это совершенно нормально.

Итак, наша рекомендация такова:
  • Пока ваше дополнение поддерживает XenForo 2.3, продолжайте использовать шаги обновления.
  • Начиная с первой версии, требующей XenForo 2.4 (2040010 в разделе require вашего файла addon.json), перейдите на миграции.
Нет необходимости преобразовывать какие-либо из ваших существующих шагов обновления. Они остаются на своих местах и продолжают выполнять свою работу для всех, кто обновляется с более старой версии.
А что насчёт самого XenForo?
Мы тоже перешли на новую версию. Все изменения в базе данных в XenForo 2.4 записаны в виде миграций, и наши данные установки теперь генерируются на их основе, что, как приятный побочный эффект, означает, что при новой установке и обновлении форума база данных всегда получается абсолютно одинаковой.

1792636219627.png

Как всегда, если у вас возникнут вопросы, оставляйте их ниже. Мы с нетерпением ждем, чтобы увидеть, когда авторы это всё сделают!
 
Современный облачный хостинг провайдер | Aéza
Назад
Сверху Снизу