Skip to content

Commit 4511c46

Browse files
author
Munkh-Ulzii Balidar
committed
28584 fixed issue category query does not handle fragments
28584 fix typo 28584 fix typo 28584 implement fragment spread for category
1 parent dc14e50 commit 4511c46

File tree

7 files changed

+182
-23
lines changed

7 files changed

+182
-23
lines changed

app/code/Magento/CatalogGraphQl/Model/AttributesJoiner.php

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
namespace Magento\CatalogGraphQl\Model;
99

1010
use GraphQL\Language\AST\FieldNode;
11+
use GraphQL\Language\AST\FragmentSpreadNode;
12+
use GraphQL\Language\AST\InlineFragmentNode;
13+
use GraphQL\Language\AST\NodeKind;
1114
use Magento\Eav\Model\Entity\Collection\AbstractCollection;
15+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1216

1317
/**
1418
* Joins attributes for provided field node field names.
@@ -30,6 +34,11 @@ class AttributesJoiner
3034
*/
3135
private $fieldToAttributeMap = [];
3236

37+
/**
38+
* @var ResolveInfo
39+
*/
40+
private $resolverInfo = null;
41+
3342
/**
3443
* @param array $fieldToAttributeMap
3544
*/
@@ -65,17 +74,54 @@ public function getQueryFields(FieldNode $fieldNode): array
6574
$selectedFields = [];
6675
/** @var FieldNode $field */
6776
foreach ($query as $field) {
68-
if ($field->kind === 'InlineFragment') {
69-
continue;
77+
if ($field->kind === NodeKind::INLINE_FRAGMENT) {
78+
$inlineFragmentFields = $this->addInlineFragmentFields($field);
79+
$selectedFields = array_merge($selectedFields, $inlineFragmentFields);
80+
} elseif ($field->kind === NodeKind::FRAGMENT_SPREAD && isset($this->resolverInfo->fragments[$field->name->value])) {
81+
foreach ($this->resolverInfo->fragments[$field->name->value]->selectionSet->selections as $spreadNode) {
82+
if (isset($spreadNode->selectionSet->selections)) {
83+
$fragmentSpreadFields = $this->getQueryFields($spreadNode);
84+
$selectedFields = array_merge($selectedFields, $fragmentSpreadFields);
85+
} else {
86+
$selectedFields[] = $spreadNode->name->value;
87+
}
88+
}
89+
} else {
90+
$selectedFields[] = $field->name->value;
7091
}
71-
$selectedFields[] = $field->name->value;
7292
}
7393
$this->setSelectionsForFieldNode($fieldNode, $selectedFields);
7494
}
7595

7696
return $this->getFieldNodeSelections($fieldNode);
7797
}
7898

99+
/**
100+
* Add fields from inline fragment nodes
101+
*
102+
* @param InlineFragmentNode $inlineFragmentField
103+
* @param array $inlineFragmentFields
104+
* @return string[]
105+
*/
106+
private function addInlineFragmentFields(InlineFragmentNode $inlineFragmentField, $inlineFragmentFields = [])
107+
{
108+
$query = $inlineFragmentField->selectionSet->selections;
109+
/** @var FieldNode $field */
110+
foreach ($query as $field) {
111+
if ($field->kind === NodeKind::INLINE_FRAGMENT) {
112+
$this->addInlineFragmentFields($field, $inlineFragmentFields);
113+
} elseif (isset($field->selectionSet->selections)) {
114+
if (is_array($queryFields = $this->getQueryFields($field))) {
115+
$inlineFragmentFields = array_merge($inlineFragmentFields, $queryFields);
116+
}
117+
} else {
118+
$inlineFragmentFields[] = $field->name->value;
119+
}
120+
}
121+
122+
return array_unique($inlineFragmentFields);
123+
}
124+
79125
/**
80126
* Add field to collection select
81127
*
@@ -124,4 +170,12 @@ private function setSelectionsForFieldNode(FieldNode $fieldNode, array $selected
124170
{
125171
$this->queryFields[$fieldNode->name->value][$fieldNode->name->loc->start] = $selectedFields;
126172
}
173+
174+
/**
175+
* @param ResolveInfo $resolverInfo
176+
*/
177+
public function setResolverInfo(ResolveInfo $resolverInfo): void
178+
{
179+
$this->resolverInfo = $resolverInfo;
180+
}
127181
}

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

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
namespace Magento\CatalogGraphQl\Model\Category;
99

