Декларативная схема и что с ней не так в Magento 2

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

    Так вот, ближе к делу. В версии 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 полностью перейдет на декларативную схему и отпадет надобность писать патчи, это будет супер удобно. Но будет ли это и когда случится, вопрос остается открытым.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 5

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


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

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

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

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

        0
        Меня не так смущает то что атрибуты нужно устанавливать через патчи, а то, что сами патчи это отдельные классы. Вот например ситуация: Я установил новый аттрибут для карегории (то есть создал новый класс InstallCategoryAttribute), этот патч был задеплоений на дев сервер и во время тестирования оказалось, что я как-то не правильно установил данный атрибут. Ок, я делаю UpdateCategoryAttribute снова это все идет на дев сервер — и тут оказывается опять что-то не так с моим атрибутом. И вот тут не понятно как его снова проапдейтить плавильно, UpdateCategoryAttribute2?
          0
          Ну самый плохой вариант с patch_list удалить запись и переписать патч. Ну а вообще думаю UpdateCategoryAttribute + ChangeDescription нормальный вариант .
          0
          — Отсутствие возможности добавлять атрибуты в продукт-категорию через декларативную схему
          А что в более ранних версиях можно было?
          Нельзя было создавать атрибуты в InstallSchema скриптах, нужно было в InstallData.
          Выходит что патчи это прямой наследник InstallData. И декларативная схема как была тут ни при чём, так и осталась.
          — Если модуль универсальный для версий 2.1, 2.2, 2.3 придется писать и декларативную схему и инсталл скрипты.
          Нет, не нужно писать и то, и другое, достаточно написать проверки, к примеру проверка версии модуля.
          Необходимость написания патчей для работы с core'вскими таблицами.
          Это делать можно в своем модуле, для данных — патчи.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое