Skip to content

Commit f56188d

Browse files
Merge pull request #1215 from magento-tsg/2.1.8-develop-pr19
Fixed issues: - MAGETWO-57144: Unable to assign blank value to attribute #3545 #4910 #5485 - MAGETWO-57615: Visual Merchandiser: Match products by rule in admin not working - MAGETWO-58042: Elasticsearch fails with an error when used user-defined price attribute as searchable - MAGETWO-60538: [Magento Cloud] - Cache-miss when Fastly is enabled - MAGETWO-60542: "Print Shipping Label" link does not displays on frontend - MAGETWO-61135: Unable to add video to product via REST api - MAGETWO-62995: Product imports not Auto-Generating URL Keys for SKUs - MAGETWO-64240: Magento\Catalog\Test\TestCase\Product\AddCompareProductsTest.test with data set "AddCompareProductsTestVariation3" - MAGETWO-64242: Magento\Sales\Test\TestCase\MoveShoppingCartProductsOnOrderPageTest.test with data set "MoveShoppingCartProductsOnOrderPageTestVariation2"
2 parents 3016ddf + d16e9c8 commit f56188d

File tree

45 files changed

+2382
-288
lines changed

Some content is hidden

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

45 files changed

+2382
-288
lines changed

app/code/Magento/Catalog/Model/ProductRepository.php

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ protected function getCacheKey($data)
278278
*/
279279
protected function initializeProductData(array $productData, $createNew)
280280
{
281+
unset($productData['media_gallery']);
281282
if ($createNew) {
282283
$product = $this->productFactory->create();
283284
if ($this->storeManager->hasSingleStore()) {
@@ -420,8 +421,15 @@ private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $produc
420421
}
421422

422423
/**
423-
* @param ProductInterface $product
424-
* @param array $mediaGalleryEntries
424+
* Process Media gallery data before save product.
425+
*
426+
* Compare Media Gallery Entries Data with existing Media Gallery
427+
* * If Media entry has not value_id set it as new
428+
* * If Existing entry 'value_id' absent in Media Gallery set 'removed' flag
429+
* * Merge Existing and new media gallery
430+
*
431+
* @param ProductInterface $product contains only existing media gallery items
432+
* @param array $mediaGalleryEntries array which contains all media gallery items
425433
* @return $this
426434
* @throws InputException
427435
* @throws StateException
@@ -431,11 +439,10 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
431439
{
432440
$existingMediaGallery = $product->getMediaGallery('images');
433441
$newEntries = [];
442+
$entriesById = [];
434443
if (!empty($existingMediaGallery)) {
435-
$entriesById = [];
436444
foreach ($mediaGalleryEntries as $entry) {
437-
if (isset($entry['id'])) {
438-
$entry['value_id'] = $entry['id'];
445+
if (isset($entry['value_id'])) {
439446
$entriesById[$entry['value_id']] = $entry;
440447
} else {
441448
$newEntries[] = $entry;
@@ -444,6 +451,9 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
444451
foreach ($existingMediaGallery as $key => &$existingEntry) {
445452
if (isset($entriesById[$existingEntry['value_id']])) {
446453
$updatedEntry = $entriesById[$existingEntry['value_id']];
454+
if ($updatedEntry['file'] === null) {
455+
unset($updatedEntry['file']);
456+
}
447457
$existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
448458
} else {
449459
//set the removed flag
@@ -471,11 +481,18 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
471481
}
472482
/** @var ImageContentInterface $contentDataObject */
473483
$contentDataObject = $this->contentFactory->create()
474-
->setName($newEntry['content'][ImageContentInterface::NAME])
475-
->setBase64EncodedData($newEntry['content'][ImageContentInterface::BASE64_ENCODED_DATA])
476-
->setType($newEntry['content'][ImageContentInterface::TYPE]);
484+
->setName($newEntry['content']['data'][ImageContentInterface::NAME])
485+
->setBase64EncodedData($newEntry['content']['data'][ImageContentInterface::BASE64_ENCODED_DATA])
486+
->setType($newEntry['content']['data'][ImageContentInterface::TYPE]);
477487
$newEntry['content'] = $contentDataObject;
478488
$this->processNewMediaGalleryEntry($product, $newEntry);
489+
490+
$finalGallery = $product->getData('media_gallery');
491+
$newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById));
492+
$newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]);
493+
$entriesById[$newEntryId] = $newEntry;
494+
$finalGallery['images'][$newEntryId] = $newEntry;
495+
$product->setData('media_gallery', $finalGallery);
479496
}
480497
return $this;
481498
}
@@ -503,8 +520,6 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
503520
$productDataArray = $this->extensibleDataObjectConverter
504521
->toNestedArray($product, [], 'Magento\Catalog\Api\Data\ProductInterface');
505522
$productDataArray = array_replace($productDataArray, $product->getData());
506-
unset($productDataArray['media_gallery']);
507-
508523
$ignoreLinksFlag = $product->getData('ignore_links_flag');
509524
$productLinks = null;
510525
if (!$ignoreLinksFlag && $ignoreLinksFlag !== null) {
@@ -514,8 +529,8 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
514529
$product = $this->initializeProductData($productDataArray, empty($existingProduct));
515530

516531
$this->processLinks($product, $productLinks);
517-
if (isset($productDataArray['media_gallery_entries'])) {
518-
$this->processMediaGallery($product, $productDataArray['media_gallery_entries']);
532+
if (isset($productDataArray['media_gallery'])) {
533+
$this->processMediaGallery($product, $productDataArray['media_gallery']['images']);
519534
}
520535

521536
if (!$product->getOptionsReadonly()) {

app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php

Lines changed: 226 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,36 @@
55
*/
66
namespace Magento\Catalog\Test\Unit\Ui\DataProvider\Product\Form\Modifier;
77

8-
use Magento\Catalog\Model\Product\Type;
8+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
9+
use Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface;
10+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
11+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
12+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute;
13+
use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory as EavAttributeFactory;
914
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav;
15+
use Magento\Eav\Api\Data\AttributeGroupInterface;
1016
use Magento\Eav\Model\Config;
11-
use Magento\Framework\App\RequestInterface;
12-
use Magento\Store\Model\StoreManagerInterface;
13-
use Magento\Store\Api\Data\StoreInterface;
14-
use Magento\Ui\DataProvider\EavValidationRules;
15-
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\Collection as GroupCollection;
16-
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory as GroupCollectionFactory;
1717
use Magento\Eav\Model\Entity\Attribute\Group;
18-
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute;
1918
use Magento\Eav\Model\Entity\Type as EntityType;
2019
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection as AttributeCollection;
21-
use Magento\Ui\DataProvider\Mapper\FormElement as FormElementMapper;
22-
use Magento\Ui\DataProvider\Mapper\MetaProperties as MetaPropertiesMapper;
23-
use Magento\Framework\Api\SearchCriteriaBuilder;
24-
use Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface;
20+
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\Collection as GroupCollection;
21+
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory as GroupCollectionFactory;
22+
use Magento\Framework\Api\AttributeInterface;
2523
use Magento\Framework\Api\SearchCriteria;
26-
use Magento\Framework\Api\SortOrderBuilder;
27-
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
24+
use Magento\Framework\Api\SearchCriteriaBuilder;
2825
use Magento\Framework\Api\SearchResultsInterface;
29-
use Magento\Catalog\Api\Data\ProductAttributeInterface;
30-
use Magento\Eav\Api\Data\AttributeGroupInterface;
31-
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
26+
use Magento\Framework\Api\SortOrderBuilder;
27+
use Magento\Framework\App\RequestInterface;
3228
use Magento\Framework\Currency;
29+
use Magento\Framework\Event\ManagerInterface;
3330
use Magento\Framework\Locale\Currency as CurrencyLocale;
34-
Use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
31+
use Magento\Framework\Stdlib\ArrayManager;
32+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
33+
use Magento\Store\Api\Data\StoreInterface;
34+
use Magento\Store\Model\StoreManagerInterface;
35+
use Magento\Ui\DataProvider\EavValidationRules;
36+
use Magento\Ui\DataProvider\Mapper\FormElement as FormElementMapper;
37+
use Magento\Ui\DataProvider\Mapper\MetaProperties as MetaPropertiesMapper;
3538

3639
/**
3740
* Class EavTest
@@ -157,6 +160,26 @@ class EavTest extends AbstractModifierTest
157160
*/
158161
protected $currencyLocaleMock;
159162

163+
/**
164+
* @var ProductAttributeInterface|\PHPUnit_Framework_MockObject_MockObject
165+
*/
166+
private $productAttributeMock;
167+
168+
/**
169+
* @var ArrayManager|\PHPUnit_Framework_MockObject_MockObject
170+
*/
171+
protected $arrayManagerMock;
172+
173+
/**
174+
* @var EavAttributeFactory|\PHPUnit_Framework_MockObject_MockObject
175+
*/
176+
private $eavAttributeFactoryMock;
177+
178+
/**
179+
* @var ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
180+
*/
181+
private $eventManagerMock;
182+
160183
/**
161184
* @var ObjectManager
162185
*/
@@ -167,6 +190,9 @@ class EavTest extends AbstractModifierTest
167190
*/
168191
protected $eav;
169192

193+
/**
194+
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
195+
*/
170196
protected function setUp()
171197
{
172198
parent::setUp();
@@ -228,10 +254,24 @@ protected function setUp()
228254
$this->searchResultsMock = $this->getMockBuilder(SearchResultsInterface::class)
229255
->getMockForAbstractClass();
230256
$this->eavAttributeMock = $this->getMockBuilder(Attribute::class)
231-
->setMethods(['getAttributeGroupCode', 'getApplyTo', 'getFrontendInput', 'getAttributeCode'])
257+
->setMethods(['load', 'getAttributeGroupCode', 'getApplyTo', 'getFrontendInput', 'getAttributeCode'])
258+
->disableOriginalConstructor()
259+
->getMock();
260+
$this->productAttributeMock = $this->getMockBuilder(ProductAttributeInterface::class)
261+
->getMock();
262+
$this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class)
263+
->getMock();
264+
$this->eavAttributeFactoryMock = $this->getMockBuilder(EavAttributeFactory::class)
265+
->disableOriginalConstructor()
266+
->setMethods(['create'])
267+
->getMock();
268+
$this->eventManagerMock = $this->getMockBuilder(ManagerInterface::class)
232269
->disableOriginalConstructor()
233270
->getMock();
234271

272+
$this->eavAttributeFactoryMock->expects($this->any())
273+
->method('create')
274+
->willReturn($this->eavAttributeMock);
235275
$this->groupCollectionFactoryMock->expects($this->any())
236276
->method('create')
237277
->willReturn($this->groupCollectionMock);
@@ -277,7 +317,10 @@ protected function setUp()
277317
->disableOriginalConstructor()
278318
->setMethods(['getCurrency'])
279319
->getMock();
280-
320+
$this->eavAttributeMock->expects($this->any())
321+
->method('load')
322+
->willReturnSelf();
323+
281324
$this->eav =$this->getModel();
282325
$this->objectManager->setBackwardCompatibleProperty(
283326
$this->eav,
@@ -304,6 +347,9 @@ protected function createModel()
304347
'attributeGroupRepository' => $this->attributeGroupRepositoryMock,
305348
'sortOrderBuilder' => $this->sortOrderBuilderMock,
306349
'attributeRepository' => $this->attributeRepositoryMock,
350+
'arrayManager' => $this->arrayManagerMock,
351+
'eavAttributeFactory' => $this->eavAttributeFactoryMock,
352+
'_eventManager' => $this->eventManagerMock,
307353
]);
308354
}
309355

@@ -399,4 +445,164 @@ public function testModifyData()
399445

400446
$this->assertEquals($sourceData, $this->eav->modifyData([]));
401447
}
448+
449+
/**
450+
* @param int $productId
451+
* @param bool $productRequired
452+
* @param string $attrValue
453+
* @param array $expected
454+
* @covers \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav::isProductExists
455+
* @covers \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav::setupAttributeMeta
456+
* @dataProvider setupAttributeMetaDataProvider
457+
*/
458+
public function testSetupAttributeMetaDefaultAttribute($productId, $productRequired, $attrValue, $expected)
459+
{
460+
$configPath = 'arguments/data/config';
461+
$groupCode = 'product-details';
462+
$sortOrder = '0';
463+
464+
$this->productMock->expects($this->any())
465+
->method('getId')
466+
->willReturn($productId);
467+
468+
$this->productAttributeMock->expects($this->any())
469+
->method('getIsRequired')
470+
->willReturn($productRequired);
471+
472+
$this->productAttributeMock->expects($this->any())
473+
->method('getDefaultValue')
474+
->willReturn('required_value');
475+
476+
$this->productAttributeMock->expects($this->any())
477+
->method('getAttributeCode')
478+
->willReturn('code');
479+
480+
$this->productAttributeMock->expects($this->any())
481+
->method('getValue')
482+
->willReturn('value');
483+
484+
$attributeMock = $this->getMockBuilder(AttributeInterface::class)
485+
->disableOriginalConstructor()
486+
->getMock();
487+
488+
$attributeMock->expects($this->any())
489+
->method('getValue')
490+
->willReturn($attrValue);
491+
492+
$this->productMock->expects($this->any())
493+
->method('getCustomAttribute')
494+
->willReturn($attributeMock);
495+
496+
$this->arrayManagerMock->expects($this->any())
497+
->method('set')
498+
->with(
499+
$configPath,
500+
[],
501+
$expected
502+
)
503+
->willReturn($expected);
504+
505+
$this->arrayManagerMock->expects($this->any())
506+
->method('merge')
507+
->willReturn($expected);
508+
509+
$this->arrayManagerMock->expects($this->any())
510+
->method('get')
511+
->willReturn([]);
512+
513+
$this->arrayManagerMock->expects($this->any())
514+
->method('exists');
515+
516+
$this->assertEquals(
517+
$expected,
518+
$this->eav->setupAttributeMeta($this->productAttributeMock, $groupCode, $sortOrder)
519+
);
520+
}
521+
522+
/**
523+
* Setup attribute meta data provider.
524+
*
525+
* @return array
526+
*/
527+
public function setupAttributeMetaDataProvider()
528+
{
529+
return [
530+
'default_null_prod_not_new_and_required' => [
531+
'productId' => 1,
532+
'productRequired' => true,
533+
'attrValue' => 'val',
534+
'expected' => [
535+
'dataType' => null,
536+
'formElement' => null,
537+
'visible' => null,
538+
'required' => true,
539+
'notice' => null,
540+
'default' => null,
541+
'label' => null,
542+
'code' => 'code',
543+
'source' => 'product-details',
544+
'scopeLabel' => '',
545+
'globalScope' => false,
546+
'sortOrder' => 0,
547+
],
548+
],
549+
'default_null_prod_not_new_and_not_required' => [
550+
'productId' => 1,
551+
'productRequired' => false,
552+
'attrValue' => 'val',
553+
'expected' => [
554+
'dataType' => null,
555+
'formElement' => null,
556+
'visible' => null,
557+
'required' => false,
558+
'notice' => null,
559+
'default' => null,
560+
'label' => null,
561+
'code' => 'code',
562+
'source' => 'product-details',
563+
'scopeLabel' => '',
564+
'globalScope' => false,
565+
'sortOrder' => 0,
566+
],
567+
],
568+
'default_null_prod_new_and_not_required' => [
569+
'productId' => null,
570+
'productRequired' => false,
571+
'attrValue' => null,
572+
'expected' => [
573+
'dataType' => null,
574+
'formElement' => null,
575+
'visible' => null,
576+
'required' => false,
577+
'notice' => null,
578+
'default' => 'required_value',
579+
'label' => null,
580+
'code' => 'code',
581+
'source' => 'product-details',
582+
'scopeLabel' => '',
583+
'globalScope' => false,
584+
'sortOrder' => 0,
585+
],
586+
],
587+
'default_null_prod_new_and_required' => [
588+
'productId' => null,
589+
'productRequired' => false,
590+
'attrValue' => null,
591+
'expected' => [
592+
'dataType' => null,
593+
'formElement' => null,
594+
'visible' => null,
595+
'required' => false,
596+
'notice' => null,
597+
'default' => 'required_value',
598+
'label' => null,
599+
'code' => 'code',
600+
'source' => 'product-details',
601+
'scopeLabel' => '',
602+
'globalScope' => false,
603+
'sortOrder' => 0,
604+
],
605+
]
606+
];
607+
}
402608
}

0 commit comments

Comments
 (0)