Skip to content

Commit 6057eb8

Browse files
authored
Merge pull request #7817 from magento-arcticfoxes/B2B-2404
B2B-2404: Optimize Product Permissions in GraphQL resolver
2 parents b025795 + 671cf02 commit 6057eb8

File tree

17 files changed

+180
-30
lines changed

17 files changed

+180
-30
lines changed

app/code/Magento/BundleGraphQl/Model/Resolver/Options/Label.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Magento\Framework\GraphQl\Query\ResolverInterface;
1616

1717
/**
18-
* Class Label
18+
* Bundle product option label resolver
1919
*/
2020
class Label implements ResolverInterface
2121
{
@@ -56,8 +56,8 @@ public function resolve(
5656
$this->product->addProductSku($value['sku']);
5757
$this->product->addEavAttributes(['name']);
5858

59-
$result = function () use ($value) {
60-
$productData = $this->product->getProductBySku($value['sku']);
59+
$result = function () use ($value, $context) {
60+
$productData = $this->product->getProductBySku($value['sku'], $context);
6161
/** @var \Magento\Catalog\Model\Product $productModel */
6262
$productModel = isset($productData['model']) ? $productData['model'] : null;
6363
return $productModel ? $productModel->getName() : null;

app/code/Magento/BundleGraphQl/Model/Resolver/PriceRange.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function resolve(
7373
array $args = null
7474
) {
7575
$this->productDataProvider->addProductSku($value['sku']);
76-
$productData = $this->productDataProvider->getProductBySku($value['sku']);
76+
$productData = $this->productDataProvider->getProductBySku($value['sku'], $context);
7777
$value['model'] = $productData['model'];
7878

7979
return $this->priceRangeDataProvider->prepare($context, $info, $value);

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,22 @@
114114
</argument>
115115
</arguments>
116116
</type>
117+
<type name="Magento\BundleGraphQl\Model\Resolver\Options\Label">
118+
<arguments>
119+
<argument name="product" xsi:type="object">Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct</argument>
120+
</arguments>
121+
</type>
122+
<type name="Magento\BundleGraphQl\Model\Resolver\PriceRange">
123+
<arguments>
124+
<argument name="productDataProvider" xsi:type="object">Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct</argument>
125+
</arguments>
126+
</type>
127+
<virtualType name="Magento\BundleGraphQl\Model\Resolver\Options\Product"
128+
type="Magento\CatalogGraphQl\Model\Resolver\Product">
129+
<arguments>
130+
<argument name="productDataProvider" xsi:type="object">
131+
Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct
132+
</argument>
133+
</arguments>
134+
</virtualType>
117135
</config>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ type BundleItemOption @doc(description: "Defines the characteristics that compri
6969
price: Float @doc(description: "The price of the selected option.")
7070
price_type: PriceTypeEnum @doc(description: "One of FIXED, PERCENT, or DYNAMIC.")
7171
can_change_quantity: Boolean @doc(description: "Indicates whether the customer can change the number of items for this option.")
72-
product: ProductInterface @doc(description: "Contains details about this product option.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product")
72+
product: ProductInterface @doc(description: "Contains details about this product option.") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Options\\Product")
7373
uid: ID! @doc(description: "The unique ID for a `BundleItemOption` object.") @resolver(class: "Magento\\BundleGraphQl\\Model\\Resolver\\Options\\BundleItemOptionUid")
7474
}
7575

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\Catalog\Model\ResourceModel\Product;
9+
10+
/**
11+
* Factory class for child product collection
12+
*/
13+
class ChildCollectionFactory extends CollectionFactory
14+
{
15+
/**
16+
* Create class instance with specified parameters
17+
*
18+
* @param array $data
19+
* @return \Magento\Catalog\Model\ResourceModel\Product\Collection
20+
*/
21+
public function create(array $data = [])
22+
{
23+
$collection = parent::create($data);
24+
$collection->setFlag('product_children', true);
25+
return $collection;
26+
}
27+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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\Catalog\Model\ResourceModel\Product;
9+
10+
/**
11+
* Factory class for @see \Magento\Catalog\Model\ResourceModel\Product\Collection
12+
*/
13+
class CollectionFactory
14+
{
15+
/**
16+
* Object Manager instance
17+
*
18+
* @var \Magento\Framework\ObjectManagerInterface
19+
*/
20+
private $objectManager = null;
21+
22+
/**
23+
* Instance name to create
24+
*
25+
* @var string
26+
*/
27+
private $instanceName = null;
28+
29+
/**
30+
* Factory constructor
31+
*
32+
* @param \Magento\Framework\ObjectManagerInterface $objectManager
33+
* @param string $instanceName
34+
*/
35+
public function __construct(
36+
\Magento\Framework\ObjectManagerInterface $objectManager,
37+
$instanceName = Collection::class
38+
) {
39+
$this->objectManager = $objectManager;
40+
$this->instanceName = $instanceName;
41+
}
42+
43+
/**
44+
* Create class instance with specified parameters
45+
*
46+
* @param array $data
47+
* @return \Magento\Catalog\Model\ResourceModel\Product\Collection
48+
*/
49+
public function create(array $data = [])
50+
{
51+
return $this->objectManager->create($this->instanceName, $data);
52+
}
53+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
6363
$fields = $this->productFieldsSelector->getProductFieldsFromInfo($info);
6464
$this->productDataProvider->addEavAttributes($fields);
6565

66-
$result = function () use ($value) {
67-
$data = $value['product'] ?? $this->productDataProvider->getProductBySku($value['sku']);
66+
$result = function () use ($value, $context) {
67+
$data = $value['product'] ?? $this->productDataProvider->getProductBySku($value['sku'], $context);
6868
if (empty($data)) {
6969
return null;
7070
}

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Deferred/Product.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,12 @@ public function addEavAttributes(array $attributeCodes) : void
103103
* Get product from result set.
104104
*
105105
* @param string $sku
106+
* @param null|ContextInterface $context
106107
* @return array
107108
*/
108-
public function getProductBySku(string $sku) : array
109+
public function getProductBySku(string $sku, ContextInterface $context = null) : array
109110
{
110-
$products = $this->fetch();
111+
$products = $this->fetch($context);
111112

112113
if (!isset($products[$sku])) {
113114
return [];
@@ -119,9 +120,10 @@ public function getProductBySku(string $sku) : array
119120
/**
120121
* Fetch product data and return in array format. Keys for products will be their skus.
121122
*
123+
* @param null|ContextInterface $context
122124
* @return array
123125
*/
124-
private function fetch() : array
126+
private function fetch(ContextInterface $context = null) : array
125127
{
126128
if (empty($this->productSkus) || !empty($this->productList)) {
127129
return $this->productList;
@@ -132,7 +134,8 @@ private function fetch() : array
132134
$this->searchCriteriaBuilder->create(),
133135
$this->attributeCodes,
134136
false,
135-
false
137+
true,
138+
$context
136139
);
137140

138141
/** @var \Magento\Catalog\Model\Product $product */

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/Product/CollectionProcessor/VisibilityStatusProcessor.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public function process(
3737
): Collection {
3838
$collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner');
3939
$collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner');
40+
if ($context) {
41+
$store = $context->getExtensionAttributes()->getStore();
42+
if ($store) {
43+
$websiteId = $store->getWebsiteId();
44+
$collection->addWebsiteFilter([$websiteId]);
45+
}
46+
}
4047

4148
return $collection;
4249
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,20 @@
191191
<type name="Magento\Catalog\Api\ProductRepositoryInterface">
192192
<plugin name="availableProductsFilter" type="Magento\CatalogGraphQl\Plugin\AvailableProductsFilter" />
193193
</type>
194+
<virtualType name="Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ChildProduct"
195+
type="Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Product">
196+
<arguments>
197+
<argument name="collectionFactory" xsi:type="object">
198+
Magento\Catalog\Model\ResourceModel\Product\ChildCollectionFactory
199+
</argument>
200+
</arguments>
201+
</virtualType>
202+
<virtualType name="Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct"
203+
type="Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\Product">
204+
<arguments>
205+
<argument name="productDataProvider" xsi:type="object">
206+
Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ChildProduct
207+
</argument>
208+
</arguments>
209+
</virtualType>
194210
</config>

app/code/Magento/ConfigurableProductGraphQl/Model/Variant/Collection.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ private function fetch(ContextInterface $context) : array
153153
$childCollection = $this->childCollectionFactory->create();
154154
$childCollection->setProductFilter($product);
155155
$childCollection->addWebsiteFilter($context->getExtensionAttributes()->getStore()->getWebsiteId());
156+
$childCollection->setFlag('product_children', true);
156157
$this->collectionProcessor->process(
157158
$childCollection,
158159
$this->searchCriteriaBuilder->create(),

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,12 @@
8585
<type name="Magento\Quote\Model\Quote">
8686
<plugin name="update_customized_options" type="Magento\ConfigurableProductGraphQl\Plugin\Quote\UpdateCustomizedOptions"/>
8787
</type>
88+
<virtualType name="Magento\ConfigurableProductGraphQl\Model\Resolver\Variant\Product"
89+
type="Magento\CatalogGraphQl\Model\Resolver\Product">
90+
<arguments>
91+
<argument name="productDataProvider" xsi:type="object">
92+
Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct
93+
</argument>
94+
</arguments>
95+
</virtualType>
8896
</config>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type ConfigurableProduct implements ProductInterface, RoutableInterface, Physica
1212

1313
type ConfigurableVariant @doc(description: "Contains all the simple product variants of a configurable product.") {
1414
attributes: [ConfigurableAttributeOption] @resolver(class: "Magento\\ConfigurableProductGraphQl\\Model\\Resolver\\Variant\\Attributes") @doc(description: "An array of configurable attribute options.")
15-
product: SimpleProduct @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product") @doc(description: "An array of linked simple products.")
15+
product: SimpleProduct @resolver(class: "Magento\\ConfigurableProductGraphQl\\Model\\Resolver\\Variant\\Product") @doc(description: "An array of linked simple products.")
1616
}
1717

1818
type ConfigurableAttributeOption @doc(description: "Contains details about a configurable product attribute option.") {

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,17 @@
5353
</argument>
5454
</arguments>
5555
</type>
56+
<type name="Magento\GroupedProductGraphQl\Model\Resolver\GroupedItems">
57+
<arguments>
58+
<argument name="productResolver" xsi:type="object">Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct</argument>
59+
</arguments>
60+
</type>
61+
<virtualType name="Magento\GroupedProductGraphQl\Model\Resolver\GroupedItem\Product"
62+
type="Magento\CatalogGraphQl\Model\Resolver\Product">
63+
<arguments>
64+
<argument name="productDataProvider" xsi:type="object">
65+
Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\ChildProduct
66+
</argument>
67+
</arguments>
68+
</virtualType>
5669
</config>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type GroupedProduct implements ProductInterface, RoutableInterface, PhysicalProd
88
type GroupedProductItem @doc(description: "Contains information about an individual grouped product item."){
99
qty: Float @doc(description: "The quantity of this grouped product item.")
1010
position: Int @doc(description: "The relative position of this item compared to the other group items.")
11-
product: ProductInterface @doc(description: "Details about this product option.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product")
11+
product: ProductInterface @doc(description: "Details about this product option.") @resolver(class: "Magento\\GroupedProductGraphQl\\Model\\Resolver\\GroupedItem\\Product")
1212
}
1313

1414
type GroupedProductWishlistItem implements WishlistItemInterface @doc(description: "A grouped product wish list item.") {

dev/tests/api-functional/testsuite/Magento/GraphQl/Bundle/BundleProductViewTest.php

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public function testBundleProductWithNotVisibleChildren()
212212
}
213213
$this->assertBundleBaseFields($bundleProduct, $response['products']['items'][0]);
214214

215-
$this->assertBundleProductOptions($bundleProduct, $response['products']['items'][0]);
215+
$this->assertBundleProductOptions($bundleProduct, $response['products']['items'][0], false);
216216
$this->assertNotEmpty(
217217
$response['products']['items'][0]['items'],
218218
"Precondition failed: 'items' must not be empty"
@@ -242,8 +242,9 @@ private function assertBundleBaseFields($product, $actualResponse)
242242
/**
243243
* @param ProductInterface $product
244244
* @param array $actualResponse
245+
* @param bool $isChildVisible
245246
*/
246-
private function assertBundleProductOptions($product, $actualResponse)
247+
private function assertBundleProductOptions($product, $actualResponse, $isChildVisible = true)
247248
{
248249
$this->assertNotEmpty(
249250
$actualResponse['items'],
@@ -279,19 +280,26 @@ private function assertBundleProductOptions($product, $actualResponse)
279280
'position' => $bundleProductLink->getPosition(),
280281
'is_default' => (bool)$bundleProductLink->getIsDefault(),
281282
'price_type' => self::KEY_PRICE_TYPE_FIXED,
282-
'can_change_quantity' => $bundleProductLink->getCanChangeQuantity(),
283-
'label' => $childProduct->getName()
283+
'can_change_quantity' => $bundleProductLink->getCanChangeQuantity()
284284
]
285285
);
286-
$this->assertResponseFields(
287-
$actualResponse['items'][0]['options'][0]['product'],
288-
[
289-
'id' => $childProduct->getId(),
290-
'name' => $childProduct->getName(),
291-
'type_id' => $childProduct->getTypeId(),
292-
'sku' => $bundleProductLink->getSku()
293-
]
286+
$this->assertEquals(
287+
$isChildVisible ? $childProduct->getName() : null,
288+
$actualResponse['items'][0]['options'][0]['label']
294289
);
290+
if ($isChildVisible) {
291+
$this->assertResponseFields(
292+
$actualResponse['items'][0]['options'][0]['product'],
293+
[
294+
'id' => $childProduct->getId(),
295+
'name' => $childProduct->getName(),
296+
'type_id' => $childProduct->getTypeId(),
297+
'sku' => $childProduct->getSku()
298+
]
299+
);
300+
} else {
301+
$this->assertNull($actualResponse['items'][0]['options'][0]['product']);
302+
}
295303
}
296304

297305
/**

dev/tests/api-functional/testsuite/Magento/GraphQl/PageCache/VarnishTest.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?php
2-
/*
2+
/**
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
@@ -15,10 +15,6 @@
1515
*/
1616
class VarnishTest extends GraphQlAbstract
1717
{
18-
protected function setUp(): void
19-
{
20-
$this->markTestSkipped("Tests are skipped until vcl files are merged into mainline");
21-
}
2218
/**
2319
* Test that we obtain cache MISS/HIT when expected for a guest.
2420
*

0 commit comments

Comments
 (0)