Skip to content

Commit e1d322f

Browse files
authored
Merge branch '2.4-develop' into 2.4-develop-sidecar-pr16
2 parents 4ea1aa9 + 9d39246 commit e1d322f

File tree

223 files changed

+4274
-1163
lines changed

Some content is hidden

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

223 files changed

+4274
-1163
lines changed

app/code/Magento/Backend/Test/Mftf/Test/AdminLoginAfterChangeCookieDomainTest.xml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,11 @@
2121
</annotations>
2222
<before>
2323
<magentoCLI command="config:set {{ChangedCookieDomainForMainWebsiteConfigData.path}} --scope={{ChangedCookieDomainForMainWebsiteConfigData.scope}} --scope-code={{ChangedCookieDomainForMainWebsiteConfigData.scope_code}} {{ChangedCookieDomainForMainWebsiteConfigData.value}}" stepKey="changeDomainForMainWebsiteBeforeTestRun"/>
24-
<actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCacheBeforeTestRun">
25-
<argument name="tags" value="config"/>
26-
</actionGroup>
24+
<comment userInput="Adding the comment to replace CliCacheFlushActionGroup action group ('cache:flush' command) for preserving Backward Compatibility" stepKey="flushCacheBeforeTestRun"/>
2725
</before>
2826
<after>
2927
<magentoCLI command="config:set {{EmptyCookieDomainForMainWebsiteConfigData.path}} --scope={{EmptyCookieDomainForMainWebsiteConfigData.scope}} --scope-code={{EmptyCookieDomainForMainWebsiteConfigData.scope_code}} {{EmptyCookieDomainForMainWebsiteConfigData.value}}" stepKey="changeDomainForMainWebsiteAfterTestComplete"/>
30-
<actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCacheAfterTestComplete">
31-
<argument name="tags" value="config"/>
32-
</actionGroup>
28+
<comment userInput="Adding the comment to replace CliCacheFlushActionGroup action group ('cache:flush' command) for preserving Backward Compatibility" stepKey="flushCacheAfterTestComplete"/>
3329
</after>
3430
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
3531
<actionGroup ref="AssertAdminDashboardPageIsVisibleActionGroup" stepKey="seeDashboardPage"/>

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

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
use Magento\Catalog\Api\ProductRepositoryInterface;
2020
use Magento\Catalog\Model\Product;
2121
use Magento\Framework\Api\DataObjectHelper;
22+
use Magento\Framework\EntityManager\MetadataPool;
2223
use Magento\Framework\Exception\CouldNotSaveException;
2324
use Magento\Framework\Exception\InputException;
24-
use Magento\Framework\EntityManager\MetadataPool;
2525
use Magento\Framework\Exception\NoSuchEntityException;
2626
use Magento\Store\Model\StoreManagerInterface;
2727

