Skip to content

Commit 8fa8b58

Browse files
authored
Merge branch '2.4-develop' into 2.4-develop-pr148
2 parents 5182a9b + 5dcb5a5 commit 8fa8b58

File tree

4 files changed

+208
-18
lines changed

4 files changed

+208
-18
lines changed

app/code/Magento/ConfigurableProductGraphQl/Model/Cart/BuyRequest/SuperAttributeDataProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public function execute(array $cartItemData): array
9393
throw new GraphQlNoSuchEntityException(__('Could not find specified product.'));
9494
}
9595

96-
$this->checkProductStock($sku, (float) $qty, (int) $cart->getStore()->getWebsite()->getId());
96+
$this->checkProductStock($sku, (float) $qty, (int) $cart->getStore()->getWebsiteId());
9797

9898
$configurableProductLinks = $parentProduct->getExtensionAttributes()->getConfigurableProductLinks();
9999
if (!in_array($product->getId(), $configurableProductLinks)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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\ConfigurableProductGraphQl\Test\Unit\Model\Cart\BuyRequest;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\CatalogInventory\Api\StockStateInterface;
13+
use Magento\ConfigurableProductGraphQl\Model\Cart\BuyRequest\SuperAttributeDataProvider;
14+
use Magento\ConfigurableProductGraphQl\Model\Options\Collection as OptionCollection;
15+
use Magento\Framework\EntityManager\MetadataPool;
16+
use Magento\Framework\Stdlib\ArrayManager;
17+
use Magento\Quote\Model\Quote;
18+
use Magento\Store\Api\Data\StoreInterface;
19+
use PHPUnit\Framework\MockObject\MockObject;
20+
use PHPUnit\Framework\TestCase;
21+
22+
/**
23+
* Test for SuperAttributeDataProvider
24+
*/
25+
class SuperAttributeDataProviderTest extends TestCase
26+
{
27+
/**
28+
* @var ArrayManager|MockObject
29+
*/
30+
private $arrayManager;
31+
32+
/**
33+
* @var ProductRepositoryInterface|MockObject
34+
*/
35+
private $productRepository;
36+
37+
/**
38+
* @var OptionCollection|MockObject
39+
*/
40+
private $optionCollection;
41+
42+
/**
43+
* @var MetadataPool|MockObject
44+
*/
45+
private $metadataPool;
46+
47+
/**
48+
* @var StockStateInterface|MockObject
49+
*/
50+
private $stockState;
51+
52+
/**
53+
* @var SuperAttributeDataProvider|MockObject
54+
*/
55+
private $superAttributeDataProvider;
56+
57+
/**
58+
* @inheritDoc
59+
*/
60+
protected function setUp(): void
61+
{
62+
$this->arrayManager = $this->getMockBuilder(ArrayManager::class)
63+
->disableOriginalConstructor()
64+
->getMock();
65+
$this->productRepository = $this->getMockBuilder(ProductRepositoryInterface::class)
66+
->disableOriginalConstructor()
67+
->getMockForAbstractClass();
68+
$this->optionCollection = $this->createMock(OptionCollection::class);
69+
$this->metadataPool = $this->getMockBuilder(MetadataPool::class)
70+
->disableOriginalConstructor()
71+
->onlyMethods(['getMetadata'])
72+
->addMethods(['getLinkField'])
73+
->getMock();
74+
$this->stockState = $this->getMockBuilder(StockStateInterface::class)
75+
->disableOriginalConstructor()
76+
->addMethods(['getHasError'])
77+
->getMockForAbstractClass();
78+
79+
$this->superAttributeDataProvider = new SuperAttributeDataProvider(
80+
$this->arrayManager,
81+
$this->productRepository,
82+
$this->optionCollection,
83+
$this->metadataPool,
84+
$this->stockState
85+
);
86+
}
87+
88+
/**
89+
* Check that website id is correctly retrieved
90+
*/
91+
public function testExecute(): void
92+
{
93+
$quoteMock = $this->getMockBuilder(Quote::class)
94+
->disableOriginalConstructor()
95+
->getMock();
96+
$cartItemData = [
97+
'data' => [
98+
'quantity' => 2.0,
99+
'sku' => 'simple1',
100+
],
101+
'parent_sku' => 'configurable',
102+
'model' => $quoteMock,
103+
];
104+
105+
$this->arrayManager->method('get')
106+
->withConsecutive(
107+
['parent_sku', $cartItemData],
108+
['data/sku', $cartItemData],
109+
['data/quantity', $cartItemData],
110+
['model', $cartItemData],
111+
)
112+
->willReturnOnConsecutiveCalls(
113+
'configurable',
114+
'simple1',
115+
2.0,
116+
$quoteMock,
117+
);
118+
119+
$storeMock = $this->getMockBuilder(StoreInterface::class)
120+
->disableOriginalConstructor()
121+
->addMethods(['getWebsite'])
122+
->getMockForAbstractClass();
123+
$storeMock->expects($this->once())->method('getWebsiteId')->willReturn(1);
124+
$storeMock->expects($this->never())->method('getWebsite');
125+
$quoteMock->expects($this->atLeastOnce())
126+
->method('getStore')
127+
->willReturn($storeMock);
128+
129+
$productMock = $this->getMockBuilder(Product::class)
130+
->disableOriginalConstructor()
131+
->onlyMethods(['getId', 'getExtensionAttributes', 'getData'])
132+
->addMethods(['getConfigurableProductLinks'])
133+
->getMock();
134+
$productMock->method('getId')
135+
->willReturn(1);
136+
$productMock->method('getExtensionAttributes')
137+
->willReturnSelf();
138+
$productMock->method('getConfigurableProductLinks')
139+
->willReturn([1]);
140+
$productMock->method('getData')
141+
->willReturn(1);
142+
$this->productRepository->method('get')
143+
->willReturn($productMock);
144+
$this->stockState->method('checkQuoteItemQty')
145+
->willReturnSelf();
146+
$this->stockState->method('getHasError')
147+
->willReturn(false);
148+
$this->metadataPool->method('getMetadata')
149+
->willReturnSelf();
150+
$this->metadataPool->method('getLinkField')
151+
->willReturnSelf();
152+
$this->optionCollection->method('getAttributesByProductId')
153+
->willReturn([
154+
[
155+
'attribute_code' => 'code',
156+
'attribute_id' => 1,
157+
'values' => [['value_index' => 1]],
158+
]
159+
]);
160+
161+
$this->assertEquals(['super_attribute' => [1 => 1]], $this->superAttributeDataProvider->execute($cartItemData));
162+
}
163+
}

app/code/Magento/Customer/Controller/Adminhtml/File/Customer/Upload.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use Magento\Framework\Exception\LocalizedException;
1515
use Psr\Log\LoggerInterface;
1616

17+
/**
18+
* Class for upload customer file attribute
19+
*/
1720
class Upload extends Action
1821
{
1922
/**
@@ -38,6 +41,11 @@ class Upload extends Action
3841
*/
3942
private $logger;
4043

44+
/**
45+
* @var string
46+
*/
47+
private $scope;
48+
4149
/**
4250
* @param Context $context
4351
* @param FileUploaderFactory $fileUploaderFactory
@@ -65,15 +73,15 @@ public function execute()
6573
if (empty($_FILES)) {
6674
throw new \Exception('$_FILES array is empty.');
6775
}
68-
69-
$attributeCode = key($_FILES['customer']['name']);
76+
$scope = array_key_first($_FILES);
77+
$attributeCode = key($_FILES[$scope]['name']);
7078
$attributeMetadata = $this->customerMetadataService->getAttributeMetadata($attributeCode);
7179

7280
/** @var FileUploader $fileUploader */
7381
$fileUploader = $this->fileUploaderFactory->create([
7482
'attributeMetadata' => $attributeMetadata,
7583
'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
76-
'scope' => 'customer',
84+
'scope' => $scope,
7785
]);
7886

7987
$errors = $fileUploader->validate();

lib/internal/Magento/Framework/Module/ModuleList/Loader.php

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ private function sortBySequence(array $origList): array
133133
{
134134
ksort($origList);
135135
$modules = $this->prearrangeModules($origList);
136-
136+
$sequenceCache = [];
137137
$expanded = [];
138138
foreach (array_keys($modules) as $moduleName) {
139-
$sequence = $this->expandSequence($origList, $moduleName);
139+
$sequence = $this->expandSequence($origList, $moduleName, $sequenceCache);
140140
asort($sequence);
141141

142142
$expanded[] = [
@@ -189,27 +189,46 @@ private function prearrangeModules(array $modules): array
189189
/**
190190
* Accumulate information about all transitive "sequence" references
191191
*
192+
* Added a sequence cache to avoid re-computing the sequences of dependencies over and over again.
193+
*
192194
* @param array $list
193195
* @param string $name
196+
* @param array $sequenceCache
194197
* @param array $accumulated
198+
* @param string $parentName
195199
* @return array
196200
* @throws \Exception
197201
*/
198-
private function expandSequence($list, $name, $accumulated = [])
199-
{
202+
private function expandSequence(
203+
array $list,
204+
string $name,
205+
array& $sequenceCache,
206+
array $accumulated = [],
207+
string $parentName = ''
208+
) {
209+
// Making sure we haven't already called the method for this module higher in the stack
210+
if (isset($accumulated[$name])) {
211+
throw new \LogicException("Circular sequence reference from '{$parentName}' to '{$name}'.");
212+
}
200213
$accumulated[$name] = true;
201-
$result = $list[$name]['sequence'];
202-
$allResults = [];
203-
foreach ($result as $relatedName) {
204-
if (isset($accumulated[$relatedName])) {
205-
throw new \LogicException("Circular sequence reference from '{$name}' to '{$relatedName}'.");
214+
215+
// Checking if we already computed the full sequence for this module
216+
if (!isset($sequenceCache[$name])) {
217+
$sequence = $list[$name]['sequence'] ?? [];
218+
$allSequences = [];
219+
// Going over all immediate dependencies to gather theirs recursively
220+
foreach ($sequence as $relatedName) {
221+
$relatedSequence = $this->expandSequence($list, $relatedName, $sequenceCache, $accumulated, $name);
222+
$allSequences[] = $relatedSequence;
206223
}
207-
if (!isset($list[$relatedName])) {
208-
continue;
224+
$allSequences[] = $sequence;
225+
226+
// Caching the full sequence list
227+
if (!empty($allSequences)) {
228+
$sequenceCache[$name] = array_unique(array_merge(...$allSequences));
209229
}
210-
$allResults[] = $this->expandSequence($list, $relatedName, $accumulated);
211230
}
212-
$allResults[] = $result;
213-
return array_unique(array_merge([], ...$allResults));
231+
232+
return $sequenceCache[$name] ?? [];
214233
}
215234
}

0 commit comments

Comments
 (0)