staempfli / magento2-code-generator

Code generator for Magento 2
250 stars 58 forks source link

[CrudEAV] "Fatal Error: Class not found" after generation, but class exists and namespace correct #3

Closed thomasdom closed 7 years ago

thomasdom commented 7 years ago

I got this fatal error after generating a custom EAV Model :

Fatal error: Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Class 'VehicleCompany\Cars\Model\ResourceModel\Car\Grid\Collection' not found in /<magento_root_dir>/vendor/magento/module-ui/Component/Wrapper/UiComponent.php on line 0

But this class exists, and its namespace is correct (no typos).

Please, how to fix this issue ? I've been searching for several hours, but i didn't manage to find a solution.

Files :

<?php
/**
 * Collection.php
 *
 * @copyright Copyright © 2017 Vehicle Company. All rights reserved.
 * @author    thomasdom@vehicle-company.com
 */

namespace VehicleCompany\Cars\Model\ResourceModel\Car\Grid;

use Magento\Framework\Api\Search\AggregationInterface;
use Magento\Framework\Api\Search\SearchResultInterface;
use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Eav\Model\Config;
use Magento\Eav\Model\EntityFactory as EavEntityFactory;
use Magento\Eav\Model\ResourceModel\Helper;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
use Magento\Framework\Data\Collection\EntityFactory;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Validator\UniversalFactory;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;

/**
 * Class Collection
 * Collection for displaying grid
 */
class Collection extends \VehicleCompany\Cars\Model\ResourceModel\Car\Collection implements SearchResultInterface
{
    /**
     * @var AggregationInterface
     */
    protected $aggregations;

    /**
     * Collection constructor.
     * @param EntityFactory $entityFactory
     * @param LoggerInterface $logger
     * @param FetchStrategyInterface $fetchStrategy
     * @param ManagerInterface $eventManager
     * @param Config $eavConfig
     * @param ResourceConnection $resource
     * @param EavEntityFactory $eavEntityFactory
     * @param Helper $resourceHelper
     * @param UniversalFactory $universalFactory
     * @param StoreManagerInterface $eventPrefix
     * @param $eventObject
     * @param $resourceModel
     * @param string $model
     * @param StoreManagerInterface $storeManager
     * @param AdapterInterface|null $connection
     *
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
     */
    public function __construct(
        EntityFactory $entityFactory,
        LoggerInterface $logger,
        FetchStrategyInterface $fetchStrategy,
        ManagerInterface $eventManager,
        Config $eavConfig,
        ResourceConnection $resource,
        EavEntityFactory $eavEntityFactory,
        Helper $resourceHelper,
        UniversalFactory $universalFactory,
        StoreManagerInterface $storeManager,
        $eventPrefix,
        $eventObject,
        $resourceModel,
        $model = 'VehicleCompany\Cars\Ui\Component\Listing\DataProvider\Document',
        AdapterInterface $connection = null
    )
    {
        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $eavConfig, $resource, $eavEntityFactory, $resourceHelper, $universalFactory, $storeManager, $connection);
        $this->_eventPrefix = $eventPrefix;
        $this->_eventObject = $eventObject;
        $this->_init($model, $resourceModel);
    }

    /**
     * @return AggregationInterface
     */
    public function getAggregations()
    {
        return $this->aggregations;
    }

    /**
     * @param AggregationInterface $aggregations
     * @return $this
     */
    public function setAggregations($aggregations)
    {
        $this->aggregations = $aggregations;
    }

    /**
     * Retrieve all ids for collection
     * Backward compatibility with EAV collection
     *
     * @param int $limit
     * @param int $offset
     * @return array
     */
    public function getAllIds($limit = null, $offset = null)
    {
        return $this->getConnection()->fetchCol($this->_getAllIdsSelect($limit, $offset), $this->_bindParams);
    }

    /**
     * Get search criteria.
     *
     * @return SearchCriteriaInterface|null
     */
    public function getSearchCriteria()
    {
        return null;
    }

    /**
     * Set search criteria.
     *
     * @param SearchCriteriaInterface $searchCriteria
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setSearchCriteria(SearchCriteriaInterface $searchCriteria = null)
    {
        return $this;
    }

    /**
     * Get total count.
     *
     * @return int
     */
    public function getTotalCount()
    {
        return $this->getSize();
    }

    /**
     * Set total count.
     *
     * @param int $totalCount
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setTotalCount($totalCount)
    {
        return $this;
    }

    /**
     * Set items list.
     *
     * @param \Magento\Framework\Api\ExtensibleDataInterface[] $items
     * @return $this
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function setItems(array $items = null)
    {
        return $this;
    }
}

Configuration :

thomasdom commented 7 years ago

After searching for a couple of hours, I changed a line in \<module_path>/etc/di.xml,

From this:

<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
    <arguments>
        <argument name="collections" xsi:type="array">
            <item name="vehiclecompany_cars_car_listing_data_source" xsi:type="string">VehicleCompany\Cars\Model\ResourceModel\Car\Grid\Collection</item>
        </argument>
    </arguments>
</type>

To this:

<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
    <arguments>
        <argument name="collections" xsi:type="array">
            <item name="vehiclecompany_cars_car_listing_data_source" xsi:type="string">VehicleCompany\Cars\Model\ResourceModel\Car\Collection</item>
        </argument>
    </arguments>
</type>

After this, the listing page loads successfully. But I have some questions:

jalogut commented 7 years ago

Hi @thomasdom ,

Thanks for your feedback. It is very weird what you mention. Somehow Magento does not find your class although is there... I guess that you have already checked it but just in case. Could you check that the Folders and Files are properly written and they all start with Uppercase?

The change you did in di.xml just demonstrates that the normal Collection is found but unfortunately that is not a solution. Here you need to use Grid\Collection because is the one that implements SearchResultInterface, which is needed for Grid filters. That also answers your first question.

Regarding your second question. I do not know yet but we will try to figure it out.

I just tried to reproduce your issue using the latest version of magento2-code-generator but it seems to work just fine. See attached video.

Could you give me more information:

Thanks Car EAV Module.mov.zip

thomasdom commented 7 years ago

Hi @jalogut,

Thank you for your help! Here are the informations you requested:

I'm going to try to generate a CRUD EAV model in a separate generated module to check, I'll tell you if this issue still occurs.

thomasdom commented 7 years ago

@jalogut I solved the issue! It was a system permission issue: The directory <magento_root_dir>/app/code/VehicleCompany/Cars/Model/ResourceModel/Car/Grid was not traversable by my Web server. That's why the exception was thrown.

So I did a find app/code/VehicleCompany/Cars -type d -exec chmod +x {} \; and the Car listing did reappear.

Thanks a lot for your help!

jalogut commented 7 years ago

Hi @thomasdom,

I am glad you found the source of the problem 😀

Regarding permissions, giving read and write access should be enough. You can find more info here: