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


ссылка на оригинал статьи https://habr.com/ru/post/462795/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *