Skip to content

Commit 0452331

Browse files
authored
Merge branch '2.4-develop' into fix-for-issue-37437
2 parents c4fe67c + 13e54e1 commit 0452331

File tree

462 files changed

+17099
-2502
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

462 files changed

+17099
-2502
lines changed

app/code/Magento/Backend/Model/Auth/Session.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ public function __construct(
114114
);
115115
}
116116

117+
/**
118+
* @inheritDoc
119+
*/
120+
public function _resetState(): void
121+
{
122+
parent::_resetState();
123+
$this->_isFirstAfterLogin = null;
124+
$this->acl = null;
125+
}
126+
117127
/**
118128
* Refresh ACL resources stored in session
119129
*

app/code/Magento/Backend/Model/Session/Quote.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ public function __construct(
139139
}
140140
}
141141

142+
/**
143+
* @inheritDoc
144+
*/
145+
public function _resetState(): void
146+
{
147+
parent::_resetState();
148+
$this->_quote = null;
149+
$this->_store = null;
150+
$this->_order = null;
151+
}
152+
142153
/**
143154
* Retrieve quote model object
144155
*
@@ -154,7 +165,7 @@ public function getQuote()
154165
$this->_quote->setCustomerGroupId($customerGroupId);
155166
$this->_quote->setIsActive(false);
156167
$this->_quote->setStoreId($this->getStoreId());
157-
168+
158169
$this->quoteRepository->save($this->_quote);
159170
$this->setQuoteId($this->_quote->getId());
160171
$this->_quote = $this->quoteRepository->get($this->getQuoteId(), [$this->getStoreId()]);

app/code/Magento/Backend/Test/Mftf/Section/LocaleOptionsSection.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@
1818
<element name="defaultLocale" type="checkbox" selector="#general_locale_code_inherit"/>
1919
<element name="checkIfTabExpand" type="button" selector="#general_locale-head:not(.open)"/>
2020
<element name="timeZoneDropdown" type="select" selector="//select[@id='general_locale_timezone']"/>
21+
<element name="changeStoreConfigButton" type="button" selector="//button[@id='store-change-button']"/>
22+
<element name="changeStoreConfigToSpecificWebsite" type="select" selector="//a[contains(text(),'{{var}}')]" parameterized="true"/>
23+
<element name="changeWebsiteConfirmButton" type="button" selector="//button[@class='action-primary action-accept']/span"/>
2124
</section>
2225
</sections>

app/code/Magento/Backup/Controller/Adminhtml/Index/Download.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
*/
77
namespace Magento\Backup\Controller\Adminhtml\Index;
88

9+
use Magento\Framework\App\Action\HttpGetActionInterface;
910
use Magento\Framework\App\Filesystem\DirectoryList;
1011

11-
class Download extends \Magento\Backup\Controller\Adminhtml\Index
12+
class Download extends \Magento\Backup\Controller\Adminhtml\Index implements HttpGetActionInterface
1213
{
1314
/**
1415
* @var \Magento\Framework\Controller\Result\RawFactory
@@ -66,17 +67,12 @@ public function execute()
6667

6768
$fileName = $this->_objectManager->get(\Magento\Backup\Helper\Data::class)->generateBackupDownloadName($backup);
6869

69-
$this->_fileFactory->create(
70+
return $this->_fileFactory->create(
7071
$fileName,
71-
null,
72+
['type' => 'filename', 'value' => $backup->getPath() . DIRECTORY_SEPARATOR . $backup->getFileName()],
7273
DirectoryList::VAR_DIR,
7374
'application/octet-stream',
7475
$backup->getSize()
7576
);
76-
77-
/** @var \Magento\Framework\Controller\Result\Raw $resultRaw */
78-
$resultRaw = $this->resultRawFactory->create();
79-
$resultRaw->setContents($backup->output());
80-
return $resultRaw;
8177
}
8278
}

app/code/Magento/Backup/Model/ResourceModel/Db.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ public function rollBackTransaction()
301301
*/
302302
public function runCommand($command)
303303
{
304-
$this->connection->query($command);
304+
$this->connection->multiQuery($command);
305305
return $this;
306306
}
307307
}

