Что такое «исходные» элементы в файлах компонентов пользовательского интерфейса

17

В файлах конфигурации компонента формы пользовательского интерфейса Magento 2 вы часто будете видеть 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 настраивает рабочую форму компонента пользовательского интерфейса , но не использует эти name="source"элементы.

Кто-нибудь знает, для чего эти name="source"предметы? Мне известно о механике компонентов пользовательского интерфейса, которая принимает 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поля.

Если я смотрю на uiElement«S initModulesметод

    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. Отсюда и мой вопрос.

Алан Сторм
источник

Ответы:

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 компонент пользовательского интерфейса из реестра, используя this.provider. Опять же, это provider, хотя, а не source. Таким образом, если источник не является вызываемой функцией в этот момент, он просто загружает провайдера, а оригинал this.sourceидет по пути ветра.

this.sourceчасто пусто, но в случае cms_block_form, this.sourceбыло бы 'block'для начала. Поскольку это строка, а не вызываемая функция, она просто переопределяется.

Также обратите внимание, что компонент пользовательского интерфейса может легко добавить некоторую логику для установки this.sourceв вызываемую функцию, основанную на строке из XML, до initModules()запуска.


Теперь, почему этот источник там в первую очередь? Я не знаю, почему это в 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()Функция возвращается из это - не удивительно - вызываемая функция. В результате это оценивается как ложное и пропускается:

initModules: function () {
    ...

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

    return this;
}, 

Назад grid/columns/column.js, sourceиспользуется для изменения сортировки сетки.

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объявления объекта sourceон имеет прямой доступ к выполняемым методам dataProvider.


Вывод: источником является то, что используется, по крайней мере в классах Javascript, в качестве поставщика данных. Если источник задан в классе Javascript и является вызываемой функцией, его можно использовать для выполнения методов непосредственно в dataProvider.

Это оставляет мне еще несколько вопросов:

  • Можно ли использовать sourceв XML для прокси класса dataProvider?
  • Должен ли он служить цели в XML, но в какой-то момент устарел?
  • Существуют ли какие-либо базовые классы, которые смотрят this.source(из XML) и делают с ним что-то интересное перед initModules()запуском?
bassplayer7
источник
1
+1 за полезную информацию, но в конечном итоге я source
Alan Storm
7

Пошел к «источнику» (стону) для этого, и похоже, что эти <item name="source"/>узлы действительно избыточны. Или инженер Magento, в настоящее время отвечающий за них, считает, что они избыточны, так что это настолько близко к истине, насколько мы узнаем.

Алан Сторм
источник
3

Источник - это ключ, с помощью которого компонент пользовательского интерфейса может читать данные, предоставленные классом « 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>

getData()Метод в DataProvider классе будет возвращать массив с ключами «клиент» и «адрес» и соответствующие поля в поле наборов будут отображаться из него. Снимок экрана показывает результат getData()метода.

Вывод метода getData () класса DataProvider

Затем, когда 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;
}
Панкадж Бхопе
источник
Спасибо, что ответили. Тем не менее, вы уверены в этом? Я не уверен, что ты прав. Да, в форме customer данные JSON имеют ключ с именем customer, и этот ключ по совпадению использует имя name в качестве <item name="sourceузла. Однако я не вижу никакого кода PHP, который ссылается на данные в исходном узле. Кроме того, форма страницы CMS имеет <item name="source" xsi:type="string">page</item>узел, а данные источника данных не имеют pageключа. Наконец, мое исследование показывает, name="dataScope"что оно определяет, где поле получает свои значения.
Алан Шторм
1
да, ты прав Алан. Во время отладки я тоже видел то же самое (насчет dataScope). Благодарю за разъяснение. Если я получу что-нибудь больше об "источнике", я опубликую
Панкадж