From c45ec2a7f2211020617ec9e0ab9e2b7673cde6b8 Mon Sep 17 00:00:00 2001 From: magento-engcom-team Date: Thu, 7 Dec 2017 11:52:23 +0200 Subject: [PATCH 1/5] 10797: catalogProductTierPriceManagementV1 DELETE and POST operation wipes out media gallery selections when used on store code "all". --- .../Catalog/Model/ProductRepository.php | 18 ++++++++++-------- .../Api/ProductTierPriceManagementTest.php | 10 ++++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index e814dc03cf37f..3f4d275fb9553 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -489,16 +489,17 @@ private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $produc * @throws InputException * @throws StateException * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws LocalizedException */ - protected function processMediaGallery(ProductInterface $product, $mediaGalleryEntries) + protected function processMediaGallery(ProductInterface $product, array $mediaGalleryEntries) { $existingMediaGallery = $product->getMediaGallery('images'); $newEntries = []; $entriesById = []; if (!empty($existingMediaGallery)) { foreach ($mediaGalleryEntries as $entry) { - if (isset($entry['value_id'])) { - $entriesById[$entry['value_id']] = $entry; + if (isset($entry['id'])) { + $entriesById[$entry['id']] = $entry; } else { $newEntries[] = $entry; } @@ -515,6 +516,7 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE $existingEntry['removed'] = true; } } + unset($existingEntry); $product->setData('media_gallery', ["images" => $existingMediaGallery]); } else { $newEntries = $mediaGalleryEntries; @@ -536,9 +538,9 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE } /** @var ImageContentInterface $contentDataObject */ $contentDataObject = $this->contentFactory->create() - ->setName($newEntry['content']['data'][ImageContentInterface::NAME]) - ->setBase64EncodedData($newEntry['content']['data'][ImageContentInterface::BASE64_ENCODED_DATA]) - ->setType($newEntry['content']['data'][ImageContentInterface::TYPE]); + ->setName($newEntry['content'][ImageContentInterface::NAME]) + ->setBase64EncodedData($newEntry['content'][ImageContentInterface::BASE64_ENCODED_DATA]) + ->setType($newEntry['content'][ImageContentInterface::TYPE]); $newEntry['content'] = $contentDataObject; $this->processNewMediaGalleryEntry($product, $newEntry); @@ -587,8 +589,8 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO $product = $this->initializeProductData($productDataArray, empty($existingProduct)); $this->processLinks($product, $productLinks); - if (isset($productDataArray['media_gallery'])) { - $this->processMediaGallery($product, $productDataArray['media_gallery']['images']); + if (isset($productDataArray['media_gallery_entries'])) { + $this->processMediaGallery($product, $productDataArray['media_gallery_entries']); } if (!$product->getOptionsReadonly()) { diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php index 315458a0e3872..7df0aede46b26 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php @@ -60,15 +60,17 @@ public function getListDataProvider() /** * @param string|int $customerGroupId * @param int $qty - * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoApiDataFixture Magento/Catalog/_files/product_with_image.php * @dataProvider deleteDataProvider */ public function testDelete($customerGroupId, $qty) { $productSku = 'simple'; + $objectManager = \Magento\TestFramework\ObjectManager::getInstance(); + $productBefore = $objectManager->get(ProductRepositoryInterface::class)->get($productSku, false, null, true); $serviceInfo = [ 'rest' => [ - 'resourcePath' => self::RESOURCE_PATH + 'resourcePath' => self::RESOURCE_PATH . $productSku . "/group-prices/" . $customerGroupId . "/tiers/" . $qty, 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE, ], @@ -80,6 +82,10 @@ public function testDelete($customerGroupId, $qty) ]; $requestData = ['sku' => $productSku, 'customerGroupId' => $customerGroupId, 'qty' => $qty]; $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + $productAfter = $objectManager->get(ProductRepositoryInterface::class)->get($productSku, false, null, true); + $this->assertSame($productBefore->getImage(), $productAfter->getImage()); + $this->assertSame($productBefore->getSmallImage(), $productAfter->getSmallImage()); + $this->assertSame($productBefore->getThumbnail(), $productAfter->getThumbnail()); } public function deleteDataProvider() From 7959af7912ee5262ad0db46b3b57f2ef93dbc7c0 Mon Sep 17 00:00:00 2001 From: magento-engcom-team Date: Thu, 7 Dec 2017 15:49:41 +0200 Subject: [PATCH 2/5] 10797: catalogProductTierPriceManagementV1 DELETE and POST operation wipes out media gallery selections when used on store code "all". --- .../Catalog/Model/ProductRepository.php | 24 ++++++++++++++++++- .../Test/Unit/Model/ProductRepositoryTest.php | 23 ++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 3f4d275fb9553..e6d2de0365333 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -507,7 +507,7 @@ protected function processMediaGallery(ProductInterface $product, array $mediaGa foreach ($existingMediaGallery as $key => &$existingEntry) { if (isset($entriesById[$existingEntry['value_id']])) { $updatedEntry = $entriesById[$existingEntry['value_id']]; - if ($updatedEntry['file'] === null) { + if (isset($updatedEntry['file']) && $updatedEntry['file'] === null) { unset($updatedEntry['file']); } $existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry); @@ -546,6 +546,9 @@ protected function processMediaGallery(ProductInterface $product, array $mediaGa $finalGallery = $product->getData('media_gallery'); $newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById)); + if (isset($newEntry['extension_attributes'])) { + $this->processExtensionAttributes($newEntry, $newEntry['extension_attributes']); + } $newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]); $entriesById[$newEntryId] = $newEntry; $finalGallery['images'][$newEntryId] = $newEntry; @@ -788,4 +791,23 @@ private function getCollectionProcessor() } return $this->collectionProcessor; } + + /** + * Convert extension attribute for product media gallery. + * + * @param array $newEntry + * @param array $extensionAttributes + * @return void + */ + private function processExtensionAttributes(array &$newEntry, array $extensionAttributes) + { + foreach ($extensionAttributes as $code => $value) { + if (is_array($value)) { + $this->processExtensionAttributes($newEntry, $value); + } else { + $newEntry[$code] = $value; + } + } + unset($newEntry['extension_attributes']); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php index c98705b4eda63..8cd3fcd11491f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php @@ -9,7 +9,6 @@ namespace Magento\Catalog\Test\Unit\Model; -use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Framework\Api\Data\ImageContentInterface; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\DB\Adapter\ConnectionException; @@ -1178,7 +1177,21 @@ public function testSaveExistingWithNewMediaGalleryEntries() $this->setupProductMocksForSave(); //media gallery data - $this->productData['media_gallery'] = $newEntriesData; + $this->productData['media_gallery_entries'] = [ + [ + 'id' => null, + 'label' => "label_text", + 'position' => 10, + 'disabled' => false, + 'types' => ['image', 'small_image'], + 'content' => [ + ImageContentInterface::NAME => 'filename', + ImageContentInterface::TYPE => 'image/jpeg', + ImageContentInterface::BASE64_ENCODED_DATA => 'encoded_content', + ], + 'media_type' => 'media_type', + ] + ]; $this->extensibleDataObjectConverterMock ->expects($this->once()) ->method('toNestedArray') @@ -1288,7 +1301,7 @@ public function testSaveExistingWithMediaGalleryEntries() //update one entry, delete one entry $newEntries = [ [ - 'value_id' => 5, + 'id' => 5, "label" => "new_label_text", 'file' => 'filename1', 'position' => 10, @@ -1316,7 +1329,7 @@ public function testSaveExistingWithMediaGalleryEntries() $expectedResult = [ [ 'value_id' => 5, - 'value_id' => 5, + 'id' => 5, "label" => "new_label_text", 'file' => 'filename1', 'position' => 10, @@ -1332,7 +1345,7 @@ public function testSaveExistingWithMediaGalleryEntries() $this->setupProductMocksForSave(); //media gallery data - $this->productData['media_gallery']['images'] = $newEntries; + $this->productData['media_gallery_entries'] = $newEntries; $this->extensibleDataObjectConverterMock ->expects($this->once()) ->method('toNestedArray') From 5aef35b950f77917f39406bfcfc9c481275cefe9 Mon Sep 17 00:00:00 2001 From: magento-engcom-team Date: Thu, 7 Dec 2017 18:24:59 +0200 Subject: [PATCH 3/5] 10797: catalogProductTierPriceManagementV1 DELETE and POST operation wipes out media gallery selections when used on store code "all". --- .../Catalog/Model/ProductRepository.php | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index e6d2de0365333..cdab94b57b4e4 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -488,8 +488,8 @@ private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $produc * @return $this * @throws InputException * @throws StateException - * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @throws LocalizedException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function processMediaGallery(ProductInterface $product, array $mediaGalleryEntries) { @@ -531,29 +531,8 @@ protected function processMediaGallery(ProductInterface $product, array $mediaGa } } } + $this->processEntries($product, $newEntries, $entriesById); - foreach ($newEntries as $newEntry) { - if (!isset($newEntry['content'])) { - throw new InputException(__('The image content is not valid.')); - } - /** @var ImageContentInterface $contentDataObject */ - $contentDataObject = $this->contentFactory->create() - ->setName($newEntry['content'][ImageContentInterface::NAME]) - ->setBase64EncodedData($newEntry['content'][ImageContentInterface::BASE64_ENCODED_DATA]) - ->setType($newEntry['content'][ImageContentInterface::TYPE]); - $newEntry['content'] = $contentDataObject; - $this->processNewMediaGalleryEntry($product, $newEntry); - - $finalGallery = $product->getData('media_gallery'); - $newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById)); - if (isset($newEntry['extension_attributes'])) { - $this->processExtensionAttributes($newEntry, $newEntry['extension_attributes']); - } - $newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]); - $entriesById[$newEntryId] = $newEntry; - $finalGallery['images'][$newEntryId] = $newEntry; - $product->setData('media_gallery', $finalGallery); - } return $this; } @@ -810,4 +789,41 @@ private function processExtensionAttributes(array &$newEntry, array $extensionAt } unset($newEntry['extension_attributes']); } + + /** + * Convert entries into product media gallery data and set to product. + * + * @param ProductInterface $product + * @param array $newEntries + * @param array $entriesById + * @throws InputException + * @throws LocalizedException + * @throws StateException + * @return void + */ + private function processEntries(ProductInterface $product, array $newEntries, array $entriesById) + { + foreach ($newEntries as $newEntry) { + if (!isset($newEntry['content'])) { + throw new InputException(__('The image content is not valid.')); + } + /** @var ImageContentInterface $contentDataObject */ + $contentDataObject = $this->contentFactory->create() + ->setName($newEntry['content'][ImageContentInterface::NAME]) + ->setBase64EncodedData($newEntry['content'][ImageContentInterface::BASE64_ENCODED_DATA]) + ->setType($newEntry['content'][ImageContentInterface::TYPE]); + $newEntry['content'] = $contentDataObject; + $this->processNewMediaGalleryEntry($product, $newEntry); + + $finalGallery = $product->getData('media_gallery'); + $newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById)); + if (isset($newEntry['extension_attributes'])) { + $this->processExtensionAttributes($newEntry, $newEntry['extension_attributes']); + } + $newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]); + $entriesById[$newEntryId] = $newEntry; + $finalGallery['images'][$newEntryId] = $newEntry; + $product->setData('media_gallery', $finalGallery); + } + } } From 6e3ebfbd04ae24ebcd0a08ff316182e575513c83 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Mon, 11 Dec 2017 15:47:08 +0200 Subject: [PATCH 4/5] 10797: catalogProductTierPriceManagementV1 DELETE and POST operation wipes out media gallery selections when used on store code "all". --- app/code/Magento/Catalog/Model/ProductRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index cdab94b57b4e4..90b18031c1448 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -507,7 +507,7 @@ protected function processMediaGallery(ProductInterface $product, array $mediaGa foreach ($existingMediaGallery as $key => &$existingEntry) { if (isset($entriesById[$existingEntry['value_id']])) { $updatedEntry = $entriesById[$existingEntry['value_id']]; - if (isset($updatedEntry['file']) && $updatedEntry['file'] === null) { + if (array_key_exists('file', $updatedEntry) && $updatedEntry['file'] === null) { unset($updatedEntry['file']); } $existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry); From 93df8bf33a25756cbaedfc686be3e9f982df6ff8 Mon Sep 17 00:00:00 2001 From: Ievgen Shakhsuvarov Date: Tue, 12 Dec 2017 13:58:50 +0200 Subject: [PATCH 5/5] Update ProductRepository.php --- app/code/Magento/Catalog/Model/ProductRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 90b18031c1448..e76bba52b4a3f 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -491,7 +491,7 @@ private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $produc * @throws LocalizedException * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - protected function processMediaGallery(ProductInterface $product, array $mediaGalleryEntries) + protected function processMediaGallery(ProductInterface $product, $mediaGalleryEntries) { $existingMediaGallery = $product->getMediaGallery('images'); $newEntries = [];