Skip to content

Commit 203a44f

Browse files
authored
Merge pull request #7228 from magento-honey-badgers/PWA-2356-integration-test-failures
[honey] PWA-2356: Fixing schema introspection test to override GQL types first
2 parents 363ba43 + 6e94990 commit 203a44f

File tree

10 files changed

+234
-35
lines changed

10 files changed

+234
-35
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\QuoteGraphQl\Model\Cart;
10+
11+
use Magento\Quote\Model\Quote;
12+
use Magento\Quote\Model\Quote\Address;
13+
use Magento\Quote\Model\Quote\Address\Total;
14+
use Magento\Quote\Model\Quote\TotalsCollector as QuoteTotalsCollector;
15+
16+
/**
17+
* Helper class to eliminate redundant expensive total calculations
18+
*/
19+
class TotalsCollector
20+
{
21+
/**
22+
* @var QuoteTotalsCollector
23+
*/
24+
private $quoteTotalsCollector;
25+
26+
/**
27+
* @var Total[]
28+
*/
29+
private $quoteTotals;
30+
31+
/**
32+
* @var Total[][]
33+
*/
34+
private $addressTotals;
35+
36+
/**
37+
* @param QuoteTotalsCollector $quoteTotalsCollector
38+
*/
39+
public function __construct(QuoteTotalsCollector $quoteTotalsCollector)
40+
{
41+
$this->quoteTotalsCollector = $quoteTotalsCollector;
42+
$this->quoteTotals = [];
43+
$this->addressTotals = [];
44+
}
45+
46+
/**
47+
* Clear stored totals to force them to be recalculated the next time they're requested
48+
*
49+
* This is relevant for mutations which can change the results
50+
*/
51+
public function clearTotals(): void
52+
{
53+
$this->quoteTotals = [];
54+
$this->addressTotals = [];
55+
}
56+
57+
/**
58+
* Calls the base collectQuoteTotals() only if it hasn't been called before for this quote
59+
*
60+
* If the totals could have changed since the last invocation, $forceRecalculate should be true
61+
*
62+
* @param Quote $quote
63+
* @param bool $forceRecalculate
64+
* @return Total
65+
* @see QuoteTotalsCollector::collectQuoteTotals()
66+
*/
67+
public function collectQuoteTotals(Quote $quote, bool $forceRecalculate = false): Total
68+
{
69+
if ($quote->getId() === null) {
70+
return $this->quoteTotalsCollector->collectQuoteTotals($quote);
71+
}
72+
$quoteId = (string)$quote->getId();
73+
if (!isset($this->quoteTotals[$quoteId]) || $forceRecalculate) {
74+
$this->quoteTotals[$quoteId] = $this->quoteTotalsCollector->collectQuoteTotals($quote);
75+
}
76+
return $this->quoteTotals[$quoteId];
77+
}
78+
79+
/**
80+
* Calls the base collectAddressTotals() only if it hasn't been called before for this address
81+
*
82+
* If the totals could have changed since the last invocation, $forceRecalculate should be true
83+
*
84+
* @param Quote $quote
85+
* @param Address $address
86+
* @param bool $forceRecalculate
87+
* @return Total
88+
* @see QuoteTotalsCollector::collectAddressTotals()
89+
*/
90+
public function collectAddressTotals(Quote $quote, Address $address, bool $forceRecalculate = false): Total
91+
{
92+
if ($quote->getId() === null || $address->getId() === null) {
93+
return $this->quoteTotalsCollector->collectAddressTotals($quote, $address);
94+
}
95+
$quoteId = (string)$quote->getId();
96+
$addressId = (string)$address->getId();
97+
if (!isset($this->addressTotals[$quoteId])) {
98+
$this->addressTotals[$quoteId] = [];
99+
}
100+
if (!isset($this->addressTotals[$quoteId][$addressId]) || $forceRecalculate) {
101+
$this->addressTotals[$quoteId][$addressId] =
102+
$this->quoteTotalsCollector->collectAddressTotals($quote, $address);
103+
}
104+
105+
return $this->addressTotals[$quoteId][$addressId];
106+
}
107+
}

app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemPrices.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1414
use Magento\Quote\Model\Cart\Totals;
1515
use Magento\Quote\Model\Quote\Item;
16-
use Magento\Quote\Model\Quote\TotalsCollector;
16+
use Magento\QuoteGraphQl\Model\Cart\TotalsCollector;
1717