app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/DownloadTest.php

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ protected function setUp(): void
115115
->getMock();
116116
$this->backupModelMock = $this->getMockBuilder(Backup::class)
117117
->disableOriginalConstructor()
118-
->setMethods(['getTime', 'exists', 'getSize', 'output'])
118+
->setMethods(['getTime', 'exists', 'getSize', 'output', 'getPath', 'getFileName'])
119119
->getMock();
120120
$this->dataHelperMock = $this->getMockBuilder(Data::class)
121121
->disableOriginalConstructor()
@@ -169,8 +169,13 @@ public function testExecuteBackupFound()
169169
$type = 'db';
170170
$filename = 'filename';
171171
$size = 10;
172-
$output = 'test';
173-
172+
$path = 'testpath';
173+
$this->backupModelMock->expects($this->atLeastOnce())
174+
->method('getPath')
175+
->willReturn($path);
176+
$this->backupModelMock->expects($this->atLeastOnce())
177+
->method('getFileName')
178+
->willReturn($filename);
174179
$this->backupModelMock->expects($this->atLeastOnce())
175180
->method('getTime')
176181
->willReturn($time);
@@ -180,9 +185,6 @@ public function testExecuteBackupFound()
180185
$this->backupModelMock->expects($this->atLeastOnce())
181186
->method('getSize')
182187
->willReturn($size);
183-
$this->backupModelMock->expects($this->atLeastOnce())
184-
->method('output')
185-
->willReturn($output);
186188
$this->requestMock->expects($this->any())
187189
->method('getParam')
188190
->willReturnMap(
@@ -206,20 +208,14 @@ public function testExecuteBackupFound()
206208
$this->fileFactoryMock->expects($this->once())
207209
->method('create')->with(
208210
$filename,
209-
null,
211+
['type' => 'filename', 'value' => $path . '/' . $filename],
210212
DirectoryList::VAR_DIR,
211213
'application/octet-stream',
212214
$size
213215
)
214216
->willReturn($this->responseMock);
215-
$this->resultRawMock->expects($this->once())
216-
->method('setContents')
217-
->with($output);
218-
$this->resultRawFactoryMock->expects($this->once())
219-
->method('create')
220-
->willReturn($this->resultRawMock);
221217

222-
$this->assertSame($this->resultRawMock, $this->downloadController->execute());
218+
$this->assertSame($this->responseMock, $this->downloadController->execute());
223219
}
224220

225221
/**
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
/**
3+
*
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Magento\Bundle\Api;
10+
11+
/**
12+
* Interface for Bulk children addition
13+
*/
14+
interface ProductLinkManagementAddChildrenInterface
15+
{
16+
/**
17+
* Bulk add children operation
18+
*
19+
* @param \Magento\Catalog\Api\Data\ProductInterface $product
20+
* @param int $optionId
21+
* @param \Magento\Bundle\Api\Data\LinkInterface[] $linkedProducts
22+
* @throws \Magento\Framework\Exception\NoSuchEntityException
23+
* @throws \Magento\Framework\Exception\CouldNotSaveException
24+
* @throws \Magento\Framework\Exception\InputException
25+
* @return void
26+
*/
27+
public function addChildren(
28+
\Magento\Catalog\Api\Data\ProductInterface $product,
29+
int $optionId,
30+
array $linkedProducts
31+
);
32+
}

app/code/Magento/Bundle/Model/LinkManagement.php

