Так вот, ближе к делу. В версии Magento 2.3 и выше появилась такая «плюшка» как декларативная схема. Что же это такое декларативная схема? Если мы обратимся к документации мадженто, то там черным по белому написано — «Декларативая схема направлена на упрощение процессов установки и обновления Magento.»
Вроде бы все здорово, ведь раньше разработчикам приходилось писать очень много install и upgrade скриптов (в М1 вообще был маленький кошмар с ними), вплоть до версии 2.3 нужно было в зависимости от задач держать N-количество скриптов, а именно:
InstallSchema — этот класс запускается при установке модуля для настройки структуры базы данных
InstallData — этот класс запускается при установке модуля для инициализации данных таблицы базы данных.
UpgradeSchema — этот класс запускается при обновлении модуля для настройки структуры базы данных
UpgradeData — этот класс запускается при обновлении модуля для добавления / удаления данных из таблицы.
Uninstall — этот класс запускается для удаления данных и таблиц из базы.
Согласитесь это уже лучше чем для каждого чиха писать отдельный скрипт. Но и это оказалось не очень удобно, так как приходилось следить за версионностью, отслеживать и понимать что у тебя содержится в этих скриптах, и к тому же они разростались в огромные «портянки» на 4000+ строк. В итоге и этот подход оказался довольно провальным. Количесто файлов сократилось, но количество строк кода увеличилось.
Тут то и пришла на помощь декларативная схема. По факту все свелось к одному файлу — db_schema.xml. В котором Вы храните конечное состояние базы данных. То есть если Вам для модуля нужна кастомная таблица, вы описываете нужные поля в данном файле и все. Дальше маджента сама для Вас создаст таблицу. В случае если Вам нужно обновить уже созданную ранее таблицу, Вы просто вносите правки в файл db_schema.xml и все (магия произойдет сама). Не нужно следить за версионностью, не нужно для каждой новой версии модуля писать скрипты обновления базы, по факту не нужно делать лишних операция. Согласитесь — это круто.
Но ведь не бывает бочки дегтя, без ложки дегтя. (это не опечатка, кто работает с мадженто меня поймет)
Декларативная схема хороша только при работе с кастомными таблицами. Если вам нужно добавить програмно атрибут в продукт или категорию, сделать INSERT или UPDATE, или в конце концов изменить что-то в Schema — будьте любезны написать патчи. О них ниже и поговорим.
Для примера рассмотрим добавление кастомного атрибута для продукта.
1. Начнем с того что в модуле создадим следующий класс:
SetupPatchDataAddAlternativeNameAttribute.php
Который для начала будет содержать следющий контент
<?php
namespace FooBarSetupPatchData;
use MagentoEavSetupEavSetupFactory;
use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupPatchDataPatchInterface;
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 FooBarSetupPatchData;
use MagentoEavSetupEavSetup;
use MagentoEavSetupEavSetupFactory;
use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupPatchDataPatchInterface;
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, равным значению нашего класса (FooBarSetupPatchDataAddAlternativeNameAttribute).
6. Удаление значения из таблицы patch_list приведет к повторному выполнению патча при запуске установки bin/magento setup:upgrade. Данная функциональность будет полезна при отладке патчей.
Итог:
+ Декларативная схема упрощает работу с кастомными таблицами
+ Отсутствие надобности следить за версионностью
+ Легкий апгред данных в таблицах и кастомизация полей таблиц
— Отсутствие возможности добавлять атрибуты в продукт-категорию через декларативную схему
— Если модуль универсальный для версий 2.1, 2.2, 2.3 придется писать и декларативную схему и инсталл скрипты.
— Необходимость написания патчей для работы с core’вскими таблицами.
Возможно в обозримом будущем, когда M2 полностью перейдет на декларативную схему и отпадет надобность писать патчи, это будет супер удобно. Но будет ли это и когда случится, вопрос остается открытым.