Skip to content

Commit 62e7b3a

Browse files
author
Oleksandr Iegorov
committed
Merge branch 'MAGETWO-69496' of https://github.com/magento-tango/magento2ce into 2.1.13-PR-0.1
2 parents 689f414 + 5570b22 commit 62e7b3a

File tree

4 files changed

+194
-22
lines changed

4 files changed

+194
-22
lines changed

app/code/Magento/Bundle/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Bundle.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,13 @@ public function afterInitialize(
105105
if ($result['bundle_options'] && !$compositeReadonly) {
106106
$product->setBundleOptionsData($result['bundle_options']);
107107
}
108+
108109
$this->processBundleOptionsData($product);
109110
$this->processDynamicOptionsData($product);
111+
} elseif (!$compositeReadonly) {
112+
$extension = $product->getExtensionAttributes();
113+
$extension->setBundleProductOptions([]);
114+
$product->setExtensionAttributes($extension);
110115
}
111116

112117
$affectProductSelections = (bool)$this->request->getPost('affect_bundle_product_selections');
@@ -127,13 +132,11 @@ protected function processBundleOptionsData(\Magento\Catalog\Model\Product $prod
127132
}
128133
$options = [];
129134
foreach ($bundleOptionsData as $key => $optionData) {
130-
if ((bool)$optionData['delete']) {
131-
continue;
132-
}
133-
134135
$option = $this->optionFactory->create(['data' => $optionData]);
135136
$option->setSku($product->getSku());
136-
$option->setOptionId(null);
137+
if (!$option->getOptionId()) {
138+
$option->setOptionId(null);
139+
}
137140

138141
$links = [];
139142
$bundleLinks = $product->getBundleSelectionsData();

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,11 @@ protected function updateOptionSelection(
246246
* @param string $sku
247247
* @return \Magento\Catalog\Api\Data\ProductInterface
248248
* @throws \Magento\Framework\Exception\InputException
249+
* @throws \Magento\Framework\Exception\NoSuchEntityException
249250
*/
250251
private function getProduct($sku)
251252
{
252-
$product = $this->productRepository->get($sku, true);
253+
$product = $this->productRepository->get($sku, true, null, true);
253254
if ($product->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
254255
throw new InputException(__('Only implemented for bundle product'));
255256
}

app/code/Magento/Bundle/Model/Product/SaveHandler.php

Lines changed: 104 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,48 @@ public function __construct(
4040
* @param object $entity
4141
* @param array $arguments
4242
* @return \Magento\Catalog\Api\Data\ProductInterface|object
43+
* @throws \Magento\Framework\Exception\NoSuchEntityException
44+
* @throws \Magento\Framework\Exception\InputException
45+
* @throws \Magento\Framework\Exception\CouldNotSaveException
4346
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
4447
*/
4548
public function execute($entity, $arguments = [])
4649
{
4750
$bundleProductOptions = $entity->getExtensionAttributes()->getBundleProductOptions();
48-
if ($entity->getTypeId() !== 'bundle' || empty($bundleProductOptions)) {
51+
if ($entity->getTypeId() !== Type::TYPE_CODE || empty($bundleProductOptions)) {
4952
return $entity;
5053
}
5154

55+
$existingBundleProductOptions = $this->optionRepository->getList($entity->getSku());
56+
57+
$existingOptionsIds = !empty($existingBundleProductOptions)
58+
? $this->getOptionIds($existingBundleProductOptions)
59+
: [];
60+
$optionIds = !empty($bundleProductOptions)
61+
? $this->getOptionIds($bundleProductOptions)
62+
: [];
63+
64+
$options = $bundleProductOptions ?: [];
65+
5266
if (!$entity->getCopyFromView()) {
53-
/** @var \Magento\Catalog\Api\Data\ProductInterface $entity */
54-
foreach ($this->optionRepository->getList($entity->getSku()) as $option) {
55-
$this->removeOptionLinks($entity->getSku(), $option);
56-
$this->optionRepository->delete($option);
57-
}
67+
$this->processRemovedOptions($entity->getSku(), $existingOptionsIds, $optionIds);
68+
$this->processExistedOptions($entity->getSku(), $existingOptionsIds, $optionIds);
5869

59-
$options = $bundleProductOptions ?: [];
60-
foreach ($options as $option) {
61-
$option->setOptionId(null);
62-
$this->optionRepository->save($entity, $option);
63-
}
70+
$newOptionsIds = array_diff($optionIds, $existingOptionsIds);
71+
$this->saveOptions($entity, $options, $newOptionsIds);
6472
} else {
6573
//save only labels and not selections + product links
66-
$options = $bundleProductOptions ?: [];
67-
foreach ($options as $option) {
68-
$this->optionRepository->save($entity, $option);
69-
$entity->setCopyFromView(false);
70-
}
74+
$this->saveOptions($entity, $options);
75+
$entity->setCopyFromView(false);
7176
}
7277
return $entity;
7378
}
7479

7580
/**
7681
* @param string $entitySku
7782
* @param \Magento\Bundle\Api\Data\OptionInterface $option
83+
* @throws \Magento\Framework\Exception\NoSuchEntityException
84+
* @throws \Magento\Framework\Exception\InputException
7885
* @return void
7986
*/
8087
protected function removeOptionLinks($entitySku, $option)
@@ -86,4 +93,85 @@ protected function removeOptionLinks($entitySku, $option)
8693
}
8794
}
8895
}
96+
97+
/**
98+
* Perform save for all options entities
99+
*
100+
* @param object $entity
101+
* @param array $options
102+
* @param array $newOptionsIds
103+
* @throws \Magento\Framework\Exception\CouldNotSaveException
104+
* @throws \Magento\Framework\Exception\InputException
105+
* @return void
106+
*/
107+
private function saveOptions($entity, array $options, array $newOptionsIds = [])
108+
{
109+
foreach ($options as $option) {
110+
if (in_array($option->getOptionId(), $newOptionsIds, true)) {
111+
$option->setOptionId(null);
112+
}
113+
$this->optionRepository->save($entity, $option);
114+
}
115+
}
116+
117+
/**
118+
* Get options ids from array of the options entities
119+
*
120+
* @param array $options
121+
* @return array
122+
*/
123+
private function getOptionIds(array $options)
124+
{
125+
$optionIds = [];
126+
127+
if (empty($options)) {
128+
return $optionIds;
129+
}
130+
131+
/** @var \Magento\Bundle\Api\Data\OptionInterface $option */
132+
foreach ($options as $option) {
133+
if ($option->getOptionId()) {
134+
$optionIds[] = $option->getOptionId();
135+
}
136+
}
137+
return $optionIds;
138+
}
139+
140+
/**
141+
* Removes old options that no longer exists
142+
*
143+
* @param string $entitySku
144+
* @param array $existingOptionsIds
145+
* @param array $optionIds
146+
* @throws \Magento\Framework\Exception\NoSuchEntityException
147+
* @throws \Magento\Framework\Exception\InputException
148+
* @throws \Magento\Framework\Exception\CouldNotSaveException
149+
* @return void
150+
*/
151+
private function processRemovedOptions($entitySku, array $existingOptionsIds, array $optionIds)
152+
{
153+
foreach (array_diff($existingOptionsIds, $optionIds) as $optionId) {
154+
$option = $this->optionRepository->get($entitySku, $optionId);
155+
$this->removeOptionLinks($entitySku, $option);
156+
$this->optionRepository->delete($option);
157+
}
158+
}
159+
160+
/**
161+
* Removes option links for existed options
162+
*
163+
* @param string $entitySku
164+
* @param array $existingOptionsIds
165+
* @param array $optionIds
166+
* @throws \Magento\Framework\Exception\NoSuchEntityException
167+
* @throws \Magento\Framework\Exception\InputException
168+
* @return void
169+
*/
170+
private function processExistedOptions($entitySku, array $existingOptionsIds, array $optionIds)
171+
{
172+
foreach (array_intersect($optionIds, $existingOptionsIds) as $optionId) {
173+
$option = $this->optionRepository->get($entitySku, $optionId);
174+
$this->removeOptionLinks($entitySku, $option);
175+
}
176+
}
89177
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Bundle\Model\Product;
8+
9+
/**
10+
* Test class for \Magento\Bundle\Model\Product\SaveHandler
11+
* The tested class used indirectly
12+
*
13+
* @magentoDataFixture Magento/Bundle/_files/product.php
14+
* @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php
15+
* @magentoDbIsolation enabled
16+
* @magentoAppIsolation enabled
17+
*/
18+
class SaveHandlerTest extends \PHPUnit_Framework_TestCase
19+
{
20+
/**
21+
* @var \Magento\Framework\ObjectManagerInterface
22+
*/
23+
private $objectManager;
24+
25+
/**
26+
* @var \Magento\Store\Model\Store
27+
*/
28+
private $store;
29+
30+
/**
31+
* @var \Magento\Catalog\Api\ProductRepositoryInterface
32+
*/
33+
private $productRepository;
34+
35+
protected function setUp()
36+
{
37+
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
38+
$this->store = $this->objectManager->create(\Magento\Store\Model\Store::class);
39+
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
40+
$this->productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
41+
}
42+
43+
public function testOptionTitlesOnDifferentStores()
44+
{
45+
/**
46+
* @var \Magento\Bundle\Model\Product\OptionList $optionList
47+
*/
48+
$optionList = $this->objectManager->create(\Magento\Bundle\Model\Product\OptionList::class);
49+
50+
$secondStoreId = $this->store->load('fixture_second_store')->getId();
51+
$thirdStoreId = $this->store->load('fixture_third_store')->getId();
52+
53+
$product = $this->productRepository->get('bundle-product', true, $secondStoreId, true);
54+
$options = $optionList->getItems($product);
55+
$title = $options[0]->getTitle();
56+
$newTitle = $title . ' ' . $this->store->load('fixture_second_store')->getCode();
57+
$options[0]->setTitle($newTitle);
58+
$extension = $product->getExtensionAttributes();
59+
$extension->setBundleProductOptions($options);
60+
$product->setExtensionAttributes($extension);
61+
$product->save();
62+
63+
$product = $this->productRepository->get('bundle-product', true, $thirdStoreId, true);
64+
$options = $optionList->getItems($product);
65+
$newTitle = $title . ' ' . $this->store->load('fixture_third_store')->getCode();
66+
$options[0]->setTitle($newTitle);
67+
$extension = $product->getExtensionAttributes();
68+
$extension->setBundleProductOptions($options);
69+
$product->setExtensionAttributes($extension);
70+
$product->save();
71+
72+
$product = $this->productRepository->get('bundle-product', false, $secondStoreId, true);
73+
$options = $optionList->getItems($product);
74+
$this->assertEquals(1, count($options));
75+
$this->assertEquals(
76+
$title . ' ' . $this->store->load('fixture_second_store')->getCode(),
77+
$options[0]->getTitle()
78+
);
79+
}
80+
}

0 commit comments

Comments
 (0)