将带有字段的字段集添加到 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,
        '供应商_产品',
        __DIR__
    );
    ?>

创建一个作曲家文件(如果您打算传输模块) app/code/Vendor/Module/composer.json :

 {
        “名称”:“供应商/模块产品”,
        “描述”:“不适用”,
        “类型”:“magento2-模块”,
        “版本”:“1.0.0”,
        “执照”: [
            "OSL-3.0",
            “AFL-3.0”
        ],
        “自动加载”:{
            “文件”:[
                “注册.php”
            ],
            “psr-4”:{
                “供应商\\产品\\”:“”
            }
        }
    }

现在,使用 Magento_Catalog 模块的依赖项创建模块的主 XML 文件 app/code/Vendor/Product/etc/module.xml,因为我们的模态窗口将添加到它的表单中:

 <?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">
            <序列>
                <module name="Magento_Catalog"/>
            </序列>
        </模块>
    </配置>

通过输入以下内容启用模块: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="修饰符" xsi:type="array">
                <item name="custom-fieldset" xsi:type="array">
                    <item name="class" xsi:type="string">Vendor\Product\Ui\DataProvider\Product\Form\Modifier\CustomFieldset</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </项目>
            </参数>
        </参数>
    </virtualType>
</配置>

修饰符负责添加数据以及对元素和 UI 表单组件进行一些操作。 修改器的接口有 2 个主要方法(它们应该始终存在):

 <?php
    /**
     * 版权所有 2016 Magento。 版权所有。
     * 有关许可证的详细信息,请参阅 COPYING.txt。
     */
    命名空间 Magento\Ui\DataProvider\Modifier;
    
    /**
     * 类修饰符接口
     */
    接口修饰符接口
    {
        /**
         * @param 数组 $data
         * @return 数组
         */
        公共函数 modifyData(数组 $data);
    
        /**
         * @param 数组 $meta
         * @return 数组
         */
        公共函数 modifyMeta(array $meta);
    }
    ?>

我们将在本例中使用 modifyMeta 方法。 modifyData 方法将在下一篇文章中解释。

现在,使用产品编辑页面的自定义字段集创建修改器文件 (app/code/Vendor/Product/Ui/DataProvider/Product/Form/Modifier/CustomFieldset.php),并用以下字段填充:

 <?php