Lines changed: 108 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Magento\Bundle\Api\Data\LinkInterface;
1111
use Magento\Bundle\Api\Data\LinkInterfaceFactory;
1212
use Magento\Bundle\Api\Data\OptionInterface;
13+
use Magento\Bundle\Api\ProductLinkManagementAddChildrenInterface;
1314
use Magento\Bundle\Api\ProductLinkManagementInterface;
1415
use Magento\Bundle\Model\Product\Type;
1516
use Magento\Bundle\Model\ResourceModel\Bundle;
@@ -30,7 +31,7 @@
3031
*
3132
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
3233
*/
33-
class LinkManagement implements ProductLinkManagementInterface
34+
class LinkManagement implements ProductLinkManagementInterface, ProductLinkManagementAddChildrenInterface
3435
{
3536
/**
3637
* @var ProductRepositoryInterface
@@ -189,19 +190,82 @@ public function saveChild(
189190
return true;
190191
}
191192

193+
/**
194+
* Linked product processing
195+
*
196+
* @param LinkInterface $linkedProduct
197+
* @param array $selections
198+
* @param int $optionId
199+
* @param ProductInterface $product
200+
* @param string $linkField
201+
* @param Bundle $resource
202+
* @return int
203+
* @throws CouldNotSaveException
204+
* @throws InputException
205+
* @throws NoSuchEntityException
206+
*/
207+
private function processLinkedProduct(
208+
LinkInterface $linkedProduct,
209+
array $selections,
210+
int $optionId,
211+
ProductInterface $product,
212+
string $linkField,
213+
Bundle $resource
214+
): int {
215+
$linkProductModel = $this->productRepository->get($linkedProduct->getSku());
216+
if ($linkProductModel->isComposite()) {
217+
throw new InputException(__('The bundle product can\'t contain another composite product.'));
218+
}
219+
220+
if ($selections) {
221+
foreach ($selections as $selection) {
222+
if ($selection['option_id'] == $optionId &&
223+
$selection['product_id'] == $linkProductModel->getEntityId() &&
224+
$selection['parent_product_id'] == $product->getData($linkField)) {
225+
if (!$product->getCopyFromView()) {
226+
throw new CouldNotSaveException(
227+
__(
228+
'Child with specified sku: "%1" already assigned to product: "%2"',
229+
[$linkedProduct->getSku(), $product->getSku()]
230+
)
231+
);
232+
}
233+
}
234+
}
235+
}
236+
237+
$selectionModel = $this->bundleSelection->create();
238+
$selectionModel = $this->mapProductLinkToBundleSelectionModel(
239+
$selectionModel,
240+
$linkedProduct,
241+
$product,
242+
(int)$linkProductModel->getEntityId()
243+
);
244+
245+
$selectionModel->setOptionId($optionId);
246+
247+
try {
248+
$selectionModel->save();
249+
$resource->addProductRelation($product->getData($linkField), $linkProductModel->getEntityId());
250+
} catch (\Exception $e) {
251+
throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
252+
}
253+
254+
return (int)$selectionModel->getId();
255+
}
256+
192257
/**
193258
* Fill selection model with product link data
194259
*
195260
* @param Selection $selectionModel
196261
* @param LinkInterface $productLink
197262
* @param string $linkedProductId
198263
* @param string $parentProductId
199-
*
200264
* @return Selection
201-
*
202265
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
203266
* @SuppressWarnings(PHPMD.NPathComplexity)
204-
* @deprecated use mapProductLinkToBundleSelectionModel
267+
* @deprecated
268+
* @see mapProductLinkToBundleSelectionModel
205269
*/
206270
protected function mapProductLinkToSelectionModel(
207271
Selection $selectionModel,
@@ -246,9 +310,9 @@ protected function mapProductLinkToSelectionModel(
246310
* @param LinkInterface $productLink
247311
* @param ProductInterface $parentProduct
248312
* @param int $linkedProductId
249-
* @param string $linkField
250313
* @return Selection
251314
* @throws NoSuchEntityException
315+
* @SuppressWarnings(PHPMD.NPathComplexity)
252316
*/
253317
private function mapProductLinkToBundleSelectionModel(
254318
Selection $selectionModel,
@@ -290,8 +354,6 @@ private function mapProductLinkToBundleSelectionModel(
290354

291355
/**
292356
* @inheritDoc
293-
*
294-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
295357
*/
296358
public function addChild(
297359
ProductInterface $product,
@@ -325,49 +387,52 @@ public function addChild(
325387
/* @var $resource Bundle */
326388
$resource = $this->bundleFactory->create();
327389
$selections = $resource->getSelectionsData($product->getData($linkField));
328-
/** @var Product $linkProductModel */
329-
$linkProductModel = $this->productRepository->get($linkedProduct->getSku());
330-
if ($linkProductModel->isComposite()) {
331-
throw new InputException(__('The bundle product can\'t contain another composite product.'));
332-
}
333-
334-
if ($selections) {
335-
foreach ($selections as $selection) {
336-
if ($selection['option_id'] == $optionId &&
337-
$selection['product_id'] == $linkProductModel->getEntityId() &&
338-
$selection['parent_product_id'] == $product->getData($linkField)) {
339-
if (!$product->getCopyFromView()) {
340-
throw new CouldNotSaveException(
341-
__(
342-
'Child with specified sku: "%1" already assigned to product: "%2"',
343-
[$linkedProduct->getSku(), $product->getSku()]
344-
)
345-
);
346-
}
347-
348-
return $this->bundleSelection->create()->load($linkProductModel->getEntityId());
349-
}
350-
}
351-
}
352-
353-
$selectionModel = $this->bundleSelection->create();
354-
$selectionModel = $this->mapProductLinkToBundleSelectionModel(
355-
$selectionModel,
390+
return $this->processLinkedProduct(
356391
$linkedProduct,
392+
$selections,
393+
(int)$optionId,
357394
$product,
358-
(int)$linkProductModel->getEntityId()
395+
$linkField,
396+
$resource
359397
);
398+
}
360399

361-
$selectionModel->setOptionId($optionId);
400+
/**
401+
* @inheritDoc
402+
*/
403+
public function addChildren(
404+
ProductInterface $product,
405+
int $optionId,
406+
array $linkedProducts
407+
) : void {
408+
if ($product->getTypeId() != Product\Type::TYPE_BUNDLE) {
409+
throw new InputException(
410+
__('The product with the "%1" SKU isn\'t a bundle product.', $product->getSku())
411+
);
412+
}
362413

363-
try {
364-
$selectionModel->save();
365-
$resource->addProductRelation($product->getData($linkField), $linkProductModel->getEntityId());
366-
} catch (\Exception $e) {
367-
throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
414+
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
415+
$options = $this->optionCollection->create();
416+
$options->setIdFilter($optionId);
417+
$options->setProductLinkFilter($product->getData($linkField));
418+
$existingOption = $options->getFirstItem();
419+
420+
if (!$existingOption->getId()) {
421+
throw new InputException(
422+
__(
423+
'Product with specified sku: "%1" does not contain option: "%2"',
424+
[$product->getSku(), $optionId]
425+
)
426+
);
368427
}
369428

370-
return (int)$selectionModel->getId();
429+
/* @var $resource Bundle */
430+
$resource = $this->bundleFactory->create();
431+
$selections = $resource->getSelectionsData($product->getData($linkField));
432+
433+
foreach ($linkedProducts as $linkedProduct) {
434+
$this->processLinkedProduct($linkedProduct, $selections, $optionId, $product, $linkField, $resource);
435+
}
371436
}
372437

373438
/**

0 commit comments

Comments
 (0)