Простой способ добавить набор полей с полями в UI-форму
Опубликовано: 2016-08-23В этой статье мы собираемся создать простой модуль, который добавит набор полей в UI-форму редактирования товара. Также мы создадим наблюдатель для перехвата этих данных при сохранении товара.
Во-первых, нам нужно создать модуль Vendor_Product:
1. Создайте каталог app/code/Vendor/Product.
2. Создайте регистрационный файл app/code/Vendor/Product/registration.php со следующим содержимым:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Продукт_Поставщика',
__КАТАЛОГ__
);
?>Создайте файл композитора (если вы планируете перенести модуль) app/code/Vendor/Module/composer.json:
{
"name": "поставщик/модуль-продукт",
"описание": "Н/Д",
"тип": "magento2-модуль",
"версия": "1.0.0",
"лицензия": [
«ОСЛ-3.0»,
«АФЛ-3.0»
],
"автозагрузка": {
"файлы": [
"регистрация.php"
],
"пср-4": {
"Поставщик\\Продукт\\": ""
}
}
}Теперь создадим основной XML-файл модуля app/code/Vendor/Product/etc/module.xml с зависимостью от модуля Magento_Catalog, потому что наше модальное окно будет добавлено в его форму:
<?xml версия="1.0"?>
<config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Vendor_Product" setup_version="1.0.0">
<последовательность>
<имя модуля="Magento_Catalog"/>
</последовательность>
</модуль>
</config>Включите модуль, введя следующее: bin/magento module:enable Vendor_Product и bin/magento setup:upgrade в корневом каталоге Magento.
Затем добавьте содержимое модуля: метаданные UI-формы и виртуальный тип для ее добавления.
Создайте файл app/code/Vendor/Product/etc/adminhtml/di.xml. Внутри мы поместим модификатор:
<?xml версия="1.0"?>
<config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
<аргументы>
<argument name="modifiers" xsi:type="array">
<item name="custom-fieldset" xsi:type="array">
<item name="class" xsi:type="string">Поставщик\Продукт\Ui\DataProvider\Product\Form\Modifier\CustomFieldset</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</аргумент>
</аргументы>
</ виртуальный тип>
</config>Модификатор отвечает за добавление данных и некоторые манипуляции с элементами и компонентами UI-формы. Есть 2 основных метода, которые пришли из интерфейса модификатора (они всегда должны присутствовать):
<?php
/**
* Copyright 2016 Magento. Все права защищены.
* Подробнее о лицензии см. COPYING.txt.
*/
пространство имен Magento\Ui\DataProvider\Modifier;
/**
* Интерфейс модификатора класса
*/
Модификатор интерфейсаИнтерфейс
{
/**
* @param массив $данные
* @возвратный массив
*/
публичная функция modifyData(массив $data);
/**
* массив @param $meta
* @возвратный массив
*/
публичная функция modifyMeta(массив $meta);
}
?>В этом примере мы собираемся использовать метод ModifyMeta. МетодmodifyData будет объяснен в следующей статье.
Теперь создайте файл модификатора (app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php) с пользовательским набором полей для страницы редактирования продукта и заполните его полями:
<?php
пространство имен Vendor\Product\Ui\DataProvider\Product\Form\Modifier;
используйте Magento\Catalog\Model\Locator\LocatorInterface;
используйте Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
используйте Magento\Framework\Stdlib\ArrayManager;
используйте Magento\Framework\UrlInterface;
используйте Magento\Ui\Component\Container;
используйте Magento\Ui\Component\Form\Fieldset;
используйте Magento\Ui\Component\Form\Element\DataType\Number;
используйте Magento\Ui\Component\Form\Element\DataType\Text;
используйте Magento\Ui\Component\Form\Element\Input;
используйте Magento\Ui\Component\Form\Element\Select;
используйте Magento\Ui\Component\Form\Element\MultiSelect;
используйте Magento\Ui\Component\Form\Field;
класс CustomFieldset расширяет AbstractModifier
{
// Индексы компонентов
const CUSTOM_FIELDSET_INDEX = 'custom_fieldset';
const CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
const CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';
// Имена полей
const FIELD_NAME_TEXT = 'example_text_field';
const FIELD_NAME_SELECT = 'example_select_field';
const FIELD_NAME_MULTISELECT = 'example_multiselect_field';
/**
* @var \Magento\Каталог\Модель\Локатор\ЛокаторИнтерфейс
*/
защищенный $локатор;
/**
* @var Менеджер массивов
*/
защищенный $arrayManager;
/**
* @var УрлИнтерфейс
*/
защищенный $urlBuilder;
/**
* массив @var
*/
защищенный $ мета = [];
/**
* @param LocatorInterface $locator
* @param ArrayManager $arrayManager
* @param UrlInterface $urlBuilder
*/
публичная функция __construct(
LocatorInterface $ локатор,
Менеджер массивов $Менеджер массивов,
УрлИнтерфейс $urlBuilder
) {
$this->locator = $locator;
$this->arrayManager = $arrayManager;
$this->urlBuilder = $urlBuilder;
}
/**
* Модификатор данных, в нашем примере ничего не делает.
*
* @param массив $данные
* @возвратный массив
*/
публичная функция modifyData(массив $data)
{
вернуть $данные;
}
/**
* Модификатор метаданных: добавляет наш набор полей
*
* массив @param $meta
* @возвратный массив
*/
публичная функция modifyMeta(массив $meta)
{
$this->meta = $meta;
$this->addCustomFieldset();
вернуть $this->meta;
}
/**
* Объединить существующие метаданные с нашими метаданными (не перезаписывать их!)
*
* @возврат недействителен
*/
защищенная функция addCustomFieldset()
{
$this->meta = array_merge_recursive(
$это->мета,
[
static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
]
);
}
/**
* Объявить нашу конфигурацию fieldset
*
* @возвратный массив
*/
защищенная функция getFieldsetConfig()
{
возвращаться [
'аргументы' => [
'данные' => [
'конфигурация' => [
'метка' => __('Заголовок набора полей'),
'componentType' => Набор полей::ИМЯ,
'dataScope' => static::DATA_SCOPE_PRODUCT, // сохраняем данные в данных о товаре
'поставщик' => static::DATA_SCOPE_PRODUCT . '_источник данных',
'ns' => static::FORM_NAME,
'складной' => правда,
'сортировка' => 10,
'открыто' => правда,
],
],
],
'дети' => [
static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
static::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
static::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
static::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
],
];
}
/**
* Получить конфигурацию для контейнера заголовков
*
* @param int $sortOrder
* @возвратный массив
*/
защищенная функция getHeaderContainerConfig($sortOrder)
{
возвращаться [
'аргументы' => [
'данные' => [
'конфигурация' => [
'метка' => ноль,
'formElement' => Контейнер::ИМЯ,
'componentType' => Контейнер::ИМЯ,
'template' => 'пользовательский интерфейс/форма/компоненты/комплекс',
'сортировка' => $sortOrder,
'content' => __('Здесь можно написать любой текст'),
],
],
],
'дети' => [],
];
}
/**
* Пример конфигурации текстового поля
*
* @param $sortOrder
* @возвратный массив
*/
защищенная функция getTextFieldConfig($sortOrder)
{
возвращаться [
'аргументы' => [
'данные' => [
'конфигурация' => [
'метка' => __('Пример текстового поля'),
'formElement' => Поле::ИМЯ,
'componentType' => Input::NAME,
'dataScope' => static::FIELD_NAME_TEXT,
'dataType' => Число::ИМЯ,
'сортировка' => $sortOrder,
],
],
],
];
}
/**
* Пример конфигурации поля выбора
*
* @param $sortOrder
* @возвратный массив
*/
защищенная функция getSelectFieldConfig($sortOrder)
{
возвращаться [
'аргументы' => [
'данные' => [
'конфигурация' => [
'метка' => __('Выбор параметров'),
'componentType' => Поле::ИМЯ,
'formElement' => Выбрать::ИМЯ,
'dataScope' => static::FIELD_NAME_SELECT,
'dataType' => Текст::ИМЯ,
'сортировка' => $sortOrder,
'опции' => $this->_getOptions(),
'видимый' => правда,
'отключено' => ложь,
],
],
],
];
}
/**
* Пример конфигурации поля множественного выбора
*
* @param $sortOrder
* @возвратный массив
*/
защищенная функция getMultiSelectFieldConfig($sortOrder)
{
возвращаться [
'аргументы' => [
'данные' => [
'конфигурация' => [
'label' => __('Множественный выбор опций'),
'componentType' => Поле::ИМЯ,
'formElement' => MultiSelect::NAME,
'dataScope' => static::FIELD_NAME_MULTISELECT,
'dataType' => Текст::ИМЯ,
'сортировка' => $sortOrder,
'опции' => $this->_getOptions(),
'видимый' => правда,
'отключено' => ложь,
],
],
],
];
}
/**
* Получить примеры опций в виде массива опций:
* [
* метка => строка,
* значение => option_id
* ]
*
* @возвратный массив
*/
защищенная функция _getOptions()
{
$ параметры = [
1 => [
'метка' => __('Вариант 1'),
'значение' => 1
],
2 => [
'метка' => __('Вариант 2'),
'значение' => 2
],
3 => [
'метка' => __('Вариант 3'),
'значение' => 3
],
];
вернуть $options;
}
}
?>
В этом примере нам нужно взять существующие метаданные UI-формы и объединить их (не переписывать!) с нашими новыми данными:

