Skip to content

Commit

Permalink
MC-24195: Filter groups not applying correctly for customer search
Browse files Browse the repository at this point in the history
  • Loading branch information
Viktor Kopin committed Nov 10, 2020
1 parent 05b2748 commit 2638e0f
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

declare(strict_types=1);

namespace Magento\Framework\View\Element\UiComponent\DataProvider;

use Magento\Framework\Api\Filter;
use Magento\Framework\Api\Search\FilterGroup;
use Magento\Framework\Api\Search\SearchCriteriaInterface;
use Magento\Framework\ObjectManagerInterface;
use Magento\TestFramework\Helper\Bootstrap;
use PHPUnit\Framework\TestCase;

/**
* Represents FilterPool methods test class
*/
class ReportingTest extends TestCase
{
/**
* @var ObjectManagerInterface
*/
private $objectManager;

/**
* @inheritdoc
*/
protected function setUp(): void
{
$this->objectManager = Bootstrap::getObjectManager();
}

/**
* @magentoDataFixture Magento/Customer/_files/five_repository_customers.php
* @magentoDbIsolation disabled
* @dataProvider filtersDataProvider
* @param array $filters
* @param int $expectedCount
*/
public function testSearchItemsByOrCondition(array $filters, int $expectedCount): void
{
$filterGroups = [];
$filterGroups[] = $this->objectManager->create(FilterGroup::class)
->setFilters(
[
$this->objectManager->create(Filter::class, ['data' => $filters[0]]),
$this->objectManager->create(Filter::class, ['data' => $filters[1]]),
]
);
$filterGroups[] = $this->objectManager->create(FilterGroup::class)
->setFilters([$this->objectManager->create(Filter::class, ['data' => $filters[2]])]);
if (isset($filters[3], $filters[4])) {
$filterGroups[] = $this->objectManager->create(FilterGroup::class)
->setFilters(
[
$this->objectManager->create(Filter::class, ['data' => $filters[3]]),
$this->objectManager->create(Filter::class, ['data' => $filters[4]]),
]
);
}

/** @var SearchCriteriaInterface $searchCriteria */
$searchCriteria = $this->objectManager->get(SearchCriteriaInterface::class);
$searchCriteria->setFilterGroups($filterGroups);
$searchCriteria->setRequestName('customer_listing_data_source');
$searchCriteria->setSortOrders([]);

/** @var Reporting $reporting */
$reporting = $this->objectManager->get(Reporting::class);
$collection = $reporting->search($searchCriteria);
self::assertCount($expectedCount, $collection->getItems(), 'Wrong collection filters applied');
}

/**
* @return array[]
*/
public function filtersDataProvider()
{
return [
'variation 1 (filter OR filter) AND filter' => [
'filters' => [
[
'field' => 'email',
'value' => '%1%',
'condition_type' => 'like',
],
[
'field' => 'email',
'value' => '%2%',
'condition_type' => 'like',
],
[
'field' => 'name',
'value' => 'John Smith',
'condition_type' => 'eq',
],
],
'expected_count' => 2,
],
'variation 2 (filter OR filter) AND filter' => [
'filters' => [
[
'field' => 'email',
'value' => '%1%',
'condition_type' => 'like',
],
[
'field' => 'name',
'value' => 'John Smith',
'condition_type' => 'eq',
],
[
'field' => 'email',
'value' => '%example%',
'condition_type' => 'like',
],
],
'expected_count' => 5,
],
'variation 3 (filter OR filter) AND filter' => [
'filters' => [
[
'field' => 'email',
'value' => 'customer%',
'condition_type' => 'like',
],
[
'field' => 'name',
'value' => 'John%',
'condition_type' => 'like',
],
[
'field' => 'email',
'value' => 'customer2@example.com',
'condition_type' => 'eq',
],
],
'expected_count' => 1,
],
'variation (filter OR filter) AND filter AND (filter OR filter)' => [
'filters' => [
[
'field' => 'email',
'value' => 'customer%',
'condition_type' => 'like',
],
[
'field' => 'name',
'value' => 'Test',
'condition_type' => 'eq',
],
[
'field' => 'email',
'value' => 'customer%@example.com',
'condition_type' => 'like',
],
[
'field' => 'name',
'value' => 'non existing',
'condition_type' => 'like',
],
[
'field' => 'email',
'value' => 'customer3%',
'condition_type' => 'like',
],
],
'expected_count' => 1,
],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

use Magento\Framework\Data\Collection;
use Magento\Framework\Api\Search\SearchCriteriaInterface;
use Magento\Framework\Data\Collection\AbstractDb;
use Magento\Framework\DB\Select;

/**
* Filter poll apply filters from search criteria
Expand All @@ -34,17 +36,47 @@ public function __construct(array $appliers = [])
/**
* Apply filters from search criteria
*
* @param Collection $collection
* @param Collection|AbstractDb $collection
* @param SearchCriteriaInterface $criteria
* @return void
*/
public function applyFilters(Collection $collection, SearchCriteriaInterface $criteria)
{
$groupedParts = $collection->getSelect()->getPart(Select::WHERE);
foreach ($criteria->getFilterGroups() as $filterGroup) {
$filterParts = [];
foreach ($filterGroup->getFilters() as $filter) {
$filterApplier = $this->appliers[$filter->getConditionType()] ?? $this->appliers['regular'];
$filterApplier->apply($collection, $filter);
$whereParts = $collection->getSelect()->getPart(Select::WHERE);
if (is_array($whereParts) && count($whereParts)) {
$appliedParts = array_diff($whereParts, $groupedParts);
foreach ($appliedParts as $part) {
$filterParts[] = $this->preparePart($part);
}
}
$collection->getSelect()->reset(Select::WHERE);
$collection->getSelect()->setPart(Select::WHERE, $groupedParts);
}
if (count($filterParts)) {
$resultCondition = '((' . implode(') ' . Select::SQL_OR . ' (', $filterParts) . '))';
$groupedParts[] = (count($groupedParts) ? Select::SQL_AND : '') . ' ' . $resultCondition;
$collection->getSelect()->setPart(Select::WHERE, $groupedParts);
}
}
if (count($groupedParts)) {
$collection->getSelect()->setPart(Select::WHERE, $groupedParts);
}
}

/**
* Remove were join condition in the beginning of applied filter
*
* @param string $part
* @return string
*/
private function preparePart(string $part): string
{
return preg_replace('/^(' . Select::SQL_OR . '|' . Select::SQL_AND . ')\s+/i', '', trim($part), 1);
}
}

0 comments on commit 2638e0f

Please sign in to comment.