Skip to content

Commit

Permalink
Merge pull request #2434 from magento-tango/MAGETWO-84209-2
Browse files Browse the repository at this point in the history
MAGETWO-84209: Impossible specify Bundle option title on store view level
  • Loading branch information
dhorytskyi authored Apr 24, 2018
2 parents 199272b + bcec239 commit 9bdfce4
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,13 @@ public function afterInitialize(
if ($result['bundle_options'] && !$compositeReadonly) {
$product->setBundleOptionsData($result['bundle_options']);
}

$this->processBundleOptionsData($product);
$this->processDynamicOptionsData($product);
} elseif (!$compositeReadonly) {
$extension = $product->getExtensionAttributes();
$extension->setBundleProductOptions([]);
$product->setExtensionAttributes($extension);
}

$affectProductSelections = (bool)$this->request->getPost('affect_bundle_product_selections');
Expand Down
3 changes: 2 additions & 1 deletion app/code/Magento/Bundle/Model/OptionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,11 @@ protected function updateOptionSelection(
* @param string $sku
* @return \Magento\Catalog\Api\Data\ProductInterface
* @throws \Magento\Framework\Exception\InputException
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/
private function getProduct($sku)
{
$product = $this->productRepository->get($sku, true);
$product = $this->productRepository->get($sku, true, null, true);
if ($product->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) {
throw new InputException(__('Only implemented for bundle product'));
}
Expand Down
112 changes: 87 additions & 25 deletions app/code/Magento/Bundle/Model/Product/SaveHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/
namespace Magento\Bundle\Model\Product;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Bundle\Api\ProductOptionRepositoryInterface as OptionRepository;
use Magento\Bundle\Api\ProductLinkManagementInterface;
use Magento\Framework\App\ObjectManager;
Expand Down Expand Up @@ -53,50 +52,50 @@ public function __construct(
* @param object $entity
* @param array $arguments
* @return \Magento\Catalog\Api\Data\ProductInterface|object
* @throws \Magento\Framework\Exception\NoSuchEntityException
* @throws \Magento\Framework\Exception\InputException
* @throws \Magento\Framework\Exception\CouldNotSaveException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function execute($entity, $arguments = [])
{
/** @var \Magento\Bundle\Api\Data\OptionInterface[] $options */
$options = $entity->getExtensionAttributes()->getBundleProductOptions() ?: [];
$bundleProductOptions = $entity->getExtensionAttributes()->getBundleProductOptions() ?: [];

if ($entity->getTypeId() !== 'bundle' || empty($options)) {
if ($entity->getTypeId() !== Type::TYPE_CODE || empty($bundleProductOptions)) {
return $entity;
}

if (!$entity->getCopyFromView()) {
$updatedOptions = [];
$oldOptions = $this->optionRepository->getList($entity->getSku());

$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
$existingBundleProductOptions = $this->optionRepository->getList($entity->getSku());

$productId = $entity->getData($metadata->getLinkField());
$existingOptionsIds = !empty($existingBundleProductOptions)
? $this->getOptionIds($existingBundleProductOptions)
: [];
$optionIds = !empty($bundleProductOptions)
? $this->getOptionIds($bundleProductOptions)
: [];

foreach ($options as $option) {
$updatedOptions[$option->getOptionId()][$productId] = (bool)$option->getOptionId();
}

foreach ($oldOptions as $option) {
if (!isset($updatedOptions[$option->getOptionId()][$productId])) {
$option->setParentId($productId);
$this->removeOptionLinks($entity->getSku(), $option);
$this->optionRepository->delete($option);
}
}
}
$options = $bundleProductOptions ?: [];

foreach ($options as $option) {
$this->optionRepository->save($entity, $option);
if (!$entity->getCopyFromView()) {
$this->processRemovedOptions($entity->getSku(), $existingOptionsIds, $optionIds);

$newOptionsIds = array_diff($optionIds, $existingOptionsIds);
$this->saveOptions($entity, $options, $newOptionsIds);
} else {
//save only labels and not selections + product links
$this->saveOptions($entity, $options);
$entity->setCopyFromView(false);
}

$entity->setCopyFromView(false);

return $entity;
}

/**
* @param string $entitySku
* @param \Magento\Bundle\Api\Data\OptionInterface $option
* @throws \Magento\Framework\Exception\NoSuchEntityException
* @throws \Magento\Framework\Exception\InputException
* @return void
*/
protected function removeOptionLinks($entitySku, $option)
Expand All @@ -108,4 +107,67 @@ protected function removeOptionLinks($entitySku, $option)
}
}
}

/**
* Perform save for all options entities
*
* @param object $entity
* @param array $options
* @param array $newOptionsIds
* @throws \Magento\Framework\Exception\CouldNotSaveException
* @throws \Magento\Framework\Exception\InputException
* @return void
*/
private function saveOptions($entity, array $options, array $newOptionsIds = [])
{
foreach ($options as $option) {
if (in_array($option->getOptionId(), $newOptionsIds, true)) {
$option->setOptionId(null);
}
$this->optionRepository->save($entity, $option);
}
}

/**
* Get options ids from array of the options entities
*
* @param array $options
* @return array
*/
private function getOptionIds(array $options)
{
$optionIds = [];

if (empty($options)) {
return $optionIds;
}

/** @var \Magento\Bundle\Api\Data\OptionInterface $option */
foreach ($options as $option) {
if ($option->getOptionId()) {
$optionIds[] = $option->getOptionId();
}
}
return $optionIds;
}

/**
* Removes old options that no longer exists
*
* @param string $entitySku
* @param array $existingOptionsIds
* @param array $optionIds
* @throws \Magento\Framework\Exception\NoSuchEntityException
* @throws \Magento\Framework\Exception\InputException
* @throws \Magento\Framework\Exception\CouldNotSaveException
* @return void
*/
private function processRemovedOptions($entitySku, array $existingOptionsIds, array $optionIds)
{
foreach (array_diff($existingOptionsIds, $optionIds) as $optionId) {
$option = $this->optionRepository->get($entitySku, $optionId);
$this->removeOptionLinks($entitySku, $option);
$this->optionRepository->delete($option);
}
}
}
61 changes: 14 additions & 47 deletions app/code/Magento/Bundle/Model/ResourceModel/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,39 +81,28 @@ protected function _afterSave(\Magento\Framework\Model\AbstractModel $object)
{
parent::_afterSave($object);

$conditions = [
$condition = [
'option_id = ?' => $object->getId(),
'store_id = ? OR store_id = 0' => $object->getStoreId(),
'parent_product_id = ?' => $object->getParentId()
];

$connection = $this->getConnection();
$connection->delete($this->getTable('catalog_product_bundle_option_value'), $condition);

if ($this->isOptionPresent($conditions)) {
$connection->update(
$this->getTable('catalog_product_bundle_option_value'),
[
'title' => $object->getTitle()
],
$conditions
);
} else {
$data = new \Magento\Framework\DataObject();
$data->setOptionId($object->getId())
->setStoreId($object->getStoreId())
->setParentProductId($object->getParentId())
->setTitle($object->getTitle());
$data = new \Magento\Framework\DataObject();
$data->setOptionId($object->getId())
->setStoreId($object->getStoreId())
->setParentProductId($object->getParentId())
->setTitle($object->getTitle());

$connection->insert($this->getTable('catalog_product_bundle_option_value'), $data->getData());
$connection->insert($this->getTable('catalog_product_bundle_option_value'), $data->getData());

/**
* also saving default value if this store view scope
*/
if ($object->getStoreId()) {
$data->setStoreId(0);
$data->setTitle($object->getDefaultTitle());
$connection->insert($this->getTable('catalog_product_bundle_option_value'), $data->getData());
}
/**
* also saving default fallback value
*/
if (0 !== (int)$object->getStoreId()) {
$data->setStoreId(0)->setTitle($object->getDefaultTitle());
$connection->insert($this->getTable('catalog_product_bundle_option_value'), $data->getData());
}

return $this;
Expand Down Expand Up @@ -218,26 +207,4 @@ public function save(\Magento\Framework\Model\AbstractModel $object)

return $this;
}

/**
* Is Bundle option present in the database
*
* @param array $conditions
*
* @return bool
*/
private function isOptionPresent($conditions)
{
$connection = $this->getConnection();

$select = $connection->select()->from($this->getTable('catalog_product_bundle_option_value'));
foreach ($conditions as $condition => $conditionValue) {
$select->where($condition, $conditionValue);
}
$select->limit(1);

$rowSelect = $connection->fetchRow($select);

return (is_array($rowSelect) && !empty($rowSelect));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\Bundle\Model\Product;

/**
* Test class for \Magento\Bundle\Model\Product\SaveHandler
* The tested class used indirectly
*
* @magentoDataFixture Magento/Bundle/_files/product.php
* @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php
* @magentoDbIsolation disabled
* @magentoAppIsolation enabled
*/
class SaveHandlerTest extends \PHPUnit\Framework\TestCase
{
/**
* @var \Magento\Framework\ObjectManagerInterface
*/
private $objectManager;

/**
* @var \Magento\Store\Model\Store
*/
private $store;

/**
* @var \Magento\Catalog\Api\ProductRepositoryInterface
*/
private $productRepository;

protected function setUp()
{
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
$this->store = $this->objectManager->create(\Magento\Store\Model\Store::class);
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
$this->productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
}

public function testOptionTitlesOnDifferentStores()
{
/**
* @var \Magento\Bundle\Model\Product\OptionList $optionList
*/
$optionList = $this->objectManager->create(\Magento\Bundle\Model\Product\OptionList::class);

$secondStoreId = $this->store->load('fixture_second_store')->getId();
$thirdStoreId = $this->store->load('fixture_third_store')->getId();

$product = $this->productRepository->get('bundle-product', true, $secondStoreId, true);
$options = $optionList->getItems($product);
$title = $options[0]->getTitle();
$newTitle = $title . ' ' . $this->store->load('fixture_second_store')->getCode();
$options[0]->setTitle($newTitle);
$extension = $product->getExtensionAttributes();
$extension->setBundleProductOptions($options);
$product->setExtensionAttributes($extension);
$product->save();

$product = $this->productRepository->get('bundle-product', true, $thirdStoreId, true);
$options = $optionList->getItems($product);
$newTitle = $title . ' ' . $this->store->load('fixture_third_store')->getCode();
$options[0]->setTitle($newTitle);
$extension = $product->getExtensionAttributes();
$extension->setBundleProductOptions($options);
$product->setExtensionAttributes($extension);
$product->save();

$product = $this->productRepository->get('bundle-product', false, $secondStoreId, true);
$options = $optionList->getItems($product);
$this->assertEquals(1, count($options));
$this->assertEquals(
$title . ' ' . $this->store->load('fixture_second_store')->getCode(),
$options[0]->getTitle()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public function testPrepareData()
*/
public function testPrepareDataWithDifferentStoreValues()
{
$this->markTestSkipped('Test is blocked by MAGETWO-84209.');
$storeCode = 'default';
$expectedNames = [
'name' => 'Bundle Product Items',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ function (Product $product) {
array_values($resultCollection->getItems())
);

asort($expectedSkuList);
asort($resultSkuList);
sort($expectedSkuList);
sort($resultSkuList);

$this->assertEquals($expectedSkuList, $resultSkuList, sprintf('%s failed', $variationName));
}
Expand Down

0 comments on commit 9bdfce4

Please sign in to comment.