@@ -173,12 +173,11 @@ public function saveChild(
173173
)
174174
);
175175
}
176-
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
177-
$selectionModel = $this->mapProductLinkToSelectionModel(
176+
$selectionModel = $this->mapProductLinkToBundleSelectionModel(
178177
$selectionModel,
179178
$linkedProduct,
180-
$linkProductModel->getId(),
181-
$product->getData($linkField)
179+
$product,
180+
(int)$linkProductModel->getId()
182181
);
183182

184183
try {
@@ -202,6 +201,7 @@ public function saveChild(
202201
*
203202
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
204203
* @SuppressWarnings(PHPMD.NPathComplexity)
204+
* @deprecated use mapProductLinkToBundleSelectionModel
205205
*/
206206
protected function mapProductLinkToSelectionModel(
207207
Selection $selectionModel,
@@ -239,6 +239,55 @@ protected function mapProductLinkToSelectionModel(
239239
return $selectionModel;
240240
}
241241

242+
/**
243+
* Fill selection model with product link data.
244+
*
245+
* @param Selection $selectionModel
246+
* @param LinkInterface $productLink
247+
* @param ProductInterface $parentProduct
248+
* @param int $linkedProductId
249+
* @param string $linkField
250+
* @return Selection
251+
* @throws NoSuchEntityException
252+
*/
253+
private function mapProductLinkToBundleSelectionModel(
254+
Selection $selectionModel,
255+
LinkInterface $productLink,
256+
ProductInterface $parentProduct,
257+
int $linkedProductId
258+
): Selection {
259+
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
260+
$selectionModel->setProductId($linkedProductId);
261+
$selectionModel->setParentProductId($parentProduct->getData($linkField));
262+
if ($productLink->getSelectionId() !== null) {
263+
$selectionModel->setSelectionId($productLink->getSelectionId());
264+
}
265+
if ($productLink->getOptionId() !== null) {
266+
$selectionModel->setOptionId($productLink->getOptionId());
267+
}
268+
if ($productLink->getPosition() !== null) {
269+
$selectionModel->setPosition($productLink->getPosition());
270+
}
271+
if ($productLink->getQty() !== null) {
272+
$selectionModel->setSelectionQty($productLink->getQty());
273+
}
274+
if ($productLink->getPriceType() !== null) {
275+
$selectionModel->setSelectionPriceType($productLink->getPriceType());
276+
}
277+
if ($productLink->getPrice() !== null) {
278+
$selectionModel->setSelectionPriceValue($productLink->getPrice());
279+
}
280+
if ($productLink->getCanChangeQuantity() !== null) {
281+
$selectionModel->setSelectionCanChangeQty($productLink->getCanChangeQuantity());
282+
}
283+
if ($productLink->getIsDefault() !== null) {
284+
$selectionModel->setIsDefault($productLink->getIsDefault());
285+
}
286+
$selectionModel->setWebsiteId((int)$this->storeManager->getStore($parentProduct->getStoreId())->getWebsiteId());
287+
288+
return $selectionModel;
289+
}
290+
242291
/**
243292
* @inheritDoc
244293
*
@@ -302,12 +351,13 @@ public function addChild(
302351
}
303352

304353
$selectionModel = $this->bundleSelection->create();
305-
$selectionModel = $this->mapProductLinkToSelectionModel(
354+
$selectionModel = $this->mapProductLinkToBundleSelectionModel(
306355
$selectionModel,
307356
$linkedProduct,
308-
$linkProductModel->getEntityId(),
309-
$product->getData($linkField)
357+
$product,
358+
(int)$linkProductModel->getEntityId()
310359
);
360+
311361
$selectionModel->setOptionId($optionId);
312362

313363
try {

app/code/Magento/Bundle/Model/Option/SaveAction.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77

88
namespace Magento\Bundle\Model\Option;
99

10+
use Magento\Bundle\Api\Data\LinkInterface;
1011
use Magento\Bundle\Api\Data\OptionInterface;
1112
use Magento\Bundle\Model\ResourceModel\Option;
1213
use Magento\Catalog\Api\Data\ProductInterface;
14+
use Magento\Framework\App\ObjectManager;
1315
use Magento\Framework\EntityManager\MetadataPool;
1416
use Magento\Framework\Exception\CouldNotSaveException;
1517
use Magento\Bundle\Model\Product\Type;
1618
use Magento\Bundle\Api\ProductLinkManagementInterface;
19+
use Magento\Framework\Exception\NoSuchEntityException;
20+
use Magento\Store\Model\StoreManagerInterface;
1721

1822
/**
1923
* Encapsulates logic for saving a bundle option, including coalescing the parent product's data.
@@ -45,12 +49,14 @@ class SaveAction
4549
* @param MetadataPool $metadataPool
4650
* @param Type $type
4751
* @param ProductLinkManagementInterface $linkManagement
52+
* @param StoreManagerInterface|null $storeManager
4853
*/
4954
public function __construct(
5055
Option $optionResource,
5156
MetadataPool $metadataPool,
5257
Type $type,
53-
ProductLinkManagementInterface $linkManagement
58+
ProductLinkManagementInterface $linkManagement,
59+
?StoreManagerInterface $storeManager = null
5460
) {
5561
$this->optionResource = $optionResource;
5662
$this->metadataPool = $metadataPool;
@@ -69,7 +75,7 @@ public function __construct(
6975
*/
7076
public function save(ProductInterface $bundleProduct, OptionInterface $option)
7177
{
72-
$metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
78+
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
7379

7480
$option->setStoreId($bundleProduct->getStoreId());
7581
$parentId = $bundleProduct->getData($metadata->getLinkField());
@@ -108,7 +114,7 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option)
108114
throw new CouldNotSaveException(__("The option couldn't be saved."), $e);
109115
}
110116

111-
/** @var \Magento\Bundle\Api\Data\LinkInterface $linkedProduct */
117+
/** @var LinkInterface $linkedProduct */
112118
foreach ($linksToAdd as $linkedProduct) {
113119
$this->linkManagement->addChild($bundleProduct, $option->getOptionId(), $linkedProduct);
114120
}
@@ -121,8 +127,8 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option)
121127
/**
122128
* Update option selections
123129
*
124-
* @param \Magento\Catalog\Api\Data\ProductInterface $product
125-
* @param \Magento\Bundle\Api\Data\OptionInterface $option
130+
* @param ProductInterface $product
131+
* @param OptionInterface $option
126132
* @return void
127133
*/
128134
private function updateOptionSelection(ProductInterface $product, OptionInterface $option)
@@ -141,7 +147,7 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac
141147
$linksToUpdate[] = $productLink;
142148
}
143149
}
144-
/** @var \Magento\Bundle\Api\Data\LinkInterface[] $linksToDelete */
150+
/** @var LinkInterface[] $linksToDelete */
145151
$linksToDelete = $this->compareLinks($existingLinks, $linksToUpdate);
146152
}
147153
foreach ($linksToUpdate as $linkedProduct) {
@@ -162,8 +168,8 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac
162168
/**
163169
* Compute the difference between given arrays.
164170
*
165-
* @param \Magento\Bundle\Api\Data\LinkInterface[] $firstArray
166-
* @param \Magento\Bundle\Api\Data\LinkInterface[] $secondArray
171+
* @param LinkInterface[] $firstArray
172+
* @param LinkInterface[] $secondArray
167173
*
168174
* @return array
169175
*/
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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\Bundle\Model\Quote\Item;
9+
10+
use Magento\Bundle\Model\Product\Price;
11+
use Magento\Bundle\Model\Product\Type;
12+
use Magento\Catalog\Model\Product;
13+
use Magento\Framework\Serialize\Serializer\Json;
14+
15+
/**
16+
* Bundle product options model
17+
*/
18+
class Option
19+
{
20+
/**
21+
* @var Json
22+
*/
23+
private $serializer;
24+
25+
/**
26+
* @param Json $serializer
27+
*/
28+
public function __construct(
29+
Json $serializer
30+
) {
31+
$this->serializer = $serializer;
32+
}
33+
34+
/**
35+
* Get selection options for provided bundle product
36+
*
37+
* @param Product $product
38+
* @return array
39+
*/
40+
public function getSelectionOptions(Product $product): array
41+
{
42+
$options = [];
43+
$bundleOptionIds = $this->getOptionValueAsArray($product, 'bundle_option_ids');
44+
if ($bundleOptionIds) {
45+
/** @var Type $typeInstance */
46+
$typeInstance = $product->getTypeInstance();
47+
$optionsCollection = $typeInstance->getOptionsByIds($bundleOptionIds, $product);
48+
$selectionIds = $this->getOptionValueAsArray($product, 'bundle_selection_ids');
49+
50+
if ($selectionIds) {
51+
$selectionsCollection = $typeInstance->getSelectionsByIds($selectionIds, $product);
52+
$optionsCollection->appendSelections($selectionsCollection, true);
53+
54+
foreach ($selectionsCollection as $selection) {
55+
$selectionId = $selection->getSelectionId();
56+
$options[$selectionId][] = $this->getBundleSelectionAttributes($product, $selection);
57+
}
58+
}
59+
}
60+
61+
return $options;
62+
}
63+
64+
/**
65+
* Get selection attributes for provided selection
66+
*
67+
* @param Product $product
68+
* @param Product $selection
69+
* @return array
70+
*/
71+
private function getBundleSelectionAttributes(Product $product, Product $selection): array
72+
{
73+
$selectionId = $selection->getSelectionId();
74+
/** @var \Magento\Bundle\Model\Option $bundleOption */
75+
$bundleOption = $selection->getOption();
76+
/** @var Price $priceModel */
77+
$priceModel = $product->getPriceModel();
78+
$price = $priceModel->getSelectionFinalTotalPrice($product, $selection, 0, 1);
79+
$customOption = $product->getCustomOption('selection_qty_' . $selectionId);
80+
$qty = (float)($customOption ? $customOption->getValue() : 0);
81+
82+
return [
83+
'code' => 'bundle_selection_attributes',
84+
'value'=> $this->serializer->serialize(
85+
[
86+
'price' => $price,
87+
'qty' => $qty,
88+
'option_label' => $bundleOption->getTitle(),
89+
'option_id' => $bundleOption->getId(),
90+
]
91+
)
92+
];
93+
}
94+
95+
/**
96+
* Get unserialized value of custom option
97+
*
98+
* @param Product $product
99+
* @param string $code
100+
* @return array
101+
*/
102+
private function getOptionValueAsArray(Product $product, string $code): array
103+
{
104+
$option = $product->getCustomOption($code);
105+
return $option && $option->getValue()
106+
? $this->serializer->unserialize($option->getValue())
107+
: [];
108+
}
109+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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\Bundle\Model\Quote\Item\Option;
9+
10+
use Magento\Framework\DataObject;
11+
use Magento\Framework\Serialize\Serializer\Json;
12+
use Magento\Quote\Model\Quote\Item\Option\ComparatorInterface;
13+
14+
/**
15+
* Bundle quote item option comparator
16+
*/
17+
class BundleSelectionAttributesComparator implements ComparatorInterface
18+
{
19+
/**
20+
* @var Json
21+
*/
22+
private $serializer;
23+
24+
/**
25+
* @param Json $serializer
26+
*/
27+
public function __construct(
28+
Json $serializer
29+
) {
30+
$this->serializer = $serializer;
31+
}
32+
33+
/**
34+
* @inheritdoc
35+
*/
36+
public function compare(DataObject $option1, DataObject $option2): bool
37+
{
38+
$value1 = $option1->getValue() ? $this->serializer->unserialize($option1->getValue()) : [];
39+
$value2 = $option2->getValue() ? $this->serializer->unserialize($option2->getValue()) : [];
40+
$option1Id = isset($value1['option_id']) ? (int) $value1['option_id'] : null;
41+
$option2Id = isset($value2['option_id']) ? (int) $value2['option_id'] : null;
42+
43+
return $option1Id === $option2Id;
44+
}
45+
}

0 commit comments

Comments
 (0)