Apa itu "sumber" Item dalam File Komponen UI

17

Dalam file konfigurasi Komponen Bentuk UI Magento 2, Anda akan sering melihat itematribut dengan yang sama source- di <item name="source" xsi:type="string">block</item>bawah.

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

Untuk apa bidang-bidang ini? Saya bertanya karena sepertinya mereka tidak perlu. Sebagai contoh, modul dalam repositori GitHub ini mengonfigurasi bentuk Komponen UI yang berfungsi , tetapi tidak menggunakan name="source"item ini .

Apakah ada yang tahu untuk apa name="source"barang - barang ini? Saya mengetahui mekanika Komponen UI yang mengambil XML dan cofigures sebagai 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"
    }
},

Yang dimasukkan ke uiElementobjek model tampilan Knockout berbasis. Namun, tidak jelas bagaimana pohon uiElementobjek model tampilan Knockout bersarang menggunakan bidang tingkat sourcebidang ini.

Jika saya melihat uiElement's initModulesmetode

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

Saya melihat objek referensi sourceproperti, dan jika tidak disetel, akan mencapai ke registri untuk objek menggunakan providerproperti sebagai pengenal string / kunci. Ini tampaknya seperti nilai ini sourceitem tidak digunakan. Namun, mungkin saja mereka digunakan oleh kode PHP, atau kode javascript lainnya. Karena itu, pertanyaan saya.

Alan Storm
sumber

Jawaban:

7

The sourceadalah, atau seharusnya, penyedia data. Dari apa yang saya tahu, <item name="source">simpul dalam contoh XML yang Anda berikan tidak membuat perbedaan yang terukur dan dapat dihapus tanpa konsekuensi.

Inilah cara saya sampai pada hal itu: dalam initModules()metode elements/element.js, ada tanda centang untuk melihat apakah this.sourceada fungsi yang dapat dipanggil:

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

Jika this.sourcebukan fungsi yang bisa dipanggil, itu ditimpa this.source dengan Komponen UI dari registri menggunakan this.provider. Sekali lagi, ini adalah provider, dan bukan source. Dengan demikian, jika sumbernya bukan fungsi yang dapat dipanggil pada saat itu, ia hanya memuat penyedia dan sumber asli this.sourceberjalan sesuai arah angin.

this.sourcesering kosong, tetapi dalam kasus cms_block_form, this.sourceakan 'block'mulai dengan. Karena itu adalah string dan bukan fungsi yang bisa dipanggil, itu hanya diganti.

Perhatikan juga bahwa Komponen UI dapat dengan mudah menambahkan beberapa logika untuk mengatur this.sourcefungsi yang dapat dipanggil, berdasarkan dari string dari XML, sebelum initModules()dijalankan.


Sekarang, mengapa sumber ini ada di tempat pertama? Saya tidak tahu mengapa itu ada di XML, tapi itu melayani tujuan di Javascript. Sebagai contoh, saya berhenti grid/columns/column.js. Di defaults: {}, berikut ini ada:

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

Kembali elements/element.js, ini dievaluasi dalam initModules():

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

Inilah requestModule()metodenya:

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

The async()Metode dikembalikan dari registri, dan dalam initModules(), ditugaskan untuk properti yang diberikan. Dalam hal ini, this.sourcediatur menjadi async()metode dari registri. Ini akan terjadi untuk apa pun di dalam modules:{}, tidak hanya source, tetapi menjelaskan apa yang terjadi dengan sourcebeberapa komponen. The async()Fungsi kembali dari ini - tidak mengherankan - fungsi callable. Akibatnya, ini bernilai false dan dilewati:

initModules: function () {
    ...

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

    return this;
}, 

Kembali grid/columns/column.js, sourcedigunakan untuk mengubah penyortiran grid.

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

The async()Metode menangani fungsionalitas, tapi di sini, itu adalah memanggil set()metode pada this.source(). Sumbernya, atau, dataProvideradalah grid/provider.jsdan tidak memiliki set()metode. Itu orangtua, element/element.jsapakah:

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

Konsep dengan set()agak sederhana karena memperbarui nilai dan memberi tahu pelanggan. Jadi, sebagai akibat dari columns.jsmendeklarasikan a source, ia memiliki akses langsung untuk mengeksekusi metode pada itu dataProvider.


Kesimpulan: sumber tampaknya adalah apa yang digunakan, setidaknya di kelas Javascript, sebagai penyedia data. Jika sumber diatur dalam kelas Javascript, dan merupakan fungsi yang bisa dipanggil, dapat digunakan untuk mengeksekusi metode langsung pada dataProvider.

Ini membuat saya masih memiliki beberapa pertanyaan, namun:

  • Apakah mungkin untuk digunakan sourcedalam XML untuk proksi kelas dataProvider?
  • Apakah itu seharusnya melayani tujuan dalam XML tetapi ditinggalkan di beberapa titik?
  • Apakah ada kelas inti yang melihat this.source(dari XML) dan melakukan sesuatu yang menarik dengannya sebelum initModules()dijalankan?
bassplayer7
sumber
1
+1 untuk informasi yang bermanfaat, tetapi berakhir dengan pertanyaan yang sama yang saya miliki - apa yang sourcedilakukan di file XML itu :)
Alan Storm
7

Pergi ke "sumber" (mengerang) untuk yang satu ini dan sepertinya <item name="source"/>node - node ini memang berlebihan. Atau, insinyur Magento yang saat ini bertanggung jawab atas mereka mengira mereka mubazir, jadi itu sedekat mungkin dengan kebenaran.

Alan Storm
sumber
3

Sumber adalah kunci yang digunakan komponen ui untuk membaca data yang disediakan oleh kelas " DataProvider ". Ini sangat berguna ketika ada banyak tab dan bidang.

Misalnya: merujuk 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>

The getData()metode dalam DataProvider kelas akan mengembalikan array dengan kunci 'pelanggan' dan 'alamat' dan bidang yang sesuai dalam bidang-set akan dipetakan dari itu. Tangkapan layar menampilkan hasil getData()metode.

Output dari getData () metode kelas DataProvider

Setelah itu ketika getDataSourceData()metode di Magento \ Ui \ Component \ Form dipanggil untuk memproses data di atas.

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
sumber
Terima kasih telah menjawab. Namun, apakah Anda yakin tentang ini? Saya tidak yakin Anda benar. Ya, pada formulir pelanggan, data JSON memiliki kunci bernama pelanggan, dan kunci itu secara kebetulan menggunakan nama nama sebagai <item name="sourcesimpul. Namun, saya tidak melihat kode PHP yang mereferensikan data di node sumber. Selain itu, formulir Halaman CMS memiliki <item name="source" xsi:type="string">page</item>simpul dan sumber data datanya tidak memiliki pagekunci. Akhirnya, penelitian saya menunjukkan itu name="dataScope"yang menentukan di mana bidang mendapatkan nilainya.
Alan Storm
1
ya, Anda benar, Alan. Selama debugging saya juga melihat hal yang sama (tentang dataScope). Terimakasih atas klarifikasinya. Jika saya mendapatkan lebih banyak tentang "sumber" saya akan memposting.
Pankaj Bhope