1818
/**
1919
* @inheritdoc

app/code/Magento/QuoteGraphQl/Model/Resolver/CartPrices.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1414
use Magento\Quote\Model\Quote;
1515
use Magento\Quote\Model\Quote\Address\Total;
16-
use Magento\Quote\Model\Quote\TotalsCollector;
16+
use Magento\QuoteGraphQl\Model\Cart\TotalsCollector;
1717

1818
/**
1919
* @inheritdoc

app/code/Magento/QuoteGraphQl/Model/Resolver/ShippingAddress/AvailableShippingMethods.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
1515
use Magento\Quote\Api\Data\ShippingMethodInterface;
1616
use Magento\Quote\Model\Cart\ShippingMethodConverter;
17-
use Magento\Quote\Model\Quote\TotalsCollector;
17+
use Magento\QuoteGraphQl\Model\Cart\TotalsCollector;
1818

1919
/**
2020
* @inheritdoc
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\QuoteGraphQl\Plugin;
10+
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
13+
use Magento\Framework\GraphQl\Query\ResolverInterface;
14+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
15+
use Magento\QuoteGraphQl\Model\Cart\TotalsCollector;
16+
17+
/**
18+
* Plugin to reset stored totals before a top-level resolver runs
19+
*/
20+
class ResetStoredTotalsBeforeTopResolver
21+
{
22+
/**
23+
* @var TotalsCollector
24+
*/
25+
private $totalsCollector;
26+
27+
/**
28+
* @param TotalsCollector $totalsCollector
29+
*/
30+
public function __construct(TotalsCollector $totalsCollector)
31+
{
32+
$this->totalsCollector = $totalsCollector;
33+
}
34+
35+
/**
36+
* If this resolver is at the top level, clear any stored totals so they're forced to be recalculated
37+
*
38+
* @param ResolverInterface $subject
39+
* @param Field $field
40+
* @param ContextInterface $context
41+
* @param ResolveInfo $info
42+
* @param array|null $value
43+
* @param array|null $args
44+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
45+
*/
46+
public function beforeResolve(
47+
ResolverInterface $subject,
48+
Field $field,
49+
$context,
50+
ResolveInfo $info,
51+
array $value = null,
52+
array $args = null
53+
) {
54+
if ($info->isTopResolver()) {
55+
$this->totalsCollector->clearTotals();
56+
}
57+
}
58+
}

app/code/Magento/QuoteGraphQl/etc/graphql/di.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,12 @@
2323
<type name="Magento\Quote\Model\Quote\Config">
2424
<plugin name="append_requested_graphql_attributes" type="Magento\QuoteGraphQl\Plugin\ProductAttributesExtender"/>
2525
</type>
26+
<type name="Magento\Framework\GraphQl\Query\ResolverInterface">
27+
<plugin name="reset-totals" type="Magento\QuoteGraphQl\Plugin\ResetStoredTotalsBeforeTopResolver" sortOrder="1"/>
28+
</type>
29+
<type name="Magento\QuoteGraphQl\Model\Cart\TotalsCollector">
30+
<arguments>
31+
<argument name="quoteTotalsCollector" xsi:type="object">Magento\Quote\Model\Quote\TotalsCollector\Proxy</argument>
32+
</arguments>
33+
</type>
2634
</config>

dev/tests/integration/testsuite/Magento/GraphQl/GraphQlIntrospectionTest.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Magento\Framework\GraphQl\Schema\Type\InputObjectType;
1111
use Magento\Framework\GraphQl\Schema\Type\ObjectType;
12+
use Magento\Framework\GraphQl\Type\TypeManagement;
1213
use Magento\Framework\ObjectManagerInterface;
1314

1415
class GraphQlIntrospectionTest extends \PHPUnit\Framework\TestCase
@@ -27,6 +28,8 @@ protected function setUp(): void
2728

2829
public function testIntrospectionQuery()
2930
{
31+
$typeManagement = new TypeManagement();
32+
$typeManagement->overrideStandardGraphQLTypes();
3033
$emptySchema = $this->schemaFactory->create(
3134
[
3235
'query' => new ObjectType(
@@ -272,10 +275,10 @@ public function testIntrospectsIncludeTheDeprecatedParameter()
272275
description
273276
isDeprecated
274277
deprecationReason
275-
278+
276279
}
277280
}
278-
}
281+
}
279282
280283
QUERY;
281284
$response = \GraphQL\GraphQL::executeQuery($testSchema, $request);

lib/internal/Magento/Framework/GraphQl/Schema/Type/ResolveInfo.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,13 @@
1212
*/
1313
class ResolveInfo extends \GraphQL\Type\Definition\ResolveInfo
1414
{
15-
15+
/**
16+
* Check if this is the top-level resolver for given operation
17+
*
18+
* @return bool
19+
*/
20+
public function isTopResolver(): bool
21+
{
22+
return in_array($this->parentType->name, ['Query', 'Mutation']);
23+
}
1624
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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\Framework\GraphQl\Type;
9+
10+
use GraphQL\GraphQL;
11+
use GraphQL\Type\Definition\Type as GraphQLType;
12+
use Magento\Framework\GraphQl\Type\Definition\FloatType;
13+
use Magento\Framework\GraphQl\Type\Definition\IntType;
14+
use Magento\Framework\GraphQl\Type\Definition\StringType;
15+
16+
/**
17+
* Class containing shared methods for GraphQL type management
18+
*/
19+
class TypeManagement
20+
{
21+
/**
22+
* Replace the standard type definitions with ones that know how to cast input values
23+
*/
24+
public function overrideStandardGraphQLTypes(): void
25+
{
26+
$standardTypes = GraphQLType::getStandardTypes();
27+
$overrideTypes = [];
28+
if (!($standardTypes[GraphQLType::INT] instanceof IntType)) {
29+
$overrideTypes[GraphQLType::INT] = new IntType($standardTypes[GraphQLType::INT]->config);
30+
}
31+
if (!($standardTypes[GraphQLType::FLOAT] instanceof FloatType)) {
32+
$overrideTypes[GraphQLType::FLOAT] = new FloatType($standardTypes[GraphQLType::FLOAT]->config);
33+
}
34+
if (!($standardTypes[GraphQLType::STRING] instanceof StringType)) {
35+
$overrideTypes[GraphQLType::STRING] = new StringType($standardTypes[GraphQLType::STRING]->config);
36+
}
37+
if ($overrideTypes) {
38+
GraphQL::overrideStandardTypes($overrideTypes);
39+
}
40+
}
41+
}

lib/internal/Magento/Framework/GraphQlSchemaStitching/GraphQlReader.php

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@
77

88
namespace Magento\Framework\GraphQlSchemaStitching;
99

10-
use GraphQL\GraphQL;
1110
use GraphQL\Type\Definition\ScalarType;
12-
use GraphQL\Type\Definition\Type as GraphQLType;
1311
use GraphQL\Utils\BuildSchema;
1412
use Magento\Framework\Component\ComponentRegistrar;
1513
use Magento\Framework\Config\FileResolverInterface;
1614
use Magento\Framework\Config\ReaderInterface;
17-
use Magento\Framework\GraphQl\Type\Definition\FloatType;
18-
use Magento\Framework\GraphQl\Type\Definition\IntType;
19-
use Magento\Framework\GraphQl\Type\Definition\StringType;
15+
use Magento\Framework\GraphQl\Type\TypeManagement;
2016
use Magento\Framework\GraphQlSchemaStitching\GraphQlReader\TypeMetaReaderInterface as TypeReaderComposite;
2117
use Magento\Framework\GraphQlSchemaStitching\GraphQlReader\Reader\InterfaceType;
2218

@@ -57,11 +53,6 @@ class GraphQlReader implements ReaderInterface
5753
*/
5854
private static $componentRegistrar;
5955

60-
/**
61-
* @var boolean
62-
*/
63-
private static $typesOverridden = false;
64-
6556
/**
6657
* @param FileResolverInterface $fileResolver
6758
* @param TypeReaderComposite $typeReader
@@ -78,7 +69,8 @@ public function __construct(
7869
$this->typeReader = $typeReader;
7970
$this->defaultScope = $defaultScope;
8071
$this->fileName = $fileName;
81-
$this->overrideStandardGraphQLTypes();
72+
$typeManagement = new TypeManagement();
73+
$typeManagement->overrideStandardGraphQLTypes();
8274
}
8375

8476
/**
@@ -352,22 +344,4 @@ private function addModuleNameToTypes(array $source, string $filePath): array
352344

353345
return $source;
354346
}
355-
356-
/**
357-
* Replace the standard type definitions with ones that know how to cast input values
358-
*/
359-
private function overrideStandardGraphQLTypes(): void
360-
{
361-
if (!self::$typesOverridden) {
362-
$standardTypes = GraphQLType::getStandardTypes();
363-
364-
GraphQL::overrideStandardTypes([
365-
GraphQLType::INT => new IntType($standardTypes[GraphQLType::INT]->config),
366-
GraphQLType::FLOAT => new FloatType($standardTypes[GraphQLType::FLOAT]->config),
367-
GraphQLType::STRING => new StringType($standardTypes[GraphQLType::STRING]->config)
368-
]);
369-
370-
self::$typesOverridden = true;
371-
}
372-
}
373347
}

0 commit comments

Comments
 (0)