hyva-themes / magento2-hyva-admin

This module aims to make creating grids and forms in the Magento 2 adminhtml area joyful and fast.
https://hyva-themes.github.io/magento2-hyva-admin/
BSD 3-Clause "New" or "Revised" License
168 stars 39 forks source link

Cannot use field(s) from source processor (beforeLoad) #45

Closed advocat closed 3 years ago

advocat commented 3 years ago

Example: You are want to join some field (stored in separate table) to product grid You can use native collection and processor with join data on beforeLoad

    <source>
        <collection>\Magento\Catalog\Model\ResourceModel\Product\Collection</collection>
        <processors>
            <processor class="\Your\Extension\Model\Hyva\GridSource\ProductGridProcessor"/>
        </processors>
    </source>

But you cannot use field in grid definition like

    <columns>
        <include>
            <column name="custom_filed"/>
        </include>
    </columns>

As Result: Exception #0 (OutOfBoundsException): Column(s) not found on source: custom_filed

Please advise designed solution for?

I can define own collection and join this field in init select, but looking for some easy way, which allows to easy extend data from different extensions

Also, if you want to use plugin for \Hyva\Admin\Model\GridSourceType\CollectionGridSourceType - you cannot access to gridName variable

Ideally, if we have defined excluded fields - not extract them, especially linked products, etc

Vinai commented 3 years ago

Hi Victor,

thanks for opening the issue! So far I never had to deal with this scenario, so it isn't supported yet. I've only worked with the collection provider with custom collections that joined tables in the init select, but the scenario you describe should be absolutely supported. I'll add a bug label to this issue and hope to have a solution this week.

Also, if you want to use plugin for \Hyva\Admin\Model\GridSourceType\CollectionGridSourceType - you cannot access to gridName variable

Time to add a getGridName() method.

Ideally, if we have defined excluded fields - not extract them, especially linked products, etc

I' not sure I understand correctly, but what I think you are saying is to not load the data for excluded fields, right? This is actually something that was done on purpose. It should be possible to exclude fields, so they are not rendered in the grid automatically, and still render them in combined columns using custom templates. I've had to do that a few times.

Does that answer this question?

advocat commented 3 years ago

Vinai, let me explain more details about exclude scenario. This is more related to performance and extra data that are never use in grid. Maybe more correct request here is extract only included fields if they are specified.

Precondition: you have a real catalog (not sample data) with 100 custom attributes, with assigned related, upsell, crosssell. You create a grid and specify only 20 attributes that are requires for you with includes.

Expected Result: the system processes (extract) only your specified attributes for render

Actual Result: the system processes all EAV attributes for each product individually and in case 50 products per page - try to load related, upsell, crosssell collections for each row.

Possible workaround: Defines event for hyva_grid_column_definition_build_after and remove all heavy columns or just keep specified in includes node.

I didn't check scenario (saw in examples) when specified additional filters which are not present in includes in columns

Vinai commented 3 years ago

@advocat I've opened a separate issue #46 to track the exclude columns topic.

Vinai commented 3 years ago

Regarding the join field, I've decided to introduce a new interface that is specific for collection source type processors: \Hyva\Admin\Api\HyvaGridCollectionProcessorInterface

It declares a method afterInitSelect that can be used to join fields before the available columns are extracted or the search criteria is applied.

public function afterInitSelect(AbstractDbCollection $source, string $gridName): void

The new interface extends the HyvaGridSourceProcessorInterface.

Here is the test I used to reproduce the issue and to confirm the new interface works as intended:

    /**
     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
     * @magentoDataFixture Magento/Catalog/_files/products_list.php
     */
    public function testAfterInitSelectProcessorCanJoinFieldsForGrid(): void
    {
        $processor = new class() extends AbstractGridSourceProcessor implements HyvaGridCollectionProcessorInterface {

            public function afterInitSelect(AbstractDbCollection $source, string $gridName): void
            {
                $select = $source->getSelect();

                // add select expression
                $select->columns(['foo' => new \Zend_Db_Expr('foo')]);

                // add field from joined table
                $source->getSelect()->joinLeft(
                    'catalog_category_product',
                    'e.entity_id = catalog_category_product.product_id',
                    ['test_field' => 'catalog_category_product.entity_id']
                );
            }
        };

        $args = [
            'gridName'            => 'test',
            'processors'          => [$processor],
            'sourceConfiguration' => ['collection' => ProductCollection::class],
        ];

        /** @var CollectionGridSourceType $sut */
        $sut = ObjectManager::getInstance()->create(CollectionGridSourceType::class, $args);

        $columnKeys = $sut->getColumnKeys();

        $this->assertContains('foo', $columnKeys); // select expression
        $this->assertContains('test_field', $columnKeys); // joined field
        $this->assertContains('sku', $columnKeys); // entity table attribute
        $this->assertContains('color', $columnKeys); // eav attribute
    }

I'll roll a release shortly and hope that solves that issue for you. I'll also add the getter for the grid name in the release.

Vinai commented 3 years ago

Released in 1.1.14. Documentation updates:

New Interface:

Example in test: