Skip to content

Commit 7c4cbef

Browse files
committed
MC-32388: Add url_path as a possible filter in categoryList query
- refactor only. no functional change
1 parent 047f5b9 commit 7c4cbef

File tree

5 files changed

+149
-61
lines changed

5 files changed

+149
-61
lines changed

app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77

88
namespace Magento\CatalogGraphQl\Model\Category;
99

10+
use Magento\Catalog\Api\CategoryListInterface;
1011
use Magento\Catalog\Api\Data\CategoryInterface;
11-
use Magento\Catalog\Model\ResourceModel\Category\Collection;
1212
use Magento\Framework\App\Config\ScopeConfigInterface;
1313
use Magento\Framework\Exception\InputException;
14+
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\ArgumentApplier\Filter;
15+
use Magento\Search\Model\Query;
1416
use Magento\Store\Api\Data\StoreInterface;
1517
use Magento\Store\Model\ScopeInterface;
16-
use Magento\Search\Model\Query;
18+
use Magento\Framework\GraphQl\Query\Resolver\Argument\SearchCriteria\Builder;
1719

1820
/**
1921
* Category filter allows to filter collection using 'id, url_key, name' from search criteria.
@@ -25,78 +27,86 @@ class CategoryFilter
2527
*/
2628
private $scopeConfig;
2729

30+
/**
31+
* @var CategoryListInterface
32+
*/
33+
private $categoryList;
34+
35+
/**
36+
* @var Builder
37+
*/
38+
private $searchCriteriaBuilder;
39+
2840
/**
2941
* @param ScopeConfigInterface $scopeConfig
42+
* @param CategoryListInterface $categoryList
43+
* @param Builder $searchCriteriaBuilder
3044
*/
3145
public function __construct(
32-
ScopeConfigInterface $scopeConfig
46+
ScopeConfigInterface $scopeConfig,
47+
CategoryListInterface $categoryList,
48+
Builder $searchCriteriaBuilder
3349
) {
3450
$this->scopeConfig = $scopeConfig;
51+
$this->categoryList = $categoryList;
52+
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
3553
}
3654

3755
/**
38-
* Filter for filtering the requested categories id's based on url_key, ids, name in the result.
56+
* Search for categories, return list of ids
3957
*
40-
* @param array $args
41-
* @param Collection $categoryCollection
58+
* @param array $criteria
4259
* @param StoreInterface $store
43-
* @throws InputException
60+
* @return int[]
4461
*/
45-
public function applyFilters(array $args, Collection $categoryCollection, StoreInterface $store)
62+
public function getCategoryIds(array $criteria, StoreInterface $store): array
4663
{
47-
$categoryCollection->addAttributeToFilter(CategoryInterface::KEY_IS_ACTIVE, ['eq' => 1]);
48-
foreach ($args['filters'] as $field => $cond) {
49-
foreach ($cond as $condType => $value) {
50-
if ($field === 'ids') {
51-
$categoryCollection->addIdFilter($value);
52-
} else {
53-
$this->addAttributeFilter($categoryCollection, $field, $condType, $value, $store);
54-
}
55-
}
64+
$categoryIds = [];
65+
try {
66+
$criteria[Filter::ARGUMENT_NAME] = $this->formatMatchFilters($criteria['filters'], $store);
67+
} catch (InputException $e) {
68+
//Return empty set when match filter is too short. (matches search api behavior)
69+
return $categoryIds;
5670
}
57-
}
71+
$criteria[Filter::ARGUMENT_NAME][CategoryInterface::KEY_IS_ACTIVE] = ['eq' => 1];
5872

59-
/**
60-
* Add filter to category collection
61-
*
62-
* @param Collection $categoryCollection
63-
* @param string $field
64-
* @param string $condType
65-
* @param string|array $value
66-
* @param StoreInterface $store
67-
* @throws InputException
68-
*/
69-
private function addAttributeFilter($categoryCollection, $field, $condType, $value, $store)
70-
{
71-
if ($condType === 'match') {
72-
$this->addMatchFilter($categoryCollection, $field, $value, $store);
73-
return;
73+
$searchCriteria = $this->searchCriteriaBuilder->build('categoryList', $criteria);
74+
$categories = $this->categoryList->getList($searchCriteria);
75+
foreach ($categories->getItems() as $category) {
76+
$categoryIds[] = (int)$category->getId();
7477
}
75-
$categoryCollection->addAttributeToFilter($field, [$condType => $value]);
78+
return $categoryIds;
7679
}
7780

7881
/**
79-
* Add match filter to collection
82+
* Format match filters to behave like fuzzy match
8083
*
81-
* @param Collection $categoryCollection
82-
* @param string $field
83-
* @param string $value
84+
* @param array $filters
8485
* @param StoreInterface $store
86+
* @return array
8587
* @throws InputException
8688
*/
87-
private function addMatchFilter($categoryCollection, $field, $value, $store)
89+
private function formatMatchFilters(array $filters, StoreInterface $store): array
8890
{
8991
$minQueryLength = $this->scopeConfig->getValue(
9092
Query::XML_PATH_MIN_QUERY_LENGTH,
9193
ScopeInterface::SCOPE_STORE,
9294
$store
9395
);
94-
$searchValue = str_replace('%', '', $value);
95-
$matchLength = strlen($searchValue);
96-
if ($matchLength < $minQueryLength) {
97-
throw new InputException(__('Invalid match filter'));
98-
}
9996

100-
$categoryCollection->addAttributeToFilter($field, ['like' => "%{$searchValue}%"]);
97+
foreach ($filters as $filter => $condition) {
98+
$conditionType = array_keys($condition)[0];
99+
if ($conditionType === 'match') {
100+
$searchValue = $condition[$conditionType];
101+
$matchLength = strlen(trim($searchValue));
102+
if ($matchLength < $minQueryLength) {
103+
throw new InputException(__('Invalid match filter'));
104+
}
105+
unset($filters[$filter]['match']);
106+
$filters[$filter]['like'] = '%' . $searchValue . '%';
107+
108+
}
109+
}
110+
return $filters;
101111
}
102112
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogGraphQl\Model\Category;
9+
10+
use Magento\Framework\GraphQl\ConfigInterface;
11+
use Magento\Framework\GraphQl\Query\Resolver\Argument\FieldEntityAttributesInterface;
12+
13+
/**
14+
* Retrieves attributes for a field for the ast converter
15+
*/
16+
class CategoryFilterAttributesForAst implements FieldEntityAttributesInterface
17+
{
18+
/**
19+
* Map schema fields to entity attributes
20+
*
21+
* @var array
22+
*/
23+
private $fieldMapping = [
24+
'ids' => 'entity_id'
25+
];
26+
27+
/**
28+
* @var array
29+
*/
30+
private $additionalFields = [
31+
'is_active'
32+
];
33+
34+
/**
35+
* @var ConfigInterface
36+
*/
37+
private $config;
38+
39+
/**
40+
* @param ConfigInterface $config
41+
* @param array $additionalFields
42+
* @param array $attributeFieldMapping
43+
*/
44+
public function __construct(
45+
ConfigInterface $config,
46+
array $additionalFields = [],
47+
array $attributeFieldMapping = []
48+
) {
49+
$this->config = $config;
50+
$this->additionalFields = array_merge($this->additionalFields, $additionalFields);
51+
$this->fieldMapping = array_merge($this->fieldMapping, $attributeFieldMapping);
52+
}
53+
54+
/**
55+
* @inheritdoc
56+
*
57+
* Gather attributes for Category filtering
58+
* Example format ['attributeNameInGraphQl' => ['type' => 'String'. 'fieldName' => 'attributeNameInSearchCriteria']]
59+
*
60+
* @return array
61+
*/
62+
public function getEntityAttributes() : array
63+
{
64+
$categoryFilterType = $this->config->getConfigElement('CategoryFilterInput');
65+
66+
if (!$categoryFilterType) {
67+
throw new \LogicException(__("CategoryFilterInput type not defined in schema."));
68+
}
69+
70+
$fields = [];
71+
foreach ($categoryFilterType->getFields() as $field) {
72+
$fields[$field->getName()] = [
73+
'type' => 'String',
74+
'fieldName' => $this->fieldMapping[$field->getName()] ?? $field->getName(),
75+
];
76+
}
77+
78+
foreach ($this->additionalFields as $additionalField) {
79+
$fields[$additionalField] = [
80+
'type' => 'String',
81+
'fieldName' => $additionalField,
82+
];
83+
}
84+
85+
return $fields;
86+
}
87+
}

app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
namespace Magento\CatalogGraphQl\Model\Resolver;
99

1010
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ExtractDataFromCategoryTree;
11-
use Magento\Framework\Exception\InputException;
1211
use Magento\Framework\GraphQl\Config\Element\Field;
1312
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
1413
use Magento\Framework\GraphQl\Query\ResolverInterface;
@@ -74,20 +73,10 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
7473
if (!isset($args['filters'])) {
7574
$rootCategoryIds[] = (int)$store->getRootCategoryId();
7675
} else {
77-
$categoryCollection = $this->collectionFactory->create();
78-
try {
79-
$this->categoryFilter->applyFilters($args, $categoryCollection, $store);
80-
} catch (InputException $e) {
81-
return [];
82-
}
83-
84-
foreach ($categoryCollection as $category) {
85-
$rootCategoryIds[] = (int)$category->getId();
86-
}
76+
$rootCategoryIds = $this->categoryFilter->getCategoryIds($args, $store);
8777
}
8878

89-
$result = $this->fetchCategories($rootCategoryIds, $info);
90-
return $result;
79+
return $this->fetchCategories($rootCategoryIds, $info);
9180
}
9281

9382
/**

app/code/Magento/CatalogGraphQl/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<arguments>
3737
<argument name="attributesInstances" xsi:type="array">
3838
<item name="products" xsi:type="object">Magento\CatalogGraphQl\Model\Resolver\Products\FilterArgument\ProductEntityAttributesForAst</item>
39+
<item name="categoryList" xsi:type="object">Magento\CatalogGraphQl\Model\Category\CategoryFilterAttributesForAst</item>
3940
</argument>
4041
</arguments>
4142
</type>

dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ protected function setUp()
3131
/**
3232
* @magentoApiDataFixture Magento/Catalog/_files/categories.php
3333
* @dataProvider filterSingleCategoryDataProvider
34-
* @param $field
35-
* @param $condition
36-
* @param $value
34+
* @param string $field
35+
* @param string $condition
36+
* @param string $value
37+
* @param array $expectedResult
3738
*/
3839
public function testFilterSingleCategoryByField($field, $condition, $value, $expectedResult)
3940
{

0 commit comments

Comments
 (0)