UI组件文件中的“源”项目是什么


17

在Magento 2的UI表单组件配置文件中,您经常会item在下面看到与source- 相同的属性<item name="source" xsi:type="string">block</item>

#File: vendor/magento/module-cms/view/adminhtml/ui_component/cms_block_form.xml
<field name="title">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="dataType" xsi:type="string">text</item>
            <item name="label" xsi:type="string" translate="true">Block Title</item>
            <item name="formElement" xsi:type="string">input</item>
            <item name="source" xsi:type="string">block</item>
            <item name="sortOrder" xsi:type="number">20</item>
            <item name="dataScope" xsi:type="string">title</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
        </item>
    </argument>
</field>    

这些字段是做什么用的?我问,因为似乎没有必要。例如,此GitHub存储库中的模块 配置了一个有效的UI组件表格,但未使用这些name="source"项目。

有人知道这些name="source"物品是干什么用的吗?我知道UI组件机制采用XML并将其配置为x-magento-initJSON

"block_id": {
    "type": "form.input",
    "name": "block_id",
    "dataScope": "block_id",
    "config": {
        "component": "Magento_Ui\/js\/form\/element\/abstract",
        "template": "ui\/form\/field",
        "visible": false,
        "dataType": "text",
        "formElement": "input",
        "source": "block"
    }
},

将其馈送到uiElement基于的Knockout视图模型对象中。但是,尚不清楚uiElement基于Knockout视图模型对象的嵌套树如何使用这些字段级别的source字段。

如果我看看uiElementinitModules方法

    initModules: function () {
        _.each(this.modules, function (name, property) {
            if (name) {
                this[property] = this.requestModule(name);
            }
        }, this);

        if (!_.isFunction(this.source)) {
            this.source = registry.get(this.provider);
        }

        return this;
    },

我看到对象引用了一个source属性,如果未设置该属性,它将使用该provider属性作为字符串/键标识符进入对象的注册表。这似乎是这些价值source不使用的物品。但是,PHP代码或其他一些javascript代码可能会使用它们。因此,我的问题。

Answers:


7

source是,或者说应该是,数据提供者。但是,据我所知,<item name="source">您提供的XML示例中的节点没有明显的区别,可以删除而不会产生任何后果。

这是我的initModules()方法:在的方法中elements/element.js,检查是否this.source是可调用函数:

if (!_.isFunction(this.source)) {
    this.source = registry.get(this.provider);
}

如果this.source不是可调用函数,则使用来从注册表中覆盖 this.source UI组件this.provider。同样,这是provider,而不是source。这样,如果在那个时候源不是可调用的函数,则它只会加载提供者,而原始函数this.source会顺其自然。

this.source通常是空的,但在的情况下cms_block_formthis.source将以它'block'开头。由于这是一个字符串而不是一个可调用函数,因此将其简单地覆盖。

还请注意this.source,在initModules()运行之前,基于XML的字符串,UI组件可以轻松添加一些逻辑以设置为可调用函数。


现在,为什么首先要有这个资源?我不知道为什么它在XML中,但是它在Javascript中起到了作用。例如,我停了下来grid/columns/column.js。在中defaults: {},存在以下内容:

modules: {
    source: '${ $.provider }'
}

回到elements/element.js,它在以下位置进行评估initModules()

_.each(this.modules, function (name, property) {
    if (name) {
        this[property] = this.requestModule(name);
    }
}, this);

这里是requestModule()方法:

requestModule: function (name) {
    var requested = this._requesetd;
    if (!requested[name]) {
        requested[name] = registry.async(name);
    }
    return requested[name];
},

async()方法从注册表返回,并在initModules()中分配给给定的属性。在这种情况下,this.source被设置为async()来自注册表的方法。这会发生的事情中modules:{},不只是source,但阐明了什么与发生source在一些组件。async()毫不奇怪,从中返回的函数是可调用函数。结果,此结果为false并被跳过:

initModules: function () {
    ...

    if (!_.isFunction(this.source)) {
        this.source = registry.get(this.provider);
    }

    return this;
}, 

返回grid/columns/column.jssource用于更改网格的排序。

exportSorting: function () {
    ...
    this.source('set', 'params.sorting', {
        field: this.index,
        direction: this.sorting
    });
},

