Простой способ добавить набор полей с полями в 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); // Работа с данными здесь } } ?>
Данные в обозревателе:
Теперь вы можете вызвать свою собственную модель из наблюдателя и сохранить в ней данные или изменить ее по своему усмотрению.
Будь осторожен! Если сохранение вашей модели связано с сохранением товара, то это может привести к рекурсии.