Question

Long story short:
The CMS page admin form data provider class Magento\Cms\Model\Page\DataProvider, more specific the method getData always returns an array with a single element that contains the data for the page that I'm editing and the element key is the page id.
How does this happen? Where is the filter by page id applied?

Short story long:
At a first glance, what the method Magento\Cms\Model\Page\DataProvider::getData returns is not that obvious.
In the method there is this line

$items = $this->collection->getItems(); 

and the collection member var is initialized in __construct with

$this->collection = $pageCollectionFactory->create();`   

Where $pageCollectionFactory is an instance of Magento\Cms\Model\ResourceModel\Page\CollectionFactory.

So, when I first looked, I thought "why the hell is it loading the full collection since I am editing only one item? This doesn't scale.".
Upon a closer inspection, I saw that the collection returns one single item. The one I am editing. This is good, but how does it work?
If I print the collection query echo $this->collection->getSelect() I get back

SELECT `main_table`.* FROM `cms_page` AS `main_table` WHERE (`main_table`.`page_id` = '2')

where 2 is the id of the page that I am editing.
Now the curious part (if this was not curious enough) If I create my own entity, following the same guidelines for the data provider class, it works the same. I get back one single item.
This makes me think the filtering happens somewhere higher in the inheritance tree, but I have no idea where?

Note: Please don't explain how to make this work on my custom module. I know how to do that. I just need an explanation on how/why/where the magic happens.

Was it helpful?

Solution

Check following function


/**
 * {@inheritdoc}
 */
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;
}

Following line is make collection as a single item


$this->getContext()->getDataProvider()
        ->addFilter($filter);

[Edit by OP].
The trace is:

  • \Magento\Framework\View\Element\UiComponent\ContentType\Json::render()
  • \Magento\Framework\View\Element\UiComponent\Context::getDataSourceData()
  • \Magento\Ui\Component\Form::getDataSourceData()
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top