Skip to content

Commit 59b2921

Browse files
Merge pull request #8677 from magento-lynx/storefront-extra-graphql-delivery
[LYNX] Storefront extra graphql delivery
2 parents 57cbaad + edcee33 commit 59b2921

File tree

14 files changed

+264
-47
lines changed

14 files changed

+264
-47
lines changed

app/code/Magento/CustomerGraphQl/Model/Customer/GetAttributesForm.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,6 @@ public function execute(string $formCode): ?array
4242
{
4343
$attributes = [];
4444
foreach ($this->entity->getAttributes($formCode) as $attribute) {
45-
// region_id and country_id returns large datasets that is also not related between each other and
46-
// not filterable. DirectoryGraphQl contains queries that allow to retrieve this information in a
47-
// meaningful way
48-
if ($attribute->getAttributeCode() === 'region_id' || $attribute->getAttributeCode() === 'country_id') {
49-
continue;
50-
}
5145
$attributes[] = ['entity_type' => $this->type, 'attribute_code' => $attribute->getAttributeCode()];
5246
}
5347
return $attributes;

app/code/Magento/EavGraphQl/Model/Output/GetAttributeData.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<?php
2-
32
/**
43
* Copyright © Magento, Inc. All rights reserved.
54
* See COPYING.txt for license details.
65
*/
7-
86
declare(strict_types=1);
97

108
namespace Magento\EavGraphQl\Model\Output;
@@ -24,12 +22,19 @@ class GetAttributeData implements GetAttributeDataInterface
2422
*/
2523
private EnumLookup $enumLookup;
2624

25+
/**
26+
* @var array
27+
*/
28+
private array $skipOptionsForAttributeCodes;
29+
2730
/**
2831
* @param EnumLookup $enumLookup
32+
* @param array $skipOptionsForAttributeCodes
2933
*/
30-
public function __construct(EnumLookup $enumLookup)
34+
public function __construct(EnumLookup $enumLookup, array $skipOptionsForAttributeCodes = [])
3135
{
3236
$this->enumLookup = $enumLookup;
37+
$this->skipOptionsForAttributeCodes = $skipOptionsForAttributeCodes;
3338
}
3439

3540
/**
@@ -91,7 +96,7 @@ private function getFrontendInput(AttributeInterface $attribute): string
9196
*/
9297
private function getOptions(AttributeInterface $attribute): array
9398
{
94-
if (!$attribute->getOptions()) {
99+
if (!$attribute->getOptions() || $this->skipOptions($attribute)) {
95100
return [];
96101
}
97102
return array_filter(
@@ -133,4 +138,18 @@ private function isDefault(mixed $value, mixed $defaultValue): bool
133138

134139
return in_array($value, explode(',', $defaultValue));
135140
}
141+
142+
/**
143+
* Skip attributes options for region_id and country_id
144+
*
145+
* Attributes region_id and country_id returns large datasets that is also not related between each other and
146+
* not filterable. DirectoryGraphQl contains queries that allow to retrieve this information in a meaningful way
147+
*
148+
* @param AttributeInterface $attribute
149+
* @return bool
150+
*/
151+
private function skipOptions(AttributeInterface $attribute): bool
152+
{
153+
return in_array($attribute->getAttributeCode(), $this->skipOptionsForAttributeCodes);
154+
}
136155
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,12 @@
99
<type name="Magento\Eav\Model\Entity\Attribute">
1010
<plugin name="entityAttributeChangePlugin" type="Magento\EavGraphQl\Plugin\Eav\AttributePlugin" />
1111
</type>
12+
<type name="Magento\EavGraphQl\Model\Output\GetAttributeData">
13+
<arguments>
14+
<argument name="skipOptionsForAttributeCodes" xsi:type="array">
15+
<item name="region_id" xsi:type="string">region_id</item>
16+
<item name="country_id" xsi:type="string">country_id</item>
17+
</argument>
18+
</arguments>
19+
</type>
1220
</config>

app/code/Magento/EavGraphQl/etc/schema.graphqls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type Query {
1111
customAttributeMetadataV2(attributes: [AttributeInput!]): AttributesMetadataOutput! @resolver(class: "Magento\\EavGraphQl\\Model\\Resolver\\AttributesMetadata") @doc(description: "Retrieve EAV attributes metadata.") @cache(cacheIdentity: "Magento\\EavGraphQl\\Model\\Resolver\\Cache\\CustomAttributeMetadataV2Identity")
1212
attributesForm(formCode: String! @doc(description: "Form code.")): AttributesFormOutput!
1313
@resolver(class: "Magento\\EavGraphQl\\Model\\Resolver\\AttributesForm")
14-
@doc(description: "Retrieve EAV attributes associated to a frontend form. For region_id and country_id attributes information use DirectoryGraphQl module.")
14+
@doc(description: "Retrieve EAV attributes associated to a frontend form. Use countries query provided by DirectoryGraphQl module to retrieve region_id and country_id attribute options.")
1515
@cache(cacheIdentity: "Magento\\Eav\\Model\\Cache\\AttributesFormIdentity")
1616
attributesList(
1717
entityType: AttributeEntityTypeEnum! @doc(description: "Entity type.")

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,13 @@
6060
</argument>
6161
</arguments>
6262
</type>
63+
<type name="Magento\StoreGraphQl\Model\Resolver\Store\StoreConfigDataProvider">
64+
<arguments>
65+
<argument name="extendedConfigData" xsi:type="array">
66+
<item name="is_guest_checkout_enabled" xsi:type="string">checkout/options/guest_checkout</item>
67+
<item name="is_one_page_checkout_enabled" xsi:type="string">checkout/options/onepage_checkout_enabled</item>
68+
<item name="max_items_in_order_summary" xsi:type="string">checkout/options/max_items_display_count</item>
69+
</argument>
70+
</arguments>
71+
</type>
6372
</config>

app/code/Magento/QuoteGraphQl/etc/schema.graphqls

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,8 @@ enum CartUserInputErrorType {
442442
UNDEFINED
443443
}
444444

445+
type StoreConfig {
446+
is_guest_checkout_enabled: Boolean @doc(description: "Extended Config Data - checkout/options/guest_checkout")
447+
is_one_page_checkout_enabled: Boolean @doc(description: "Extended Config Data - checkout/options/onepage_checkout_enabled")
448+
max_items_in_order_summary: Int @doc(description: "Extended Config Data - checkout/options/max_items_display_count")
449+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
<arguments>
2828
<argument name="extendedConfigData" xsi:type="array">
2929
<item name="use_store_in_url" xsi:type="string">web/url/use_store</item>
30+
<item name="default_country" xsi:type="string">general/country/default</item>
31+
<item name="countries_with_required_region" xsi:type="string">general/region/state_required</item>
32+
<item name="display_state_if_optional" xsi:type="string">general/region/display_all</item>
33+
<item name="optional_zip_countries" xsi:type="string">general/country/optional_zip_countries</item>
3034
</argument>
3135
</arguments>
3236
</type>

app/code/Magento/StoreGraphQl/etc/schema.graphqls

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@ type StoreConfig @doc(description: "Contains information about a store's configu
4343
secure_base_static_url : String @doc(description: "The secure fully-qualified URL that specifies the location of static view files.")
4444
secure_base_media_url : String @doc(description: "The secure fully-qualified URL that specifies the location of media files.")
4545
use_store_in_url: Boolean @doc(description: "Indicates whether the store code should be used in the URL.")
46+
default_country: String @doc(description: "Extended Config Data - general/country/default")
47+
countries_with_required_region: String @doc(description: "Extended Config Data - general/region/state_required")
48+
optional_zip_countries: String @doc(description: "Extended Config Data - general/country/optional_zip_countries")
49+
display_state_if_optional: Boolean @doc(description: "Extended Config Data - general/region/display_all")
4650
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/************************************************************************
4+
*
5+
* Copyright 2023 Adobe
6+
* All Rights Reserved.
7+
*
8+
* NOTICE: All information contained herein is, and remains
9+
* the property of Adobe and its suppliers, if any. The intellectual
10+
* and technical concepts contained herein are proprietary to Adobe
11+
* and its suppliers and are protected by all applicable intellectual
12+
* property laws, including trade secret and copyright laws.
13+
* Dissemination of this information or reproduction of this material
14+
* is strictly forbidden unless prior written permission is obtained
15+
* from Adobe.
16+
* ************************************************************************
17+
*/
18+
-->
19+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
20+
<type name="Magento\StoreGraphQl\Model\Resolver\Store\StoreConfigDataProvider">
21+
<arguments>
22+
<argument name="extendedConfigData" xsi:type="array">
23+
<item name="shopping_cart_display_price" xsi:type="string">tax/cart_display/price</item>
24+
<item name="shopping_cart_display_shipping" xsi:type="string">tax/cart_display/shipping</item>
25+
<item name="shopping_cart_display_subtotal" xsi:type="string">tax/cart_display/subtotal</item>
26+
<item name="shopping_cart_display_grand_total" xsi:type="string">tax/cart_display/grandtotal</item>
27+
<item name="shopping_cart_display_full_summary" xsi:type="string">tax/cart_display/full_summary</item>
28+
<item name="shopping_cart_display_zero_tax" xsi:type="string">tax/cart_display/zero_tax</item>
29+
</argument>
30+
</arguments>
31+
</type>
32+
</config>

app/code/Magento/TaxGraphQl/etc/schema.graphqls

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,12 @@
44
enum PriceAdjustmentCodesEnum {
55
TAX @deprecated(reason: "`PriceAdjustmentCodesEnum` is deprecated. Tax is included or excluded in the price. Tax is not shown separately in Catalog.")
66
}
7+
8+
type StoreConfig {
9+
shopping_cart_display_price: Int @doc(description: "Extended Config Data - tax/cart_display/price")
10+
shopping_cart_display_shipping: Int @doc(description: "Extended Config Data - tax/cart_display/shipping")
11+
shopping_cart_display_subtotal: Int @doc(description: "Extended Config Data - tax/cart_display/subtotal")
12+
shopping_cart_display_grand_total: Boolean @doc(description: "Extended Config Data - tax/cart_display/grandtotal")
13+
shopping_cart_display_full_summary: Boolean @doc(description: "Extended Config Data - tax/cart_display/full_summary")
14+
shopping_cart_display_zero_tax: Boolean @doc(description: "Extended Config Data - tax/cart_display/zero_tax")
15+
}

dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/Attribute/AttributesFormTest.php

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,6 @@ class AttributesFormTest extends GraphQlAbstract
5959
'used_in_forms' => ['customer_address_edit']
6060
],
6161
'attribute_2'
62-
),
63-
DataFixture(
64-
CustomerAttribute::class,
65-
[
66-
'entity_type_id' => AddressMetadataInterface::ATTRIBUTE_SET_ID_ADDRESS,
67-
'used_in_forms' => ['customer_register_address']
68-
],
69-
'attribute_3'
7062
)
7163
]
7264
public function testAttributesForm(): void
@@ -75,22 +67,16 @@ public function testAttributesForm(): void
7567
$attribute1 = DataFixtureStorageManager::getStorage()->get('attribute_1');
7668
/** @var AttributeInterface $attribute2 */
7769
$attribute2 = DataFixtureStorageManager::getStorage()->get('attribute_2');
78-
/** @var AttributeInterface $attribute3 */
79-
$attribute3 = DataFixtureStorageManager::getStorage()->get('attribute_3');
80-
$attribute3->setIsVisible(false)->save();
8170

8271
$result = $this->graphQlQuery(sprintf(self::QUERY, 'customer_register_address'));
8372

84-
foreach ($result['attributesForm']['items'] as $item) {
85-
if (array_contains($item, $attribute1->getAttributeCode())) {
86-
return;
87-
}
88-
$this->assertNotContains($attribute2->getAttributeCode(), $item);
89-
$this->assertNotContains($attribute3->getAttributeCode(), $item);
90-
$this->assertNotContains('region_id', $item);
91-
$this->assertNotContains('country_id', $item);
92-
}
93-
$this->fail(sprintf("Attribute '%s' not found in query response", $attribute1->getAttributeCode()));
73+
$this->assertNotEmpty($result['attributesForm']['items']);
74+
$codes = $this->getAttributeCodes($result['attributesForm']['items']);
75+
76+
$this->assertContains($attribute1->getAttributeCode(), $codes);
77+
$this->assertContains('country_id', $codes);
78+
$this->assertContains('region_id', $codes);
79+
$this->assertNotContains($attribute2->getAttributeCode(), $codes);
9480
}
9581

9682
public function testAttributesFormAdminHtmlForm(): void
@@ -152,13 +138,10 @@ public function testAttributesFormScope(): void
152138

153139
$result = $this->graphQlQuery(sprintf(self::QUERY, 'customer_register_address'));
154140

155-
foreach ($result['attributesForm']['items'] as $item) {
156-
if (array_contains($item, $attribute1->getAttributeCode())) {
157-
$this->fail(
158-
sprintf("Attribute '%s' found in query response in global scope", $attribute1->getAttributeCode())
159-
);
160-
}
161-
}
141+
$this->assertNotEmpty($result['attributesForm']['items']);
142+
$codes = $this->getAttributeCodes($result['attributesForm']['items']);
143+
144+
$this->assertNotContains($attribute1->getAttributeCode(), $codes);
162145

163146
/** @var StoreInterface $store */
164147
$store = DataFixtureStorageManager::getStorage()->get('store2');
@@ -170,16 +153,31 @@ public function testAttributesFormScope(): void
170153
['Store' => $store->getCode()]
171154
);
172155

173-
foreach ($result['attributesForm']['items'] as $item) {
174-
if (array_contains($item, $attribute1->getAttributeCode())) {
175-
return;
176-
}
177-
}
178-
$this->fail(
156+
$this->assertNotEmpty($result['attributesForm']['items']);
157+
$codes = $this->getAttributeCodes($result['attributesForm']['items']);
158+
$this->assertContains(
159+
$attribute1->getAttributeCode(),
160+
$codes,
179161
sprintf(
180162
"Attribute '%s' not found in query response in website scope",
181163
$attribute1->getAttributeCode()
182164
)
183165
);
184166
}
167+
168+
/**
169+
* Retrieve an array of attribute codes based on an array of attributes data
170+
*
171+
* @param array $attributes
172+
* @return array
173+
*/
174+
private function getAttributeCodes(array $attributes): array
175+
{
176+
return array_map(
177+
function (array $attribute) {
178+
return $attribute['code'];
179+
},
180+
$attributes
181+
);
182+
}
185183
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\GraphQl\Quote;
9+
10+
use Magento\Checkout\Helper\Data;
11+
use Magento\Store\Model\ScopeInterface;
12+
use Magento\TestFramework\Fixture\Config as ConfigFixture;
13+
use Magento\TestFramework\TestCase\GraphQlAbstract;
14+
15+
/**
16+
* Test the GraphQL endpoint's StoreConfigs query
17+
*/
18+
class StoreConfigResolverTest extends GraphQlAbstract
19+
{
20+
private const MAX_ITEMS_TO_DISPLAY = 5;
21+
22+
#[
23+
ConfigFixture(Data::XML_PATH_GUEST_CHECKOUT, true, ScopeInterface::SCOPE_STORE, 'default'),
24+
ConfigFixture('checkout/options/onepage_checkout_enabled', true, ScopeInterface::SCOPE_STORE, 'default'),
25+
ConfigFixture('checkout/options/max_items_display_count', self::MAX_ITEMS_TO_DISPLAY)
26+
]
27+
public function testGetStoreConfig(): void
28+
{
29+
$query
30+
= <<<QUERY
31+
{
32+
storeConfig {
33+
is_guest_checkout_enabled,
34+
is_one_page_checkout_enabled,
35+
max_items_in_order_summary
36+
}
37+
}
38+
QUERY;
39+
$response = $this->graphQlQuery($query);
40+
$this->assertArrayHasKey('storeConfig', $response);
41+
$this->validateStoreConfig($response['storeConfig']);
42+
}
43+
44+
/**
45+
* Validate Store Config Data
46+
*
47+
* @param array $responseConfig
48+
*/
49+
private function validateStoreConfig(
50+
array $responseConfig,
51+
): void {
52+
$this->assertTrue($responseConfig['is_guest_checkout_enabled']);
53+
$this->assertTrue($responseConfig['is_one_page_checkout_enabled']);
54+
$this->assertEquals(self::MAX_ITEMS_TO_DISPLAY, $responseConfig['max_items_in_order_summary']);
55+
}
56+
}

dev/tests/api-functional/testsuite/Magento/GraphQl/Store/StoreConfigResolverTest.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77

88
namespace Magento\GraphQl\Store;
99

10+
use Magento\Directory\Helper\Data;
1011
use Magento\Framework\Exception\NoSuchEntityException;
1112
use Magento\Store\Api\Data\StoreConfigInterface;
1213
use Magento\Store\Api\StoreConfigManagerInterface;
1314
use Magento\Store\Api\StoreRepositoryInterface;
1415
use Magento\Store\Api\StoreResolverInterface;
16+
use Magento\Store\Model\ScopeInterface;
1517
use Magento\Store\Model\Store;
18+
use Magento\TestFramework\Fixture\Config;
1619
use Magento\TestFramework\Helper\Bootstrap;
1720
use Magento\TestFramework\ObjectManager;
1821
use Magento\TestFramework\TestCase\GraphQlAbstract;
@@ -39,6 +42,12 @@ protected function setUp(): void
3942
* @magentoApiDataFixture Magento/Store/_files/store.php
4043
* @throws NoSuchEntityException
4144
*/
45+
#[
46+
Config(Data::XML_PATH_DEFAULT_COUNTRY, 'es', ScopeInterface::SCOPE_STORE, 'default'),
47+
Config(Data::XML_PATH_STATES_REQUIRED, 'us', ScopeInterface::SCOPE_STORE, 'default'),
48+
Config(Data::OPTIONAL_ZIP_COUNTRIES_CONFIG_PATH, 'fr', ScopeInterface::SCOPE_STORE, 'default'),
49+
Config(Data::XML_PATH_DISPLAY_ALL_STATES, true, ScopeInterface::SCOPE_STORE, 'default'),
50+
]
4251
public function testGetStoreConfig(): void
4352
{
4453
/** @var StoreConfigManagerInterface $storeConfigManager */
@@ -80,7 +89,10 @@ public function testGetStoreConfig(): void
8089
secure_base_link_url,
8190
secure_base_static_url,
8291
secure_base_media_url,
83-
store_name
92+
default_country,
93+
countries_with_required_region,
94+
optional_zip_countries,
95+
display_state_if_optional
8496
}
8597
}
8698
QUERY;
@@ -136,6 +148,9 @@ private function validateStoreConfig(
136148
$this->assertEquals($storeConfig->getSecureBaseLinkUrl(), $responseConfig['secure_base_link_url']);
137149
$this->assertEquals($storeConfig->getSecureBaseStaticUrl(), $responseConfig['secure_base_static_url']);
138150
$this->assertEquals($storeConfig->getSecureBaseMediaUrl(), $responseConfig['secure_base_media_url']);
139-
$this->assertEquals($store->getName(), $responseConfig['store_name']);
151+
$this->assertEquals('es', $responseConfig['default_country']);
152+
$this->assertEquals('us', $responseConfig['countries_with_required_region']);
153+
$this->assertEquals('fr', $responseConfig['optional_zip_countries']);
154+
$this->assertEquals('true', $responseConfig['display_state_if_optional']);
140155
}
141156
}

0 commit comments

Comments
 (0)