Jakie są elementy „źródłowe” w plikach składników interfejsu użytkownika

17

W plikach konfiguracyjnych komponentu interfejsu użytkownika Magento 2 często widzisz itematrybut o tym samym source- <item name="source" xsi:type="string">block</item>poniżej.

#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>    

Do czego służą te pola? Pytam, bo wydaje się, że nie są konieczne. Na przykład moduł w tym repozytorium GitHub konfiguruje działający formularz składnika interfejsu użytkownika , ale nie używa tych name="source"elementów.

Czy ktoś wie, do czego name="source"służą te przedmioty? Zdaję sobie sprawę z mechaniki UI Component, która pobiera XML i tworzy go jako 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"
    }
},

Który jest wprowadzany do uiElementopartego na obiekcie modelu widoku Knockout. Nie jest jednak jasne, w jaki sposób zagnieżdżone drzewo uiElementopartych na obiektach modelu widoku Knockout korzysta z tych pól na poziomie sourcepola.

Jeśli patrzę na uiElement„s initModulesmetody

    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;
    },

Widzę, że obiekt odwołuje się do sourcewłaściwości, a jeśli nie jest ustawiony, będzie sięgał do rejestru dla obiektu używającego providerwłaściwości jako identyfikatora łańcucha / klucza. To wydaje się wartość tych sourcepozycji nie jest używany. Możliwe jednak, że są one używane przez kod PHP lub inny kod javascript. Stąd moje pytanie.

Alan Storm
źródło

Odpowiedzi:

7

sourceJest lub powinien być, dostawca danych. Z tego, co mogę powiedzieć, jednak <item name="source">węzeł w podanym przykładzie XML nie ma mierzalnej różnicy i może zostać usunięty bez konsekwencji.

Oto jak do tego doszedłem: w initModules()metodzie elements/element.jssprawdza się, czy this.sourcemożna wywołać funkcję:

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

Jeśli this.sourcenie jest funkcją wywoływalną, zastępuje this.source ją składnik UI z rejestru za pomocą this.provider. Znów jest to providerjednak, a nie source. W związku z tym, jeśli źródło nie jest w tym momencie funkcją wywoływalną, po prostu ładuje dostawcę i oryginał this.sourcepodąża drogą wiatru.

this.sourceczęsto jest pusta, ale w przypadku cms_block_form, this.sourcebyłoby 'block'na początek. Ponieważ jest to ciąg znaków, a nie funkcja, którą można wywołać, jest po prostu nadpisywana.

Należy również pamiętać, że składnik interfejsu użytkownika może z łatwością dodać logikę, aby ustawić this.sourcefunkcję wywoływaną na podstawie łańcucha XML przed initModules()uruchomieniem.


Dlaczego w ogóle jest to źródło? Nie wiem, dlaczego jest w XML, ale służy to celowi w Javascript. Na przykład zatrzymałem się grid/columns/column.js. Dostępne defaults: {}są następujące elementy:

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

Po powrocie elements/element.jsjest to oceniane w initModules():

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

Oto requestModule()metoda:

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

async()Metoda jest zwracana z rejestru, w initModules(), przypisany do danej nieruchomości. W takim przypadku this.sourceustawiono async()metodę z rejestru. Stałoby się tak w przypadku wszystkiego modules:{}, nie tylko source, ale rzuca światło na to, co dzieje się z sourceniektórymi komponentami. async()Funkcja jest zwracana z - co nie dziwi - wywoływalnym funkcja. W rezultacie jest to wartość false i jest pomijane:

initModules: function () {
    ...

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

    return this;
}, 

Po powrocie grid/columns/column.js, sourcesłuży do zmiany sortowania siatki.

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

async()Metoda obsługuje funkcjonalność, ale tutaj, to jest wywołanie set()metody na this.source(). Źródło, lub, dataProviderjest grid/provider.jsi nie ma set()metody. Jest jednak rodzicem 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;
},

Koncepcja z set()jest nieco prosta, ponieważ aktualizuje wartości i powiadamia subskrybentów. Tak więc, w wyniku columns.jszadeklarowania a source, ma bezpośredni dostęp do wykonywania na nim metod dataProvider.


Wniosek: źródłem wydaje się być to, co jest używane, przynajmniej w klasach JavaScript, jako dostawca danych. Jeśli źródło jest ustawione w klasie Javascript i jest funkcją wywoływalną, można jej użyć do wykonania metod bezpośrednio na dataProvider.

Pozostaje mi jednak kilka pytań:

  • Czy można używać sourcew XML do proxy klasy dataProvider?
  • Czy miał służyć celowi w XML, ale w pewnym momencie stał się przestarzały?
  • Czy są jakieś podstawowe klasy, które przeglądają this.source(z XML) i robią z nim coś interesującego przed initModules()uruchomieniem?
bassplayer7
źródło
1
+1 za przydatne informacje, ale kończy się na tym samym pytaniu, jakie mam - co się sourcedzieje w tych plikach XML :)
Alan Storm
7

Poszedł do „źródła” (jęk) tego i wygląda na to, że te <item name="source"/>węzły są rzeczywiście zbędne. Lub inżynier Magento, który obecnie nimi kieruje, uważa, że ​​są zbędne, więc jest to tak bliskie prawdy, jak to możliwe.

Alan Storm
źródło
3

Źródło jest kluczem, za pomocą którego komponent interfejsu użytkownika może odczytać dane dostarczone przez „ klasę DataProvider ”. Jest to bardzo przydatne, gdy istnieje wiele kart i zestawów pól.

Na przykład: patrz 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()Sposób DataProvider klasy powróci tablicę z klawiszami "klienta i Adres i odpowiednich pól w polu zestawów będą odwzorowywane z niego. Zrzut ekranu pokazuje wynik getData()metody.

Dane wyjściowe metody getData () klasy DataProvider

Następnie, gdy getDataSourceData()wywoływana jest metoda w Magento \ Ui \ Component \ Form, przetwarza powyższe dane.

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;
}
Pankaj Bhope
źródło
Dziękuje za odpowiadanie. Jesteś jednak tego pewien? Nie jestem pewien, czy masz rację. Tak, w formularzu klienta dane JSON mają klucz o nazwie klient, a ten klucz przypadkowo używa nazwy nazwy jako <item name="sourcewęzła. Jednak nie widzę żadnego kodu PHP, który odwoływałby się do danych w węźle źródłowym. Ponadto formularz strony CMS ma <item name="source" xsi:type="string">page</item>węzeł, a dane źródła danych nie mają pageklucza. Wreszcie, moje badania wskazują, name="dataScope"że określa ono, skąd pole otrzymuje swoje wartości.
Alan Storm,
1
tak, masz rację Alan. Podczas debugowania widziałem też to samo (o dataScope). Dziękuję za wyjaśnienie. Jeśli otrzymam coś więcej o „źródle”, opublikuję.
Pankaj Bhope