Skip to content

Commit 80eda41

Browse files
committed
MC-39508: Spreading multiple GraphQL fragments into CategoryTree causes Magento to throw
1 parent 592c792 commit 80eda41

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

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

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

88
namespace Magento\CatalogGraphQl\Model\Category;
99

10+
use GraphQL\Language\AST\Node;
1011
use GraphQL\Language\AST\FieldNode;
1112
use GraphQL\Language\AST\InlineFragmentNode;
1213
use GraphQL\Language\AST\NodeKind;
@@ -26,22 +27,35 @@ class DepthCalculator
2627
*/
2728
public function calculate(ResolveInfo $resolveInfo, FieldNode $fieldNode) : int
2829
{
29-
$selections = $fieldNode->selectionSet->selections ?? [];
30+
return $this->calculateRecursive($resolveInfo, $fieldNode);
31+
}
32+
33+
/**
34+
* Calculate recursive the total depth of a category tree inside a GraphQL request
35+
*
36+
* @param ResolveInfo $resolveInfo
37+
* @param Node $node
38+
* @return int
39+
*/
40+
private function calculateRecursive(ResolveInfo $resolveInfo, Node $node) : int
41+
{
42+
if ($node->kind === NodeKind::FRAGMENT_SPREAD) {
43+
$selections = isset($resolveInfo->fragments[$node->name->value]) ?
44+
$resolveInfo->fragments[$node->name->value]->selectionSet->selections : [];
45+
} else {
46+
$selections = $node->selectionSet->selections ?? [];
47+
}
3048
$depth = count($selections) ? 1 : 0;
3149
$childrenDepth = [0];
32-
foreach ($selections as $node) {
33-
if (isset($node->alias) && null !== $node->alias) {
50+
foreach ($selections as $subNode) {
51+
if (isset($subNode->alias) && null !== $subNode->alias) {
3452
continue;
3553
}
3654

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-
}
55+
if ($subNode->kind === NodeKind::INLINE_FRAGMENT) {
56+
$childrenDepth[] = $this->addInlineFragmentDepth($resolveInfo, $subNode);
4357
} else {
44-
$childrenDepth[] = $this->calculate($resolveInfo, $node);
58+
$childrenDepth[] = $this->calculateRecursive($resolveInfo, $subNode);
4559
}
4660
}
4761

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,4 +842,49 @@ public function testFilterCategoryNamedFragment()
842842
$this->assertEquals($result['categoryList'][0]['uid'], base64_encode('6'));
843843
$this->assertEquals($result['categoryList'][0]['url_path'], 'category-2');
844844
}
845+
846+
/**
847+
* Test when there is recursive category node fragment
848+
*
849+
* @magentoApiDataFixture Magento/Catalog/_files/categories.php
850+
*/
851+
public function testFilterCategoryRecursiveFragment() : void
852+
{
853+
$query = <<<'QUERY'
854+
query GetCategoryTree($filters: CategoryFilterInput!) {
855+
categoryList(filters: $filters) {
856+
...recursiveCategoryNode
857+
}
858+
}
859+
860+
fragment recursiveCategoryNode on CategoryTree {
861+
...categoryNode
862+
children {
863+
...categoryNode
864+
}
865+
}
866+
867+
fragment categoryNode on CategoryTree {
868+
id
869+
}
870+
QUERY;
871+
$variables = [
872+
'filters' => [
873+
'ids' => [
874+
'eq' => '2',
875+
],
876+
],
877+
];
878+
$result = $this->graphQlQuery($query, $variables);
879+
$this->assertArrayNotHasKey('errors', $result);
880+
$this->assertCount(1, $result['categoryList']);
881+
$this->assertCount(2, $result['categoryList'][0]);
882+
$this->assertArrayHasKey('id', $result['categoryList'][0]);
883+
$this->assertArrayHasKey('children', $result['categoryList'][0]);
884+
$this->assertEquals($result['categoryList'][0]['id'], '2');
885+
$this->assertCount(7, $result['categoryList'][0]['children']);
886+
$this->assertCount(1, $result['categoryList'][0]['children'][0]);
887+
$this->assertArrayHasKey('id', $result['categoryList'][0]['children'][0]);
888+
$this->assertEquals($result['categoryList'][0]['children'][0]['id'], '3');
889+
}
845890
}

0 commit comments

Comments
 (0)