Quali sono gli elementi "sorgente" nei file dei componenti dell'interfaccia utente


17

Nei file di configurazione del componente modulo interfaccia utente di Magento 2, vedrai spesso un itemattributo con lo stesso di source- <item name="source" xsi:type="string">block</item>sotto.

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

A cosa servono questi campi? Chiedo perché sembra che non siano necessari. Ad esempio, il modulo in questo repository GitHub configura un modulo Componente UI funzionante , ma non li usaname="source" elementi.

Qualcuno sa a cosa name="source"servono questi articoli? Sono a conoscenza del meccanico dei componenti dell'interfaccia utente che accetta l'XML e lo configura come 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"
    }
},

Che viene inserito in un uiElementoggetto modello di vista Knockout basato. Tuttavia, non è chiaro in che modo l'albero nidificato degli uiElementoggetti del modello della vista Knockout basata utilizza questi livelli di camposource campo.

Se guardo il uiElement's initModulesmetodo

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

Vedo che l'oggetto fa riferimento a una sourceproprietà e, se non impostato, raggiungerà nel registro un oggetto che utilizza la providerproprietà come identificatore di stringa / chiave. E sembra che il valore di questi sourceelementi non è utilizzato. Tuttavia, è possibile che vengano utilizzati dal codice PHP o da qualche altro codice javascript. Quindi, la mia domanda.

Risposte:


7

È sourceo dovrebbe essere il fornitore di dati. Da quello che posso dire, tuttavia, il <item name="source">nodo nell'esempio XML che hai fornito non fa alcuna differenza misurabile e può essere rimosso senza conseguenze.

Ecco come sono arrivato a questo: nel initModules()metodo di elements/element.js, c'è un controllo per vedere se this.sourceè una funzione richiamabile:

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

Se this.sourcenon è una funzione richiamabile, sostituisce this.source con un componente UI dal registro mediante this.provider. Ancora una volta, questo è il provider, però, e non il source. In quanto tale, se la sorgente non è una funzione richiamabile in quel punto, carica semplicemente il provider e l'originale this.sourcesegue la direzione del vento.

this.sourcespesso è vuoto, ma nel caso del cms_block_form, this.sourcesarebbe 'block'per iniziare. Poiché si tratta di una stringa e non di una funzione richiamabile, viene semplicemente ignorata.

Si noti inoltre che un componente dell'interfaccia utente potrebbe facilmente aggiungere un po 'di logica per impostare this.sourceuna funzione richiamabile, basata su una stringa da XML, prima che initModules()venga eseguita.


Ora, perché questa fonte è lì in primo luogo? Non so perché sia ​​nell'XML, ma serve a uno scopo nel Javascript. Per un esempio, ho tirato su grid/columns/column.js. In defaults: {}, c'è il seguente:

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

Di nuovo elements/element.js, questo viene valutato in initModules():

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

Ecco il requestModule()metodo:

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

Il async()metodo viene restituito dal registro e in initModules(), assegnato alla proprietà fornita. In questo caso, this.sourceè impostato per essere il async()metodo dal registro. Ciò accadrebbe per qualsiasi cosa all'interno modules:{}, non solo source, ma fa luce su ciò che accade con sourcealcuni componenti. La async()funzione restituita da - non a caso - è una funzione richiamabile. Di conseguenza, questo viene valutato come falso e viene ignorato:

initModules: function () {
    ...

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

    return this;
}, 

Di nuovo grid/columns/column.js, sourceviene utilizzato per modificare l'ordinamento della griglia.

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

Il async()metodo gestisce la funzionalità, ma qui sta chiamando il set()metodo this.source(). La fonte, o, dataProviderè grid/provider.jse non ha un set()metodo. È genitore element/element.js, però:

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

Il concetto con set()è piuttosto semplice in quanto aggiorna i valori e notifica agli abbonati. Quindi, come risultato della columns.jsdichiarazione di a source, ha accesso diretto per eseguire metodi su di esso dataProvider.


Conclusione: la fonte sembra essere ciò che viene utilizzato, almeno nelle classi Javascript, come fornitore di dati. Se una sorgente è impostata in una classe Javascript ed è una funzione richiamabile, può essere utilizzata per eseguire metodi direttamente su dataProvider.

Questo mi lascia ancora qualche domanda, però:

  • È possibile utilizzare sourcein XML per eseguire il proxy di una classe dataProvider?
  • Doveva servire a uno scopo in XML ma a un certo punto sarebbe stato deprecato?
  • Ci sono delle classi principali che guardano this.source(da XML) e fanno qualcosa di interessante prima che initModules()venga eseguito?

1
+1 per informazioni utili, ma alla fine ho la stessa domanda che ho - cosa sta sourcefacendo in quei file XML :)
Alan Storm

7

Sono andato a "la fonte" (gemito) per questo e sembra che questi <item name="source"/>nodi siano davvero ridondanti. Oppure, l'ingegnere Magento attualmente responsabile di loro pensa che siano ridondanti, quindi è il più vicino possibile alla verità.


3

La fonte è la chiave con cui il componente dell'interfaccia utente può leggere i dati forniti dalla classe " DataProvider ". È molto utile in presenza di più schede e set di campi.

Ad esempio: fare riferimento 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>

Il getData()metodo nella classe DataProvider restituirà un array con le chiavi 'cliente' e 'indirizzo' e i campi corrispondenti nei set di campi verranno mappati da esso. La schermata mostra il risultato del getData()metodo.

Output del metodo getData () della classe DataProvider

Successivamente, quando getDataSourceData()viene chiamato il metodo in Magento \ Ui \ Component \ Form, elabora i dati di cui sopra.

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

Grazie per avermi risposto. Tuttavia, sei sicuro di questo? Non sono sicuro che tu abbia ragione. Sì, nel modulo del cliente i dati JSON hanno una chiave denominata cliente e quella chiave utilizza casualmente il nome del nome come <item name="sourcenodo. Tuttavia, non vedo alcun codice PHP che faccia riferimento ai dati nel nodo di origine. Inoltre, il modulo Pagina CMS ha un <item name="source" xsi:type="string">page</item>nodo e i suoi dati di origine dati non hanno una pagechiave. Infine, la mia ricerca indica name="dataScope"che determina dove un campo ottiene i suoi valori.
Alan Storm,

1
si, hai ragione Alan. Durante il debug ho visto anche la stessa cosa (su dataScope). Grazie per il chiarimento. Se avrò qualcosa in più su "fonte", posterò.
Pankaj Bhope,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.