Всем привет. Данная публикация не претендует на звание истины в первой инстанции, а лишь является моим личным мнением, если вы его разделяете отлично, если нет — прошу в комментарии для обсуждения.

Так вот, ближе к делу. В версии Magento 2.3 и выше появилась такая «плюшка» как декларативная схема. Что же это такое декларативная схема? Если мы обратимся к документации мадженто, то там черным по белому написано — «Декларативая схема направлена на упрощение процессов установки и обновления Magento».

Вроде бы все здорово, ведь раньше разработчикам приходилось писать очень много install и upgrade скриптов (в М1 вообще был маленький кошмар с ними), вплоть до версии 2.3 нужно было в зависимости от задач держать энное количество скриптов, а именно:

InstallSchema — этот класс запускается при установке модуля для настройки структуры базы данных
InstallData — этот класс запускается при установке модуля для инициализации данных таблицы базы данных.
UpgradeSchema — этот класс запускается при обновлении модуля для настройки структуры базы данных
UpgradeData — этот класс запускается при обновлении модуля для добавления / удаления данных из таблицы.
Uninstall — этот класс запускается для удаления данных и таблиц из базы.

Согласитесь, это уже лучше чем для каждого чиха писать отдельный скрипт. Но и это оказалось не очень удобно, так как приходилось следить за версионностью, отслеживать и понимать что у тебя содержится в этих скриптах, и к тому же они разростались в огромные «портянки» на 4000+ строк. В итоге и этот подход оказался довольно провальным. Количество файлов сократилось, но количество строк кода увеличилось.

Тут то и пришла на помощь декларативная схема. По факту все свелось к одному файлу — db_schema.xml. В котором вы храните конечное состояние базы данных. То есть если вам для модуля нужна кастомная таблица, вы описываете нужные поля в данном файле и все. Дальше маджента сама для вас создаст таблицу. В случае если вам нужно обновить уже созданную ранее таблицу, вы просто вносите правки в файл db_schema.xml и все (магия произойдет сама). Не нужно следить за версионностью, не нужно для каждой новой версии модуля писать скрипты обновления базы, по факту не нужно делать лишних операция. Согласитесь — это круто.

Но ведь не бывает бочки дегтя без ложки дегтя. (Это не опечатка, кто работает с мадженто меня поймет :) ).

Декларативная схема хороша только при работе с кастомными таблицами. Если вам нужно добавить программно атрибут в продукт или категорию, сделать INSERT или UPDATE, или в конце концов изменить что-то в Schema — будьте любезны написать патчи. О них ниже и поговорим.

Для примера рассмотрим добавление кастомного атрибута для продукта.

1. Начнем с того, что в модуле создадим следующий класс:
Setup\Patch\Data\AddAlternativeNameAttribute.php

Который для начала будет содержать следующий контент

<?php
namespace Foo\Bar\Setup\Patch\Data;

use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddAlternativeNameAttribute implements DataPatchInterface
{
    /** @var ModuleDataSetupInterface */
    private $moduleDataSetup;

    /** @var EavSetupFactory */
    private $eavSetupFactory;

    /**
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $eavSetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->eavSetupFactory = $eavSetupFactory;
    }
}

DataPatchInterface ожидает реализации трех функций: apply, getDependencies и getAliases.

2. Функция apply — место, где создаются элементы атрибутов. Теперь нет необходимости здесь вызывать функции startSetup и endSetup, ведь мы только создаем атрибуты. Для этого создаем экземпляр EavSetupFactory, передавая наш объект moduleDataSetup, и добавляем наш атрибут:

    /**
     * {@inheritdoc}
     */
    public function apply()
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);

        $eavSetup->addAttribute('catalog_product', 'alternative_name', [
            'type' => 'varchar',
            'label' => 'Alternative Name',
            'input' => 'text',
            'used_in_product_listing' => true,
            'user_defined' => true,
        ]);
    }

3. Функция getDependencies ожидает массив строк, который содержит имена классов зависимостей. Это новая функциональность, которая появилась специально для сценариев декларативной схемы, и она сообщает Magento, что нужно выполнить «патчи», которые мы здесь определили, перед нашим скриптом установки. Вот как Magento контролирует порядок выполнения скриптов патча.

    /**
     * {@inheritdoc}
     */
    public static function getDependencies()
    {
        return [];
    }

4. Последняя функция getAliases, которая определяет псевдонимы для этого патча. Поскольку мы больше не указываем номера версий, имя нашего класса может измениться, и если это произойдет, мы должны указать здесь старое имя класса, чтобы оно не выполнялось во второй раз (патчи запускаются только один раз)

    /**
     * {@inheritdoc}
     */
    public function getAliases()
    {
        return [];
    }

Итоговый класс будет выглядеть вот так:

<?php
namespace Foo\Bar\Setup\Patch\Data;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddAlternativeNameAttribute implements DataPatchInterface
{
    /** @var ModuleDataSetupInterface */
    private $moduleDataSetup;

    /** @var EavSetupFactory */
    private $eavSetupFactory;

    /**
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $eavSetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function apply()
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);

        $eavSetup->addAttribute('catalog_product', 'alternative_name', [
            'type' => 'varchar',
            'label' => 'Alternative Name',
            'input' => 'text',
            'used_in_product_listing' => true,
            'user_defined' => true,
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public static function getDependencies()
    {
        return [];
    }

    /**
     * {@inheritdoc}
     */
    public function getAliases()
    {
        return [];
    }
}

5. Теперь запускаем bin/magento setup:upgrade для того, чтобы наш патч применился. Для всех патчей, которые успешно выполнены, Magento вставляет запись в таблицу базы данных patch_list со значением поля patch_name, равным значению нашего класса (Foo\Bar\Setup\Patch\Data\AddAlternativeNameAttribute).

6. Удаление значения из таблицы patch_list приведет к повторному выполнению патча при запуске установки bin/magento setup:upgrade. Данная функциональность будет полезна при отладке патчей.

Итог:

+ Декларативная схема упрощает работу с кастомными таблицами
+ Отсутствие надобности следить за версионностью
+ Легкий апгрейд данных в таблицах и кастомизация полей таблиц

— Отсутствие возможности добавлять атрибуты в продукт-категорию через декларативную схему
— Если модуль универсальный для версий 2.1, 2.2, 2.3 придется писать и декларативную схему и инсталл скрипты.
— Необходимость написания патчей для работы с core'вскими таблицами.

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

Комментарии (2)


  1. maghamed
    09.08.2019 19:52

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


    Вполне себе решенный вопрос, Magento 2.1 уже не поддерживается, а Мадженто 2.2 будет поддерживаться до декабря 2019 года, т.е. остался последний патч релиз 2.2.10 который выйдет в ближайший месяц.

    magento.com/sites/default/files/magento-software-lifecycle-policy.pdf

    Так что можете восприниматься, что М2 уже фактически полностью перешла на декларативную схему. Вопрос остается только с кастомизациями и экстеншенам, но с момента EOF 2.2 и они подтянутся.


    1. aleeyt Автор
      09.08.2019 20:48

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