命名空间供应商\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
{

    // 组件索引
    常量 CUSTOM_FIELDSET_INDEX = 'custom_fieldset';
    常量 CUSTOM_FIELDSET_CONTENT = 'custom_fieldset_content';
    常量 CONTAINER_HEADER_NAME = 'custom_fieldset_content_header';

    // 字段名称
    常量 FIELD_NAME_TEXT = 'example_text_field';
    常量 FIELD_NAME_SELECT = 'example_select_field';
    常量 FIELD_NAME_MULTISELECT = 'example_multiselect_field';

    /**
     * @var \Magento\Catalog\Model\Locator\LocatorInterface
     */
    受保护的$定位器;

    /**
     * @var 数组管理器
     */
    受保护的 $arrayManager;

    /**
     * @var 网址接口
     */
    受保护的 $urlBuilder;

    /**
     * @var 数组
     */
    受保护的 $meta = [];

    /**
     * @param 定位器接口 $locator
     * @param ArrayManager $arrayManager
     * @param UrlInterface $urlBuilder
     */
    公共函数 __construct(
        定位器接口 $locator,
        阵列管理器 $阵列管理器,
        网址接口 $urlBuilder
    ) {
        $this->定位器 = $定位器;
        $this->arrayManager = $arrayManager;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * 数据修饰符,在我们的示例中什么都不做。
     *
     * @param 数组 $data
     * @return 数组
     */
    公共函数 modifyData(数组 $data)
    {
        返回$数据;
    }

    /**
     * 元数据修饰符:添加我们的字段集
     *
     * @param 数组 $meta
     * @return 数组
     */
    公共函数 modifyMeta(数组 $meta)
    {
        $this->meta = $meta;
        $this->addCustomFieldset();

        返回 $this->meta;
    }

    /**
     * 将现有元数据与我们的元数据合并(不要覆盖它!)
     *
     * @return 无效
     */
    受保护的函数 addCustomFieldset()
    {
        $this->meta = array_merge_recursive(
            $this->元,
            [
                静态::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
            ]
        );
    }

    /**
     * 声明我们的字段集配置
     *
     * @return 数组
     */
    受保护的函数 getFieldsetConfig()
    {
        返回 [
            '论据' => [
                '数据' => [
                    '配置' => [
                        '标签' => __('字段集标题'),
                        'componentType' => 字段集::NAME,
                        'dataScope' => static::DATA_SCOPE_PRODUCT, // 保存产品数据中的数据
                        '提供者' => 静态::DATA_SCOPE_PRODUCT 。 '_数据源',
                        'ns' => 静态::FORM_NAME,
                        '可折叠' => 真的,
                        '排序顺序' => 10,
                        '打开' => 真的,
                    ],
                ],
            ],
            '孩子' => [
                静态::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
                静态::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
                静态::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
                静态::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
            ],
        ];
    }

    /**
     * 获取头容器的配置
     *
     * @param int $sortOrder
     * @return 数组
     */
    受保护的函数 getHeaderContainerConfig($sortOrder)
    {
        返回 [
            '论据' => [
                '数据' => [
                    '配置' => [
                        '标签' => 空,
                        'formElement' => 容器::NAME,
                        'componentType' => 容器::NAME,
                        '模板' => 'ui/form/components/complex',
                        'sortOrder' => $sortOrder,
                        'content' => __('你可以在这里写任何文字'),
                    ],
                ],
            ],
            '孩子' => [],
        ];
    }

    /**
     * 示例文本字段配置
     *
     * @param $sortOrder
     * @return 数组
     */
    受保护的函数 getTextFieldConfig($sortOrder)
    {
        返回 [
            '论据' => [
                '数据' => [
                    '配置' => [
                        'label' => __('示例文本字段'),
                        'formElement' => 字段::NAME,
                        'componentType' => 输入::NAME,
                        'dataScope' => 静态::FIELD_NAME_TEXT,
                        'dataType' => 编号::NAME,
                        'sortOrder' => $sortOrder,
                    ],
                ],
            ],
        ];
    }

    /**
     * 示例选择字段配置
     *
     * @param $sortOrder
     * @return 数组
     */
    受保护的函数 getSelectFieldConfig($sortOrder)
    {
        返回 [
            '论据' => [
                '数据' => [
                    '配置' => [
                        '标签' => __('选项选择'),
                        'componentType' => 字段::NAME,
                        'formElement' => 选择::名称,
                        'dataScope' => 静态::FIELD_NAME_SELECT,
                        'dataType' => 文本::NAME,
                        'sortOrder' => $sortOrder,
                        '选项' => $this->_getOptions(),
                        '可见' => 真,
                        '禁用' => 假,
                    ],
                ],
            ],
        ];
    }

    /**
     * 示例多选字段配置
     *
     * @param $sortOrder
     * @return 数组
     */
    受保护的函数 getMultiSelectFieldConfig($sortOrder)
    {
        返回 [
            '论据' => [
                '数据' => [
                    '配置' => [
                        '标签' => __('选项多选'),
                        'componentType' => 字段::NAME,
                        'formElement' => MultiSelect::NAME,
                        'dataScope' => 静态::FIELD_NAME_MULTISELECT,
                        'dataType' => 文本::NAME,
                        'sortOrder' => $sortOrder,
                        '选项' => $this->_getOptions(),
                        '可见' => 真,
                        '禁用' => 假,
                    ],
                ],
            ],
        ];
    }

    /**
     * 获取示例选项作为选项数组:
     * [
     * 标签 => 字符串,
     * 值 => option_id
     * ]
     *
     * @return 数组
     */
    受保护的函数 _getOptions()
    {
        $选项= [
            1 => [
                '标签' => __('选项 1'),
                '价值' => 1
            ],
            2 => [
                '标签' => __('选项 2'),
                '价值' => 2
            ],
            3 => [
                '标签' => __('选项 3'),
                '价值' => 3
            ],
        ];

        返回$选项;
    }
}
?>

在此示例中,我们需要获取现有的 UI 表单元数据并将其与我们的新数据合并(而不是重写!):

 <?php
/**
 * 将现有元数据与我们的元数据合并(不要覆盖它!)
 *
 * @return 无效
 */
受保护的函数 addCustomFieldset()
{
    $this->meta = array_merge_recursive(
        $this->元,
        [
            静态::CUSTOM_FIELDSET_INDEX => $this->getFieldsetConfig(),
        ]
    );
}
?>

完成后,将新字段集添加到 getFieldsetConfig 方法:

 <?php
/**
 * 声明我们的字段集配置
 *
 * @return 数组
 */
受保护的函数 getFieldsetConfig()
{
    返回 [
        '论据' => [
            '数据' => [
                '配置' => [
                    '标签' => __('字段集标题'),
                    'componentType' => 字段集::NAME,
                    'dataScope' => static::DATA_SCOPE_PRODUCT, // 保存产品数据中的数据
                    '提供者' => 静态::DATA_SCOPE_PRODUCT 。 '_数据源',
                    'ns' => 静态::FORM_NAME,
                    '可折叠' => 真的,
                    '排序顺序' => 10,
                    '打开' => 真的,
                ],
            ],
        ],
        '孩子' => [
            静态::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
            静态::FIELD_NAME_TEXT => $this->getTextFieldConfig(20),
            静态::FIELD_NAME_SELECT => $this->getSelectFieldConfig(30),
            静态::FIELD_NAME_MULTISELECT => $this->getMultiSelectFieldConfig(40),
        ],
    ];
}
?>

我们从抽象产品 UI-form 修饰符继承,并将其命名空间和数据用作提供者:'provider' => static::DATA_SCOPE_PRODUCT。 '_data_source'(其中 DATA_SCOPE_PRODUCT 是 'data.product' 行)。

componentType 选项是主要选项之一,负责组件类型。 collapsible 选项负责折叠和扩展我们的字段集。 并且 open 选项定义了在表单绘制过程中字段集是否默认打开。

然后,我们因此在 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" />
    </事件>
</配置>

然后,创建我们在实例属性中指向的观察者类——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 $observer
     */
    公共函数执行(\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);

        // 在这里操作数据
    }
}
?>

观察者中的数据:

现在,您可以从观察者调用自己的模型并将数据保存在其中或根据需要进行修改。

当心! 如果你的模型的保存与产品的保存有关,那么它可能会导致递归。