1010
use GraphQL\Language\AST\FieldNode;
11+
use GraphQL\Language\AST\InlineFragmentNode;
12+
use GraphQL\Language\AST\NodeKind;
13+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1114

1215
/**
1316
* Used for determining the depth information for a requested category tree in a GraphQL request
@@ -17,22 +20,54 @@ class DepthCalculator
1720
/**
1821
* Calculate the total depth of a category tree inside a GraphQL request
1922
*
23+
* @param ResolveInfo $resolveInfo
2024
* @param FieldNode $fieldNode
2125
* @return int
2226
*/
23-
public function calculate(FieldNode $fieldNode) : int
27+
public function calculate(ResolveInfo $resolveInfo, FieldNode $fieldNode) : int
2428
{
2529
$selections = $fieldNode->selectionSet->selections ?? [];
2630
$depth = count($selections) ? 1 : 0;
2731
$childrenDepth = [0];
2832
foreach ($selections as $node) {
29-
if ($node->kind === 'InlineFragment' || null !== $node->alias) {
33+
if (isset($node->alias) && null !== $node->alias) {
3034
continue;
3135
}
3236

33-
$childrenDepth[] = $this->calculate($node);
37+
if ($node->kind === NodeKind::INLINE_FRAGMENT) {
38+
$childrenDepth[] = $this->addInlineFragmentDepth($resolveInfo, $node);
39+
} elseif ($node->kind === NodeKind::FRAGMENT_SPREAD && isset($resolveInfo->fragments[$node->name->value])) {
40+
foreach ($resolveInfo->fragments[$node->name->value]->selectionSet->selections as $spreadNode) {
41+
$childrenDepth[] = $this->calculate($resolveInfo, $spreadNode);
42+
}
43+
} else {
44+
$childrenDepth[] = $this->calculate($resolveInfo, $node);
45+
}
3446
}
3547

3648
return $depth + max($childrenDepth);
3749
}
50+
51+
/**
52+
* Add inline fragment fields into calculating of category depth
53+
*
54+
* @param ResolveInfo $resolveInfo
55+
* @param InlineFragmentNode $inlineFragmentField
56+
* @param array $depth
57+
* @return int[]
58+
*/
59+
private function addInlineFragmentDepth(ResolveInfo $resolveInfo, InlineFragmentNode $inlineFragmentField, $depth = [])
60+
{
61+
$selections = $inlineFragmentField->selectionSet->selections;
62+
/** @var FieldNode $field */
63+
foreach ($selections as $field) {
64+
if ($field->kind === NodeKind::INLINE_FRAGMENT) {
65+
$depth[] = $this->addInlineFragmentDepth($resolveInfo, $field, $depth);
66+
} elseif ($field->selectionSet && $field->selectionSet->selections) {
67+
$depth[] = $this->calculate($resolveInfo, $field);
68+
}
69+
}
70+
71+
return $depth ? max($depth) : 0;
72+
}
3873
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77

88
namespace Magento\CatalogGraphQl\Model\Resolver;
99

10-
use Magento\CatalogGraphQl\Model\Resolver\Product\ProductCategories;
11-
use Magento\Framework\Exception\LocalizedException;
12-
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1310
use Magento\Catalog\Api\Data\CategoryInterface;
1411
use Magento\Catalog\Model\ResourceModel\Category\Collection;
1512
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
1613
use Magento\CatalogGraphQl\Model\AttributesJoiner;
14+
use Magento\CatalogGraphQl\Model\Category\Hydrator as CategoryHydrator;
15+
use Magento\CatalogGraphQl\Model\Resolver\Product\ProductCategories;
1716
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\CustomAttributesFlattener;
17+
use Magento\Framework\Exception\LocalizedException;
1818
use Magento\Framework\GraphQl\Config\Element\Field;
19-
use Magento\Framework\GraphQl\Query\ResolverInterface;
2019
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
21-
use Magento\CatalogGraphQl\Model\Category\Hydrator as CategoryHydrator;
20+
use Magento\Framework\GraphQl\Query\ResolverInterface;
21+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
2222
use Magento\Store\Model\StoreManagerInterface;
2323

2424
/**
@@ -112,6 +112,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
112112
$categoryIds = $this->productCategories->getCategoryIdsByProduct((int)$product->getId(), (int)$storeId);
113113
$this->categoryIds = array_merge($this->categoryIds, $categoryIds);
114114
$that = $this;
115+
$that->attributesJoiner->setResolverInfo($info);
115116

116117
return $this->valueFactory->create(
117118
function () use ($that, $categoryIds, $info) {

app/code/Magento/CatalogGraphQl/Model/Resolver/Product/ProductFieldsSelector.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Magento\CatalogGraphQl\Model\Resolver\Product;
99

10+
use GraphQL\Language\AST\NodeKind;
1011
use Magento\Framework\GraphQl\Query\FieldTranslator;
1112
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1213

@@ -43,9 +44,9 @@ public function getProductFieldsFromInfo(ResolveInfo $info, string $productNodeN
4344
continue;
4445
}
4546
foreach ($node->selectionSet->selections as $selectionNode) {
46-
if ($selectionNode->kind === 'InlineFragment') {
47+
if ($selectionNode->kind === NodeKind::INLINE_FRAGMENT) {
4748
foreach ($selectionNode->selectionSet->selections as $inlineSelection) {
48-
if ($inlineSelection->kind === 'InlineFragment') {
49+
if ($inlineSelection->kind === NodeKind::INLINE_FRAGMENT) {
4950
continue;
5051
}
5152
$fieldNames[] = $this->fieldTranslator->translate($inlineSelection->name->value);

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
namespace Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider;
99

1010
use GraphQL\Language\AST\FieldNode;
11-
use Magento\CatalogGraphQl\Model\Category\DepthCalculator;
12-
use Magento\CatalogGraphQl\Model\Category\LevelCalculator;
13-
use Magento\Framework\EntityManager\MetadataPool;
14-
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
11+
use GraphQL\Language\AST\NodeKind;
1512
use Magento\Catalog\Api\Data\CategoryInterface;
13+
use Magento\Catalog\Model\Category;
1614
use Magento\Catalog\Model\ResourceModel\Category\Collection;
1715
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
1816
use Magento\CatalogGraphQl\Model\AttributesJoiner;
19-
use Magento\Catalog\Model\Category;
17+
use Magento\CatalogGraphQl\Model\Category\DepthCalculator;
18+
use Magento\CatalogGraphQl\Model\Category\LevelCalculator;
19+
use Magento\Framework\EntityManager\MetadataPool;
20+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
2021

2122
/**
2223
* Category tree data provider
@@ -53,6 +54,11 @@ class CategoryTree
5354
*/
5455
private $metadata;
5556

57+
/**
58+
* @var ResolveInfo
59+
*/
60+
private $resolverInfo;
61+
5662
/**
5763
* @param CollectionFactory $collectionFactory
5864
* @param AttributesJoiner $attributesJoiner
@@ -85,8 +91,10 @@ public function getTree(ResolveInfo $resolveInfo, int $rootCategoryId): \Iterato
8591
{
8692
$categoryQuery = $resolveInfo->fieldNodes[0];
8793
$collection = $this->collectionFactory->create();
94+
$this->resolverInfo = $resolveInfo;
95+
$this->attributesJoiner->setResolverInfo($resolveInfo);
8896
$this->joinAttributesRecursively($collection, $categoryQuery);
89-
$depth = $this->depthCalculator->calculate($categoryQuery);
97+
$depth = $this->depthCalculator->calculate($resolveInfo, $categoryQuery);
9098
$level = $this->levelCalculator->calculate($rootCategoryId);
9199

92100
// If root category is being filter, we've to remove first slash
@@ -137,11 +145,15 @@ private function joinAttributesRecursively(Collection $collection, FieldNode $fi
137145

138146
/** @var FieldNode $node */
139147
foreach ($subSelection as $node) {
140-
if ($node->kind === 'InlineFragment') {
148+
if ($node->kind === NodeKind::INLINE_FRAGMENT) {
141149
continue;
150+
} elseif ($node->kind === NodeKind::FRAGMENT_SPREAD && isset($this->resolverInfo->fragments[$node->name->value])) {
151+
foreach ($this->resolverInfo->fragments[$node->name->value]->selectionSet->selections as $spreadNode) {
152+
$this->joinAttributesRecursively($collection, $spreadNode);
153+
}
154+
} else {
155+
$this->joinAttributesRecursively($collection, $node);
142156
}
143-
144-
$this->joinAttributesRecursively($collection, $node);
145157
}
146158
}
147159
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/ProductSearch.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function getList(
110110
$searchResults = $this->searchResultsFactory->create();
111111
$searchResults->setSearchCriteria($searchCriteriaForCollection);
112112
$searchResults->setItems($collection->getItems());
113-
$searchResults->setTotalCount($searchResult->getTotalCount());
113+
$searchResults->setTotalCount($collection->getSize());
114114
return $searchResults;
115115
}
116116

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,4 +714,60 @@ private function assertCategoryChildren(array $category, array $expectedChildren
714714
$this->assertResponseFields($category['children'][$i], $expectedChild);
715715
}
716716
}
717+
718+
/**
719+
* @magentoApiDataFixture Magento/Catalog/_files/categories.php
720+
*/
721+
public function testFilterCategoryInlineFragment()
722+
{
723+
$query = <<<QUERY
724+
{
725+
categoryList(filters: {ids: {eq: "6"}}){
726+
... on CategoryTree {
727+
id
728+
name
729+
url_key
730+
url_path
731+
children_count
732+
path
733+
position
734+
}
735+
}
736+
}
737+
QUERY;
738+
$result = $this->graphQlQuery($query);
739+
$this->assertArrayNotHasKey('errors', $result);
740+
$this->assertCount(1, $result['categoryList']);
741+
$this->assertEquals($result['categoryList'][0]['name'], 'Category 2');
742+
$this->assertEquals($result['categoryList'][0]['url_path'], 'category-2');
743+
}
744+
745+
/**
746+
* @magentoApiDataFixture Magento/Catalog/_files/categories.php
747+
*/
748+
public function testFilterCategoryNamedFragment()
749+
{
750+
$query = <<<QUERY
751+
{
752+
categoryList(filters: {ids: {eq: "6"}}){
753+
...Cat
754+
}
755+
}
756+
757+
fragment Cat on CategoryTree {
758+
id
759+
name
760+
url_key
761+
url_path
762+
children_count
763+
path
764+
position
765+
}
766+
QUERY;
767+
$result = $this->graphQlQuery($query);
768+
$this->assertArrayNotHasKey('errors', $result);
769+
$this->assertCount(1, $result['categoryList']);
770+
$this->assertEquals($result['categoryList'][0]['name'], 'Category 2');
771+
$this->assertEquals($result['categoryList'][0]['url_path'], 'category-2');
772+
}
717773
}

0 commit comments

Comments
 (0)