<?php
/**
* Объединить существующие метаданные с нашими метаданными (не перезаписывать их!)
*
* @возврат недействителен
*/
защищенная функция addCustomFieldset()
{
$this->meta = array_merge_recursive(
$это->мета,
[
static::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
]
);
}
?>Когда закончите, добавьте новый набор полей в метод getFieldsetConfig:
<?php
/**
* Объявить нашу конфигурацию fieldset
*
* @возвратный массив
*/
защищенная функция getFieldsetConfig()
{
возвращаться [
'аргументы' => [
'данные' => [
'конфигурация' => [
'метка' => __('Заголовок набора полей'),
'componentType' => Набор полей::ИМЯ,
'dataScope' => static::DATA_SCOPE_PRODUCT, // сохраняем данные в данных о товаре
'поставщик' => static::DATA_SCOPE_PRODUCT . '_источник данных',
'ns' => static::FORM_NAME,
'складной' => правда,
'сортировка' => 10,
'открыто' => правда,
],
],
],
'дети' => [
static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
static::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
static::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
static::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
],
];
}
?>Мы наследуем модификатор UI-формы абстрактного продукта и используем его пространство имен и данные в качестве провайдера: 'provider' => static::DATA_SCOPE_PRODUCT . «_data_source» (где DATA_SCOPE_PRODUCT — это строка «data.product»).
Параметр componentType является одним из основных и отвечает за тип компонента. Сворачиваемая опция отвечает за свертывание и расширение нашего набора полей. И опция открытия определяет, будет ли набор полей открыт по умолчанию во время рисования формы.
Затем мы последовательно добавляем заголовок к нашему набору полей в методе getHeaderContainerConfig и 3 примера полей: текст, выбор и множественный выбор. Однако наш продукт и форма не будут получать данные, пока мы не добавим их в методmodifyData. Но у нас есть возможность передавать и перехватывать данные во время сохранения.
Посмотрим, как выглядит форма:
Сохранение данных происходит внутри файла контроллера продукта vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php в основном методе выполнения. Если все сделано правильно, то наши данные будут корректно отображаться во входных данных этого метода:
Обратите внимание: если у вашего продукта изначально не было этих атрибутов, вам следует сохранить их вручную. Это можно сделать в наблюдателе.
Во-первых, объявите его в файле app/code/Vendor/Product/etc/adminhtml/events.xml (мы используем область adminhtml, потому что форма не существует во внешнем интерфейсе):
<?xml версия="1.0"?>
<config xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="catalog_product_save_after">
<observer name="save_example_data" instance="Vendor\Product\Observer\ProductSaveAfter" />
</событие>
</config>Затем создайте класс наблюдателя, который мы указали в атрибуте экземпляра — app/code/Vendor/Product/Observer/ProductSaveAfter.php:
<?php
пространство имен Поставщик\Продукт\Обозреватель;
используйте \Magento\Framework\Event\ObserverInterface;
используйте \Magento\Framework\Event\Observer как EventObserver;
используйте Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset;
класс ProductSaveAfter реализует ObserverInterface
{
/**
* @param EventObserver $наблюдатель
*/
выполнение публичной функции (\Magento\Framework\Event\Observer $observer)
{
/** @var \Magento\Catalog\Model\Product $product */
$product = $observer->getEvent()->getProduct();
если (! $ продукт) {
возвращаться;
}
$exampleTextField = $product->getData(CustomFieldset::FIELD_NAME_TEXT);
$exampleSelectField = $product->getData(CustomFieldset::FIELD_NAME_SELECT);
$exampleMultiSelectField = $product->getData(CustomFieldset::FIELD_NAME_MULTISELECT);
// Работа с данными здесь
}
}
?>Данные в обозревателе:

Теперь вы можете вызвать свою собственную модель из наблюдателя и сохранить в ней данные или изменить ее по своему усмотрению.
Будь осторожен! Если сохранение вашей модели связано с сохранением товара, то это может привести к рекурсии.
