Magento 2 – Why UI Listing Component Needs Two Collections

magento2PHPuicomponent

Magento 2 has a new "uiComponent" feature. This allows to you to include a simple <uiComponent/> tag in your layout handle XML files to add things like Grids and forms to your application page.

It appears that the configuration for a data grid (a listing) requires two collection objects be configured.

What's the role of each configuration collection below? Or do I misunderstand the roles of these collections? Or is there a way to create grid object using only a single collection?

The following configuration sets up a UI listing Component named cms_page_listing

vendor/magento/module-cms/view/adminhtml/ui_component/cms_page_listing.xml

And the the following DI Injection tells Magento that a cms_page_listing should use a Magento\Cms\Model\ResourceModel\Page\Grid\Collection collection.

<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
    <arguments>
        <argument name="collections" xsi:type="array">
            <item name="cms_page_listing_data_source" xsi:type="string">Magento\Cms\Model\ResourceModel\Page\Grid\Collection</item>
        </argument>
    </arguments>
</type>

This seems to be the main collection used to populate the grid.

However, there's also this PageGridDataProvider in the cms_page_listing configuration.

<!-- File: vendor/magento/module-cms/view/adminhtml/ui_component/cms_page_listing.xml -->
    <argument name="dataProvider" xsi:type="configurableObject">
        <argument name="class" xsi:type="string">PageGridDataProvider</argument>
        <argument name="name" xsi:type="string">cms_page_listing_data_source</argument>
        <argument name="primaryFieldName" xsi:type="string">page_id</argument>
        <argument name="requestFieldName" xsi:type="string">id</argument>
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="update_url" xsi:type="url" path="mui/index/render"/>
            </item>
        </argument>
    </argument>

The PageGridDataProvider resolves to a virtualType

<virtualType name="PageGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider">
    <arguments>
        <argument name="collection" xsi:type="object" shared="false">Magento\Cms\Model\ResourceModel\Page\Collection</argument>
        <argument name="filterPool" xsi:type="object" shared="false">CmsGirdFilterPool</argument>
    </arguments>
</virtualType>

This virtual type configures a second collection (Magento\Cms\Model\ResourceModel\Page\Collection).

It's not clear why this second configuration is needed, or what its role is in creating a grid. The higher level question is probably what role does the dataProvider play in creating a UI Grid. The larger larger question is probably What PHP objects are created to create a UI Listing Grid, and how does a configuration control them

Best Answer

Here is a quick answer to your first question:

The configuration for virtual type isn't required. If you look into Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider you'll find that none of those two arguments are used ("collection" as well as "filterPool").

We'll remove this unused configuration as soon as we can. So, result declaration of data providers virtual types should be as simple as this:

for CMS Pages:

<virtualType name="PageGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider"/>

and for CMS Blocks

<virtualType name="PageGridDataProvider" type="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider"/>

And as now you can see, in UI Components configuration files you are not enforced to use data provider virtual type and you can refer to generic data provider Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider. We've decided to use virtual type, just to provide yet another extension point for developers.