1

I am trying to make a UI component form for creating products in Magento 2.1 module. However, I stuck with the problem that it throws this error:

Fatal error: Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to a member function addFieldToFilter() on null in /home/nikolay/Projects/project_name/vendor/magento/module-ui/Component/Wrapper/UiComponent.php on line 0

I think that it's causing an error because I don't have any collection to pass for DataProvider. But the thing is that I don't need one. So I am trying to figure out how to avoid this error without having any collection to pass.

/Model/DataProvider.php

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Company_Name\ProductParser\Model;

use Magento\Ui\DataProvider\AbstractDataProvider;

/**
 * Class DataProvider
 */
class DataProvider extends AbstractDataProvider
{

    /**
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param array $data
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        array $data = []
    ) {
        parent::__construct($name, $primaryFieldName, $requestFieldName, $data);
    }

    /**
     * {@inheritdoc}
     */
    public function getData()
    {
        return [];
    }

}

view/adminhtml/layout/productparser_parseproduct_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>
            Parse
        </title>
    </head>
    <body>
        <referenceContainer name="content">
            <uiComponent name="parse_form"/>
        </referenceContainer>
    </body>
</page>

view/adminhtml/ui_component/parse_form.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">parse_form.parse_form_data_source</item>
            <item name="deps" xsi:type="string">parse_form.parse_form_data_source</item>
            <item name="namespace" xsi:type="string">parse_form</item>
        </item>
        <item name="label" xsi:type="string" translate="true">Category Information</item>
        <!--<item name="buttons" xsi:type="array">
            <item name="delete" xsi:type="string">Magento\Catalog\Block\Adminhtml\Category\Edit\DeleteButton</item>
            <item name="save" xsi:type="string">Magento\Catalog\Block\Adminhtml\Category\Edit\SaveButton</item>
        </item>-->
        <!--<item name="reverseMetadataMerge" xsi:type="boolean">true</item>-->
        <item name="config" xsi:type="array">
            <item name="dataScope" xsi:type="string">data</item>
            <item name="namespace" xsi:type="string">parse_form</item>
        </item>
        <item name="template" xsi:type="string">templates/form/collapsible</item>
    </argument>
    <dataSource name="parse_form_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Company_Name\ProductParser\Model\DataProvider</argument>
            <argument name="name" xsi:type="string">parse_form_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">entity_id</argument>
            <argument name="requestFieldName" xsi:type="string">id</argument>
            <argument name="data" xsi:type="array">
                <!--<item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
                    <item name="componentType" xsi:type="string">field</item>
                </item>-->
                <!--<item name="config" xsi:type="array">
                    <item name="submit_url" xsi:type="string">admin/productparser/create</item>
                    &lt;!&ndash;<item name="validate_url" xsi:type="string">admin/productparser/validate</item>&ndash;&gt;
                </item>-->
            </argument>
        </argument>
        <argument name="data" xsi:type="array">
            <!--<item name="js_config" xsi:type="array">
                <item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
            </item>-->
        </argument>
    </dataSource>
    <fieldset name="data">
        <!-- This field represents form id and is hidden -->
        <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">parse_form</item>
                </item>
            </argument>
        </field>

        <!-- This field has data type 'text' and standard 'input' form element and looks like input -->
        <field name="title">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="label" xsi:type="string">Some text</item>
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="formElement" xsi:type="string">input</item>
                    <item name="source" xsi:type="string">parse_form</item>
                </item>
            </argument>
        </field>
    </fieldset>
</form>
9

Not sure if this will completely solve your problem, but it should take you a step further.
Add this method in your data provider

public function addFilter(\Magento\Framework\Api\Filter $filter)
{
    return null;
}

Since you are extending AbstractDataProvider you need to override the method.
If something else crashes, you might need to do the same thing for other methods involving $this->getCollection().
I'm thinking one of these methods addField, addOrder, setLimit, removeField, removeAllFields, count

  • I'm afraid that causes page bootloop. – Nikolay Baychenko May 31 '17 at 5:26
  • It went to the page bootloop ,So is there any other solution to mitigate this , because I also need similar functionality only form without collection . @Marius – Shashank Gupta Mar 9 '18 at 10:12
  • @ShashankGupta Sorry, I don't know. – Marius Mar 9 '18 at 12:09
  • This solution worked for me – Adnan Nov 3 '18 at 1:14
2

Change class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider

To class DataProvider extends \Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider

  • It also worked for me, what is the logic behind this, could you please elaborate? – Adnan Nov 3 '18 at 1:24
  • @AbdulBasit It worked for me, too. Can you please explain what was the reason why \Magento\Ui\DataProvider\AbstractDataProvider was not working? – Dhara Bhatti May 16 at 12:01
1

The Abstract Data Provider that you are extending has collection field. You must initialize this field with a valid collection (the collection associated with your entity).

Steps to solve the problem.

  1. Inject collectionFactory in the class that extends AbstractDataProvider.
  2. Initialize $collection field.

The error message is pretty intuitive too. (By Magento standards). Hope this helps.

0

What is probably happening is that Magento is trying to filter the collection based on the id provided in the url, since you added this line in the uiComponent

<argument name="requestFieldName" xsi:type="string">id</argument>

So to filter the collection based on this id, Magento calls the addFilter function in the AbstractDataProvider

public function addFilter(\Magento\Framework\Api\Filter $filter)
{
    $this->getCollection()->addFieldToFilter(
        $filter->getField(),
        [$filter->getConditionType() => $filter->getValue()]
    );
}

However, because getCollection() return null, as it's relying on the collection variable in the AbstractDateProvider, as you didnt override it in your extended class, you're getting the addFilter on null error.

I would suggested trying to remove the requestFieldName field from the xml, and if that didn't work, override the $collection variable in your extended class with an empty and generic collection in the constructor.

0

Just inject your collection factory class in the constructor of your dataprovider and assign the collection member variable with your collection. It should resolve the issue. Best

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Company_Name\ProductParser\Model;

use Magento\Ui\DataProvider\AbstractDataProvider;

/**
 * Class DataProvider
 */
class DataProvider extends AbstractDataProvider
{

    /**
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param array $data
     */
    public function __construct(
        \[mynamespace]\[mymodule]\model\ResourceModel\[myclass]\CollectionFactory $mycollectionFactory,
        $name,
        $primaryFieldName,
        $requestFieldName,
        array $data = []
    ) {
        parent::__construct($name, $primaryFieldName, $requestFieldName, $data);
        $this->collection = $mycollectionFactory->create();
    }

    /**
     * {@inheritdoc}
     */
    public function getData()
    {
        return [];
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.