async()方法处理功能,但是在这里,它在上调用该set()方法this.source()。源,或者dataProvider,是grid/provider.js它不具有set()方法。它是父母element/element.js,但是:

set: function (path, value) {
    var data = this.get(path),
        diffs;

    diffs = !_.isFunction(data) && !this.isTracked(path) ?
        utils.compare(data, value, path) :
        false;

    utils.nested(this, path, value);

    if (diffs) {
        this._notifyChanges(diffs);
    }

    return this;
},

的概念set()有点简单,因为它可以更新值并通知订户。因此,columns.js声明a 的结果是source,它可以直接访问on上的execute方法dataProvider


结论:来源似乎是至少在Javascript类中用作数据提供者的来源。如果源代码在Javascript类中设置并且是可调用的函数,则可将其用于直接在上执行方法dataProvider

不过,这仍然给我几个问题:

  • 可以source在XML中使用以代理dataProvider类吗?
  • 它是否应该在XML中达到目的,但在某个时候被弃用?
  • this.sourceinitModules()运行之前,是否有任何核心类可以查看(从XML)并对其做一些有趣的事情?

1
+1获取有用的信息,但最后遇到一个同样的问题- source这些XML文件中的内容:)
Alan Storm

7

去了这个的“源”(gro吟),看起来这些<item name="source"/>节点确实是多余的。或者,目前负责他们的Magento工程师认为他们是多余的,因此这与我们将要接近的事实相符。


3

源是ui组件可以用来读取“ DataProvider ”类提供的数据的键。当有多个选项卡和字段集时,它非常有用。

例如:参考 module-customer/view/base/ui_component/customer_form.xml

<fieldset name="customer">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">Account Information</item>
        </item>
    </argument>
    <field name="entity_id">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="visible" xsi:type="boolean">false</item>
                <item name="dataType" xsi:type="string">text</item>
                <item name="formElement" xsi:type="string">input</item>

                **<item name="source" xsi:type="string">customer</item>**

            </item>
        </argument>
    </field>
. 
. 
.

<fieldset name="address">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="is_collection" xsi:type="boolean">true</item>
            <item name="label" xsi:type="string" translate="true">Addresses</item>
            <item name="removeMessage" xsi:type="string" translate="true">Are you sure you want to delete this item?</item>
        </item>
    </argument>
    <field name="parent_id">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="visible" xsi:type="boolean">false</item>
                <item name="dataType" xsi:type="string">number</item>
                <item name="formElement" xsi:type="string">input</item>

                **<item name="source" xsi:type="string">address</item>**

            </item>
        </argument>
    </field>

DataProvider类中的getData()方法将返回带有键“ customer”和“ address”的数组,并将从中映射字段集中的相应字段。屏幕截图显示了方法的结果。getData()

DataProvider类的getData()方法的输出

之后,当getDataSourceData()调用Magento \ Ui \ Component \ Form中的方法时,它将处理上述数据。

public function getDataSourceData()
{
    $dataSource = [];

    $id = $this->getContext()->getRequestParam($this->getContext()->getDataProvider()->getRequestFieldName(), null);
    $filter = $this->filterBuilder->setField($this->getContext()->getDataProvider()->getPrimaryFieldName())
        ->setValue($id)
        ->create();
    $this->getContext()->getDataProvider()
        ->addFilter($filter);

    $data = $this->getContext()->getDataProvider()->getData();

    if (isset($data[$id])) {
        $dataSource = [
            'data' => $data[$id]
        ];
    } elseif (isset($data['items'])) {
        foreach ($data['items'] as $item) {
            if ($item[$item['id_field_name']] == $id) {
                **$dataSource = ['data' => ['general' => $item]];**
            }
        }
    }
    return $dataSource;
}

感谢您的回答。但是,您确定吗?我不确定你是正确的。是的,在客户窗体上,JSON数据具有一个名为客户的键,并且该键巧合地使用名称name作为<item name="source节点。但是,我看不到任何引用源节点中数据的PHP代码。另外,“ CMS页面”表单具有一个<item name="source" xsi:type="string">page</item>节点,并且其数据源数据没有page键。最后,我的研究表明,它name="dataScope"决定了字段在何处获得其价值。
艾伦·风暴

1
是的,您说的对,艾伦。在调试期间,我也看到了同样的事情(关于dataScope)。感谢您的澄清。如果我对“来源”有更多了解,我会发布。
Pankaj Bhope
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.