diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
index 83feea903f993..f260b01c02ef4 100644
--- a/app/code/Magento/Catalog/Model/ProductRepository.php
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -6,10 +6,8 @@
*/
namespace Magento\Catalog\Model;
-use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product\Gallery\MimeTypeExtensionMap;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
-use Magento\Framework\Api\Data\ImageContentInterface;
use Magento\Framework\Api\Data\ImageContentInterfaceFactory;
use Magento\Framework\Api\ImageContentValidatorInterface;
use Magento\Framework\Api\ImageProcessorInterface;
@@ -18,10 +16,8 @@
use Magento\Framework\DB\Adapter\DeadlockException;
use Magento\Framework\DB\Adapter\LockWaitException;
use Magento\Framework\Exception\CouldNotSaveException;
-use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
-use Magento\Framework\Exception\StateException;
use Magento\Framework\Exception\ValidatorException;
/**
@@ -116,11 +112,15 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
protected $fileSystem;
/**
+ * @deprecated
+ * @see \Magento\Catalog\Model\MediaGalleryProcessor
* @var ImageContentInterfaceFactory
*/
protected $contentFactory;
/**
+ * @deprecated
+ * @see \Magento\Catalog\Model\MediaGalleryProcessor
* @var ImageProcessorInterface
*/
protected $imageProcessor;
@@ -131,7 +131,7 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
protected $extensionAttributesJoinProcessor;
/**
- * @var \Magento\Catalog\Model\Product\Gallery\Processor
+ * @var ProductRepository\MediaGalleryProcessor
*/
protected $mediaGalleryProcessor;
@@ -329,6 +329,9 @@ protected function initializeProductData(array $productData, $createNew)
unset($productData['media_gallery']);
if ($createNew) {
$product = $this->productFactory->create();
+ if (isset($productData['price']) && !isset($productData['product_type'])) {
+ $product->setTypeId(Product\Type::TYPE_SIMPLE);
+ }
if ($this->storeManager->hasSingleStore()) {
$product->setWebsiteIds([$this->storeManager->getStore(true)->getWebsiteId()]);
}
@@ -375,53 +378,6 @@ private function assignProductToWebsites(\Magento\Catalog\Model\Product $product
$product->setWebsiteIds($websiteIds);
}
- /**
- * @param ProductInterface $product
- * @param array $newEntry
- * @return $this
- * @throws InputException
- * @throws StateException
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- protected function processNewMediaGalleryEntry(
- ProductInterface $product,
- array $newEntry
- ) {
- /** @var ImageContentInterface $contentDataObject */
- $contentDataObject = $newEntry['content'];
-
- /** @var \Magento\Catalog\Model\Product\Media\Config $mediaConfig */
- $mediaConfig = $product->getMediaConfig();
- $mediaTmpPath = $mediaConfig->getBaseTmpMediaPath();
-
- $relativeFilePath = $this->imageProcessor->processImageContent($mediaTmpPath, $contentDataObject);
- $tmpFilePath = $mediaConfig->getTmpMediaShortUrl($relativeFilePath);
-
- if (!$product->hasGalleryAttribute()) {
- throw new StateException(__('Requested product does not support images.'));
- }
-
- $imageFileUri = $this->getMediaGalleryProcessor()->addImage(
- $product,
- $tmpFilePath,
- isset($newEntry['types']) ? $newEntry['types'] : [],
- true,
- isset($newEntry['disabled']) ? $newEntry['disabled'] : true
- );
- // Update additional fields that are still empty after addImage call
- $this->getMediaGalleryProcessor()->updateImage(
- $product,
- $imageFileUri,
- [
- 'label' => $newEntry['label'],
- 'position' => $newEntry['position'],
- 'disabled' => $newEntry['disabled'],
- 'media_type' => $newEntry['media_type'],
- ]
- );
- return $this;
- }
-
/**
* Process product links, creating new links, updating and deleting existing links
*
@@ -480,67 +436,6 @@ private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $produc
return $this;
}
- /**
- * Process Media gallery data before save product.
- *
- * Compare Media Gallery Entries Data with existing Media Gallery
- * * If Media entry has not value_id set it as new
- * * If Existing entry 'value_id' absent in Media Gallery set 'removed' flag
- * * Merge Existing and new media gallery
- *
- * @param ProductInterface $product contains only existing media gallery items
- * @param array $mediaGalleryEntries array which contains all media gallery items
- * @return $this
- * @throws InputException
- * @throws StateException
- * @throws LocalizedException
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- */
- protected function processMediaGallery(ProductInterface $product, $mediaGalleryEntries)
- {
- $existingMediaGallery = $product->getMediaGallery('images');
- $newEntries = [];
- $entriesById = [];
- if (!empty($existingMediaGallery)) {
- foreach ($mediaGalleryEntries as $entry) {
- if (isset($entry['id'])) {
- $entriesById[$entry['id']] = $entry;
- } else {
- $newEntries[] = $entry;
- }
- }
- foreach ($existingMediaGallery as $key => &$existingEntry) {
- if (isset($entriesById[$existingEntry['value_id']])) {
- $updatedEntry = $entriesById[$existingEntry['value_id']];
- if (array_key_exists('file', $updatedEntry) && $updatedEntry['file'] === null) {
- unset($updatedEntry['file']);
- }
- $existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
- } else {
- //set the removed flag
- $existingEntry['removed'] = true;
- }
- }
- unset($existingEntry);
- $product->setData('media_gallery', ["images" => $existingMediaGallery]);
- } else {
- $newEntries = $mediaGalleryEntries;
- }
-
- $this->getMediaGalleryProcessor()->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
- $images = $product->getMediaGallery('images');
- if ($images) {
- foreach ($images as $image) {
- if (!isset($image['removed']) && !empty($image['types'])) {
- $this->getMediaGalleryProcessor()->setMediaAttribute($product, $image['types'], $image['file']);
- }
- }
- }
- $this->processEntries($product, $newEntries, $entriesById);
-
- return $this;
- }
-
/**
* {@inheritdoc}
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
@@ -577,7 +472,10 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
$this->processLinks($product, $productLinks);
if (isset($productDataArray['media_gallery_entries'])) {
- $this->processMediaGallery($product, $productDataArray['media_gallery_entries']);
+ $this->getMediaGalleryProcessor()->processMediaGallery(
+ $product,
+ $productDataArray['media_gallery_entries']
+ );
}
if (!$product->getOptionsReadonly()) {
@@ -749,13 +647,13 @@ public function cleanCache()
}
/**
- * @return Product\Gallery\Processor
+ * @return ProductRepository\MediaGalleryProcessor
*/
private function getMediaGalleryProcessor()
{
if (null === $this->mediaGalleryProcessor) {
$this->mediaGalleryProcessor = \Magento\Framework\App\ObjectManager::getInstance()
- ->get(\Magento\Catalog\Model\Product\Gallery\Processor::class);
+ ->get(ProductRepository\MediaGalleryProcessor::class);
}
return $this->mediaGalleryProcessor;
}
@@ -775,60 +673,4 @@ 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']);
- }
-
- /**
- * 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);
- }
- }
}
diff --git a/app/code/Magento/Catalog/Model/ProductRepository/MediaGalleryProcessor.php b/app/code/Magento/Catalog/Model/ProductRepository/MediaGalleryProcessor.php
new file mode 100644
index 0000000000000..4cc31d98fdfc2
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ProductRepository/MediaGalleryProcessor.php
@@ -0,0 +1,218 @@
+processor = $processor;
+ $this->contentFactory = $contentFactory;
+ $this->imageProcessor = $imageProcessor;
+ }
+
+ /**
+ * Process Media gallery data before save product.
+ *
+ * Compare Media Gallery Entries Data with existing Media Gallery
+ * * If Media entry has not value_id set it as new
+ * * If Existing entry 'value_id' absent in Media Gallery set 'removed' flag
+ * * Merge Existing and new media gallery
+ *
+ * @param ProductInterface $product contains only existing media gallery items.
+ * @param array $mediaGalleryEntries array which contains all media gallery items.
+ * @return void
+ * @throws InputException
+ * @throws StateException
+ * @throws LocalizedException
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ */
+ public function processMediaGallery(ProductInterface $product, array $mediaGalleryEntries)
+ {
+ $existingMediaGallery = $product->getMediaGallery('images');
+ $newEntries = [];
+ $entriesById = [];
+ if (!empty($existingMediaGallery)) {
+ foreach ($mediaGalleryEntries as $entry) {
+ if (isset($entry['id'])) {
+ $entriesById[$entry['id']] = $entry;
+ } else {
+ $newEntries[] = $entry;
+ }
+ }
+ foreach ($existingMediaGallery as $key => &$existingEntry) {
+ if (isset($entriesById[$existingEntry['value_id']])) {
+ $updatedEntry = $entriesById[$existingEntry['value_id']];
+ if (array_key_exists('file', $updatedEntry) && $updatedEntry['file'] === null) {
+ unset($updatedEntry['file']);
+ }
+ $existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
+ } else {
+ //set the removed flag.
+ $existingEntry['removed'] = true;
+ }
+ }
+ unset($existingEntry);
+ $product->setData('media_gallery', ["images" => $existingMediaGallery]);
+ } else {
+ $newEntries = $mediaGalleryEntries;
+ }
+
+ $this->processor->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
+ $images = $product->getMediaGallery('images');
+ if ($images) {
+ foreach ($images as $image) {
+ if (!isset($image['removed']) && !empty($image['types'])) {
+ $this->processor->setMediaAttribute($product, $image['types'], $image['file']);
+ }
+ }
+ }
+ $this->processEntries($product, $newEntries, $entriesById);
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Save gallery entry as image.
+ *
+ * @param ProductInterface $product
+ * @param array $newEntry
+ * @return void
+ * @throws InputException
+ * @throws StateException
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ private function processNewMediaGalleryEntry(
+ ProductInterface $product,
+ array $newEntry
+ ) {
+ /** @var ImageContentInterface $contentDataObject */
+ $contentDataObject = $newEntry['content'];
+
+ /** @var \Magento\Catalog\Model\Product\Media\Config $mediaConfig */
+ $mediaConfig = $product->getMediaConfig();
+ $mediaTmpPath = $mediaConfig->getBaseTmpMediaPath();
+
+ $relativeFilePath = $this->imageProcessor->processImageContent($mediaTmpPath, $contentDataObject);
+ $tmpFilePath = $mediaConfig->getTmpMediaShortUrl($relativeFilePath);
+
+ if (!$product->hasGalleryAttribute()) {
+ throw new StateException(__('Requested product does not support images.'));
+ }
+
+ $imageFileUri = $this->processor->addImage(
+ $product,
+ $tmpFilePath,
+ isset($newEntry['types']) ? $newEntry['types'] : [],
+ true,
+ isset($newEntry['disabled']) ? $newEntry['disabled'] : true
+ );
+ // Update additional fields that are still empty after addImage call.
+ $this->processor->updateImage(
+ $product,
+ $imageFileUri,
+ [
+ 'label' => $newEntry['label'],
+ 'position' => $newEntry['position'],
+ 'disabled' => $newEntry['disabled'],
+ 'media_type' => $newEntry['media_type'],
+ ]
+ );
+ }
+
+ /**
+ * 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/ProductRepository/MediaGalleryProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepository/MediaGalleryProcessorTest.php
new file mode 100644
index 0000000000000..02773b2fb3d70
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepository/MediaGalleryProcessorTest.php
@@ -0,0 +1,227 @@
+product = $this->createPartialMock(
+ \Magento\Catalog\Model\Product::class,
+ [
+ 'hasGalleryAttribute',
+ 'getMediaConfig',
+ 'getMediaAttributes',
+ 'getMediaGalleryEntries',
+ ]
+ );
+ $this->product->expects($this->any())
+ ->method('hasGalleryAttribute')
+ ->willReturn(true);
+ $this->processor = $this->getMockBuilder(Processor::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->contentFactory = $this->getMockBuilder(ImageContentInterfaceFactory::class)
+ ->setMethods(['create'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->imageProcessor = $this->getMockBuilder(ImageProcessorInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $objectManager = new ObjectManager($this);
+ $this->model = $objectManager->getObject(
+ MediaGalleryProcessor::class,
+ [
+ 'processor' => $this->processor,
+ 'contentFactory' => $this->contentFactory,
+ 'imageProcessor' => $this->imageProcessor,
+ ]
+ );
+ }
+
+ /**
+ * Test add image.
+ *
+ * @return void
+ */
+ public function testProcessWithNewMediaEntry()
+ {
+ $mediaGalleryEntries = [
+ [
+ 'value_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',
+ ],
+ ];
+
+ //setup media attribute backend.
+ $mediaTmpPath = '/tmp';
+ $absolutePath = '/a/b/filename.jpg';
+ $mediaConfigMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Media\Config::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mediaConfigMock->expects($this->once())
+ ->method('getTmpMediaShortUrl')
+ ->with($absolutePath)
+ ->willReturn($mediaTmpPath . $absolutePath);
+ $this->product->setData('media_gallery', ['images' => $mediaGalleryEntries]);
+ $this->product->expects($this->any())
+ ->method('getMediaAttributes')
+ ->willReturn(['image' => 'imageAttribute', 'small_image' => 'small_image_attribute']);
+ $this->product->expects($this->once())
+ ->method('getMediaConfig')
+ ->willReturn($mediaConfigMock);
+ $this->processor->expects($this->once())->method('clearMediaAttribute')
+ ->with($this->product, ['image', 'small_image']);
+
+ //verify new entries.
+ $contentDataObject = $this->getMockBuilder(\Magento\Framework\Api\ImageContent::class)
+ ->disableOriginalConstructor()
+ ->setMethods(null)
+ ->getMock();
+ $this->contentFactory->expects($this->once())
+ ->method('create')
+ ->willReturn($contentDataObject);
+
+ $this->imageProcessor->expects($this->once())
+ ->method('processImageContent')
+ ->willReturn($absolutePath);
+
+ $imageFileUri = 'imageFileUri';
+ $this->processor->expects($this->once())->method('addImage')
+ ->with($this->product, $mediaTmpPath . $absolutePath, ['image', 'small_image'], true, false)
+ ->willReturn($imageFileUri);
+ $this->processor->expects($this->once())->method('updateImage')
+ ->with(
+ $this->product,
+ $imageFileUri,
+ [
+ 'label' => 'label_text',
+ 'position' => 10,
+ 'disabled' => false,
+ 'media_type' => 'media_type',
+ ]
+ );
+
+ $this->model->processMediaGallery($this->product, $mediaGalleryEntries);
+ }
+
+ /**
+ * Test update(delete) images.
+ */
+ public function testProcessExistingWithMediaGalleryEntries()
+ {
+ //update one entry, delete one entry.
+ $newEntries = [
+ [
+ 'id' => 5,
+ 'label' => 'new_label_text',
+ 'file' => 'filename1',
+ 'position' => 10,
+ 'disabled' => false,
+ 'types' => ['image', 'small_image'],
+ ],
+ ];
+
+ $existingMediaGallery = [
+ 'images' => [
+ [
+ 'value_id' => 5,
+ 'label' => 'label_text',
+ 'file' => 'filename1',
+ 'position' => 10,
+ 'disabled' => true,
+ ],
+ [
+ 'value_id' => 6, //will be deleted.
+ 'file' => 'filename2',
+ ],
+ ],
+ ];
+
+ $expectedResult = [
+ [
+ 'value_id' => 5,
+ 'id' => 5,
+ 'label' => 'new_label_text',
+ 'file' => 'filename1',
+ 'position' => 10,
+ 'disabled' => false,
+ 'types' => ['image', 'small_image'],
+ ],
+ [
+ 'value_id' => 6, //will be deleted.
+ 'file' => 'filename2',
+ 'removed' => true,
+ ],
+ ];
+
+ $this->product->setData('media_gallery', $existingMediaGallery);
+ $this->product->expects($this->any())
+ ->method('getMediaAttributes')
+ ->willReturn(['image' => 'filename1', 'small_image' => 'filename2']);
+
+ $this->processor->expects($this->once())->method('clearMediaAttribute')
+ ->with($this->product, ['image', 'small_image']);
+ $this->processor->expects($this->once())
+ ->method('setMediaAttribute')
+ ->with($this->product, ['image', 'small_image'], 'filename1');
+ $this->model->processMediaGallery($this->product, $newEntries);
+ $this->assertEquals($expectedResult, $this->product->getMediaGallery('images'));
+ }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
index a220b9a5768fe..14c84f4781a3a 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
@@ -9,6 +9,7 @@
namespace Magento\Catalog\Test\Unit\Model;
+use Magento\Catalog\Model\ProductRepository\MediaGalleryProcessor;
use Magento\Framework\Api\Data\ImageContentInterface;
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
use Magento\Framework\DB\Adapter\ConnectionException;
@@ -139,7 +140,7 @@ class ProductRepositoryTest extends \PHPUnit\Framework\TestCase
protected $storeManagerMock;
/**
- * @var \Magento\Catalog\Model\Product\Gallery\Processor|\PHPUnit_Framework_MockObject_MockObject
+ * @var MediaGalleryProcessor|\PHPUnit_Framework_MockObject_MockObject
*/
protected $mediaGalleryProcessor;
@@ -234,7 +235,7 @@ protected function setUp()
$storeMock->expects($this->any())->method('getCode')->willReturn(\Magento\Store\Model\Store::ADMIN_CODE);
$this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock);
- $this->mediaGalleryProcessor = $this->createMock(\Magento\Catalog\Model\Product\Gallery\Processor::class);
+ $this->mediaGalleryProcessor = $this->createMock(MediaGalleryProcessor::class);
$this->collectionProcessorMock = $this->getMockBuilder(CollectionProcessorInterface::class)
->getMock();
@@ -1174,7 +1175,21 @@ public function testSaveExistingWithNewMediaGalleryEntries()
]
]
];
-
+ $expectedEntriesData = [
+ [
+ '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->setupProductMocksForSave();
//media gallery data
$this->productData['media_gallery_entries'] = [
@@ -1198,56 +1213,8 @@ public function testSaveExistingWithNewMediaGalleryEntries()
->will($this->returnValue($this->productData));
$this->initializedProductMock->setData('media_gallery', $newEntriesData);
- $this->initializedProductMock->expects($this->any())
- ->method('getMediaAttributes')
- ->willReturn(["image" => "imageAttribute", "small_image" => "small_image_attribute"]);
-
- //setup media attribute backend
- $mediaTmpPath = '/tmp';
- $absolutePath = '/a/b/filename.jpg';
-
- $this->mediaGalleryProcessor->expects($this->once())->method('clearMediaAttribute')
- ->with($this->initializedProductMock, ['image', 'small_image']);
-
- $mediaConfigMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Media\Config::class)
- ->disableOriginalConstructor()
- ->getMock();
- $mediaConfigMock->expects($this->once())
- ->method('getTmpMediaShortUrl')
- ->with($absolutePath)
- ->willReturn($mediaTmpPath . $absolutePath);
- $this->initializedProductMock->expects($this->once())
- ->method('getMediaConfig')
- ->willReturn($mediaConfigMock);
-
- //verify new entries
- $contentDataObject = $this->getMockBuilder(\Magento\Framework\Api\ImageContent::class)
- ->disableOriginalConstructor()
- ->setMethods(null)
- ->getMock();
- $this->contentFactoryMock->expects($this->once())
- ->method('create')
- ->willReturn($contentDataObject);
-
- $this->imageProcessorMock->expects($this->once())
- ->method('processImageContent')
- ->willReturn($absolutePath);
-
- $imageFileUri = "imageFileUri";
- $this->mediaGalleryProcessor->expects($this->once())->method('addImage')
- ->with($this->initializedProductMock, $mediaTmpPath . $absolutePath, ['image', 'small_image'], true, false)
- ->willReturn($imageFileUri);
- $this->mediaGalleryProcessor->expects($this->once())->method('updateImage')
- ->with(
- $this->initializedProductMock,
- $imageFileUri,
- [
- 'label' => 'label_text',
- 'position' => 10,
- 'disabled' => false,
- 'media_type' => 'media_type',
- ]
- );
+ $this->mediaGalleryProcessor->expects($this->once())->method('processMediaGallery')
+ ->with($this->initializedProductMock, $expectedEntriesData);
$this->initializedProductMock->expects($this->once())->method('getWebsiteIds')->willReturn([]);
$this->initializedProductMock->expects($this->atLeastOnce())
->method('getSku')->willReturn($this->productData['sku']);
@@ -1325,24 +1292,6 @@ public function testSaveExistingWithMediaGalleryEntries()
],
],
];
-
- $expectedResult = [
- [
- 'value_id' => 5,
- 'id' => 5,
- "label" => "new_label_text",
- 'file' => 'filename1',
- 'position' => 10,
- 'disabled' => false,
- 'types' => ['image', 'small_image'],
- ],
- [
- 'value_id' => 6, //will be deleted
- 'file' => 'filename2',
- 'removed' => true,
- ],
- ];
-
$this->setupProductMocksForSave();
//media gallery data
$this->productData['media_gallery_entries'] = $newEntries;
@@ -1352,21 +1301,15 @@ public function testSaveExistingWithMediaGalleryEntries()
->will($this->returnValue($this->productData));
$this->initializedProductMock->setData('media_gallery', $existingMediaGallery);
- $this->initializedProductMock->expects($this->any())
- ->method('getMediaAttributes')
- ->willReturn(["image" => "filename1", "small_image" => "filename2"]);
- $this->mediaGalleryProcessor->expects($this->once())->method('clearMediaAttribute')
- ->with($this->initializedProductMock, ['image', 'small_image']);
$this->mediaGalleryProcessor->expects($this->once())
- ->method('setMediaAttribute')
- ->with($this->initializedProductMock, ['image', 'small_image'], 'filename1');
+ ->method('processMediaGallery')
+ ->with($this->initializedProductMock, $newEntries);
$this->initializedProductMock->expects($this->once())->method('getWebsiteIds')->willReturn([]);
$this->initializedProductMock->expects($this->atLeastOnce())
->method('getSku')->willReturn($this->productData['sku']);
$this->productMock->expects($this->atLeastOnce())->method('getSku')->willReturn($this->productData['sku']);
$this->productMock->expects($this->any())->method('getMediaGalleryEntries')->willReturn(null);
$this->model->save($this->productMock);
- $this->assertEquals($expectedResult, $this->initializedProductMock->getMediaGallery('images'));
}
}
diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml
index 0a9f3c2d40dca..3197501e9b70b 100644
--- a/app/code/Magento/CatalogInventory/etc/events.xml
+++ b/app/code/Magento/CatalogInventory/etc/events.xml
@@ -27,9 +27,6 @@
-
-
-
diff --git a/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php b/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php
index dceb5767edae9..42d7d91fb90e8 100644
--- a/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php
+++ b/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php
@@ -45,7 +45,7 @@ public function __construct(
public function isAvailable(Item $item)
{
$buyRequest = $item->getBuyRequest();
- $superAttribute = $buyRequest->getData()['super_attribute'];
+ $superAttribute = $buyRequest->getData()['super_attribute'] ?? [];
$connection = $this->getConnection();
$select = $connection->select();
$orderItemParentId = $item->getParentItem()->getProductId();
diff --git a/app/code/Magento/GoogleAnalytics/view/frontend/web/js/google-analytics.js b/app/code/Magento/GoogleAnalytics/view/frontend/web/js/google-analytics.js
index 324881cdc5028..cd6292b39e989 100644
--- a/app/code/Magento/GoogleAnalytics/view/frontend/web/js/google-analytics.js
+++ b/app/code/Magento/GoogleAnalytics/view/frontend/web/js/google-analytics.js
@@ -51,10 +51,9 @@ define([
if (config.pageTrackingData.isAnonymizedIpActive) {
ga('set', 'anonymizeIp', true);
}
- ga('send', 'pageview' + config.pageTrackingData.optPageUrl);
// Process orders data
- if (config.ordersTrackingData) {
+ if (config.ordersTrackingData.length) {
ga('require', 'ec', 'ec.js');
//Set currency code
@@ -75,6 +74,9 @@ define([
}
ga('send', 'pageview');
+ }else{
+ // Process Data if not orders
+ ga('send', 'pageview' + config.pageTrackingData.optPageUrl);
}
}
}
diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php
index b8d7ccf83af7c..8f29798472f19 100644
--- a/app/code/Magento/Newsletter/Model/Subscriber.php
+++ b/app/code/Magento/Newsletter/Model/Subscriber.php
@@ -604,14 +604,20 @@ protected function _updateCustomerSubscription($customerId, $subscribe)
$this->save();
$sendSubscription = $sendInformationEmail;
- if ($sendSubscription === null xor $sendSubscription) {
+ if ($sendSubscription === null xor $sendSubscription && $this->isStatusChanged()) {
try {
- if ($isConfirmNeed) {
- $this->sendConfirmationRequestEmail();
- } elseif ($this->isStatusChanged() && $status == self::STATUS_UNSUBSCRIBED) {
- $this->sendUnsubscriptionEmail();
- } elseif ($this->isStatusChanged() && $status == self::STATUS_SUBSCRIBED) {
- $this->sendConfirmationSuccessEmail();
+ switch ($status) {
+ case self::STATUS_UNSUBSCRIBED:
+ $this->sendUnsubscriptionEmail();
+ break;
+ case self::STATUS_SUBSCRIBED:
+ $this->sendConfirmationSuccessEmail();
+ break;
+ case self::STATUS_NOT_ACTIVE:
+ if ($isConfirmNeed) {
+ $this->sendConfirmationRequestEmail();
+ }
+ break;
}
} catch (MailException $e) {
// If we are not able to send a new account email, this should be ignored
diff --git a/app/code/Magento/Quote/Model/Quote/Item.php b/app/code/Magento/Quote/Model/Quote/Item.php
index d8177ddfe5236..fe6d712500bcd 100644
--- a/app/code/Magento/Quote/Model/Quote/Item.php
+++ b/app/code/Magento/Quote/Model/Quote/Item.php
@@ -745,6 +745,9 @@ public function saveItemOptions()
unset($this->_options[$index]);
unset($this->_optionsByCode[$option->getCode()]);
} else {
+ if (!$option->getItem() || !$option->getItem()->getId()) {
+ $option->setItem($this);
+ }
$option->save();
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
index 09f6362c833d4..9dab97621f2f5 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
@@ -326,6 +326,32 @@ public function testCreateInvalidPriceFormat()
}
}
+ /**
+ * Test that Product Repository can correctly create simple product, if product type not specified in request.
+ *
+ * @return void
+ */
+ public function testCreateWithoutSpecifiedType()
+ {
+ $price = 3.62;
+ $weight = 12.2;
+ $sku = 'simple_product_without_specified_type';
+ $product = [
+ 'sku' => $sku,
+ 'name' => 'Simple Product Without Specified Type',
+ 'price' => $price,
+ 'weight' => $weight,
+ 'attribute_set_id' => 4,
+ ];
+ $response = $this->saveProduct($product);
+ $this->assertSame($sku, $response[ProductInterface::SKU]);
+ $this->assertSame(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, $response[ProductInterface::TYPE_ID]);
+ $this->assertSame($price, $response[ProductInterface::PRICE]);
+ $this->assertSame($weight, $response[ProductInterface::WEIGHT]);
+ //Clean up.
+ $this->deleteProduct($product[ProductInterface::SKU]);
+ }
+
/**
* @param array $fixtureProduct
*
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php
index 9518e9c0cdf4f..330487b757f61 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php
@@ -49,4 +49,25 @@ public function testUpdateProductSku()
$updatedProduct->load($productId);
self::assertSame($newSku, $updatedProduct->getSku());
}
+
+ /**
+ * Check Product Repository able to correctly create product without specified type.
+ *
+ * @magentoDbIsolation enabled
+ */
+ public function testCreateWithoutSpecifiedType()
+ {
+ /** @var Product $product */
+ $product = Bootstrap::getObjectManager()->get(ProductFactory::class)->create();
+ $product->setName('Simple without specified type');
+ $product->setSku('simple_without_specified_type');
+ $product->setPrice(1.12);
+ $product->setWeight(1.23);
+ $product->setAttributeSetId(4);
+ $product = $this->productRepository->save($product);
+
+ self::assertSame('1.1200', $product->getPrice());
+ self::assertSame('1.2300', $product->getWeight());
+ self::assertSame('simple', $product->getTypeId());
+ }
}