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

Filter on joined columns in a collectionGridProcessor doesn't work as the COUNT(*) query removes aliases #55

Open Mordreak opened 3 years ago

Mordreak commented 3 years ago

Steps to reproduce :

/!\ I only tried this with a text field, but I guess this is the same for any other column type.

If I remember well, in the magento 1 grid builder we had to add a "filter_index" attribute on the column definition to let the grid know that it must filter with the real "table.column_name" instead of the alias. Maybe it could be a solution

Capture d’écran 2021-06-22 à 17 30 14
Vinai commented 3 years ago

Wrote a test to reproduce the issue:

/**
 * @magentoDataFixture Magento/Cms/_files/block.php
 * @magentoDataFixture Magento/Cms/_files/blocks.php
 */
public function testFilterJoinedFieldonFlatTableCollection(): void
{
    $processor = new class() extends AbstractGridSourceProcessor implements HyvaGridCollectionProcessorInterface {

        /**
         * @param CmsBlockCollection $source
         * @param string $gridName
         */
        public function afterInitSelect(AbstractDbCollection $source, string $gridName): void
        {
            $select = $source->getSelect();
            // add field from joined table
            $source->getSelect()->joinLeft(
                'cms_block_store',
                'main_table.block_id = cms_block_store.block_id',
                ['test_field' => 'cms_block_store.store_id']
            );
        }
    };

    $args = [
        'gridName'            => 'test',
        'processors'          => [$processor],
        'sourceConfiguration' => ['collection' => CmsBlockCollection::class],
    ];
    /** @var CollectionGridSourceType $sut */
    $sut = ObjectManager::getInstance()->create(CollectionGridSourceType::class, $args);

    /** @var SearchCriteriaBuilder $searchCriteriaBuilder */
    $searchCriteriaBuilder = ObjectManager::getInstance()->get(SearchCriteriaBuilder::class);
    $searchCriteriaBuilder->addFilter('test_field', '1');

    $rawGridData = $sut->fetchData($searchCriteriaBuilder->create());
    $records = $sut->extractRecords($rawGridData);
    $this->assertGreaterThan(0, count($records));
}

Considerations:

  1. Considered mapping field names to their aliases in the Navigation::getSearchCriteria view model method, but dismissed the idea because it would expose the view model to the implementation details of the underlying grid source type.
  2. The other likely solution is to use a HyvaGridSourceProcessor::beforeLoad method in \Hyva\Admin\Model\GridSourceType\CollectionGridSourceType::fetchData before the search criteria is applied to the collection. Dismissed this idea because mutating the search criteria would cause multiple loads.
  3. The next option would also be applied in \Hyva\Admin\Model\GridSourceType\CollectionGridSourceType::fetchData, but instead of using a processor, hardcode the mapping of aliases to real column names for flat table collections. This would probably involve cloning the search criteria after the processor beforeLoad methods where called to avoid duplicate loading.