Skip to content

Commit f3cd941

Browse files
committed
Merge remote-tracking branch 'origin/2.3-develop' into MC-36136
2 parents 267a03a + 65f2d7a commit f3cd941

File tree

49 files changed

+2149
-481
lines changed

Some content is hidden

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

49 files changed

+2149
-481
lines changed

app/code/Magento/Backend/Block/Widget/Grid/Extended.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use Magento\Framework\App\Filesystem\DirectoryList;
99

1010
/**
11+
* Extended Grid Widget
12+
*
1113
* @api
1214
* @deprecated 100.2.0 in favour of UI component implementation
1315
* @SuppressWarnings(PHPMD.ExcessivePublicCount)
@@ -177,7 +179,10 @@ class Extended extends \Magento\Backend\Block\Widget\Grid implements \Magento\Ba
177179
protected $_path = 'export';
178180

179181
/**
182+
* Initialization
183+
*
180184
* @return void
185+
* @throws \Magento\Framework\Exception\FileSystemException
181186
*/
182187
protected function _construct()
183188
{
@@ -297,6 +302,7 @@ public function addColumn($columnId, $column)
297302
);
298303
$this->getColumnSet()->getChildBlock($columnId)->setGrid($this);
299304
} else {
305+
// phpcs:ignore Magento2.Exceptions.DirectThrow
300306
throw new \Exception(__('Please correct the column format and try again.'));
301307
}
302308

@@ -471,10 +477,6 @@ protected function _prepareMassactionColumn()
471477
protected function _prepareCollection()
472478
{
473479
if ($this->getCollection()) {
474-
if ($this->getCollection()->isLoaded()) {
475-
$this->getCollection()->clear();
476-
}
477-
478480
parent::_prepareCollection();
479481

480482
if (!$this->_isExport) {
@@ -663,6 +665,7 @@ public function setEmptyCellLabel($label)
663665
*/
664666
public function getRowUrl($item)
665667
{
668+
// phpstan:ignore "Call to an undefined static method"
666669
$res = parent::getRowUrl($item);
667670
return $res ? $res : '#';
668671
}
@@ -680,6 +683,7 @@ public function getMultipleRows($item)
680683

681684
/**
682685
* Retrieve columns for multiple rows
686+
*
683687
* @return array
684688
*/
685689
public function getMultipleRowColumns()
@@ -943,6 +947,7 @@ protected function _getExportTotals()
943947

944948
/**
945949
* Iterate collection and call callback method per item
950+
*
946951
* For callback method first argument always is item object
947952
*
948953
* @param string $callback
@@ -972,7 +977,12 @@ public function _exportIterateCollection($callback, array $args)
972977
$page++;
973978

974979
foreach ($collection as $item) {
975-
call_user_func_array([$this, $callback], array_merge([$item], $args));
980+
//phpcs:ignore Magento2.Functions.DiscouragedFunction
981+
call_user_func_array(
982+
[$this, $callback],
983+
// phpcs:ignore Magento2.Performance.ForeachArrayMerge
984+
array_merge([$item], $args)
985+
);
976986
}
977987
}
978988
}
@@ -1009,6 +1019,7 @@ public function getCsvFile()
10091019
$this->_isExport = true;
10101020
$this->_prepareGrid();
10111021

1022+
// phpcs:ignore Magento2.Security.InsecureFunction
10121023
$name = md5(microtime());
10131024
$file = $this->_path . '/' . $name . '.csv';
10141025

@@ -1153,6 +1164,7 @@ public function getExcelFile($sheetName = '')
11531164
[$this, 'getRowRecord']
11541165
);
11551166

1167+
// phpcs:ignore Magento2.Security.InsecureFunction
11561168
$name = md5(microtime());
11571169
$file = $this->_path . '/' . $name . '.xml';
11581170

@@ -1244,7 +1256,7 @@ public function setCollection($collection)
12441256
}
12451257

12461258
/**
1247-
* get collection object
1259+
* Get collection object
12481260
*
12491261
* @return \Magento\Framework\Data\Collection
12501262
*/

app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/ExtendedTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public function testPrepareLoadedCollection()
3232
$layout->expects($this->any())->method('getBlock')->will($this->returnValue($columnSet));
3333

3434
$collection = $this->createMock(\Magento\Framework\Data\Collection::class);
35-
$collection->expects($this->atLeastOnce())->method('isLoaded')->will($this->returnValue(true));
36-
$collection->expects($this->atLeastOnce())->method('clear');
35+
$collection->expects($this->never())->method('isLoaded');
36+
$collection->expects($this->never())->method('clear');
3737
$collection->expects($this->atLeastOnce())->method('load');
3838

3939
/** @var \Magento\Backend\Block\Widget\Grid\Extended $block */

app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/checkbox.phtml

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,51 @@
88
<?php /* @var $block \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox */ ?>
99
<?php $_option = $block->getOption() ?>
1010
<?php $_selections = $_option->getSelections() ?>
11+
<?php $inputClass = 'checkbox product bundle option bundle-option-' . $block->escapeHtmlAttr($_option->getId()) ?>
12+
<?php $inputId = 'bundle-option-' . $block->escapeHtmlAttr($_option->getId()) ?>
13+
<?php $inputName = 'bundle_option[' . $block->escapeHtmlAttr($_option->getId()) . ']' ?>
14+
<?php $dataValidation = 'data-validate="{\'validate-one-required-by-name\':\'input[name^=&quot;bundle_option[' .
15+
$block->escapeHtmlAttr($_option->getId()) . ']&quot;]:checked\'}"' ?>
16+
1117
<div class="field option <?= ($_option->getRequired()) ? ' required': '' ?>">
1218
<label class="label">
1319
<span><?= $block->escapeHtml($_option->getTitle()) ?></span>
1420
</label>
1521
<div class="control">
1622
<div class="nested options-list">
17-
<?php if ($block->showSingle()) : ?>
23+
<?php if ($block->showSingle()): ?>
1824
<?= /* @noEscape */ $block->getSelectionQtyTitlePrice($_selections[0]) ?>
1925
<?= /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selections[0]) ?>
2026
<input type="hidden"
2127
class="bundle-option-<?= $block->escapeHtmlAttr($_option->getId()) ?> product bundle option"
2228
name="bundle_option[<?= $block->escapeHtml($_option->getId()) ?>]"
2329
value="<?= $block->escapeHtmlAttr($_selections[0]->getSelectionId()) ?>"/>
24-
<?php else :?>
25-
<?php foreach ($_selections as $_selection) : ?>
30+
<?php else:?>
31+
<?php foreach ($_selections as $selection): ?>
32+
<?php $sectionId = $selection->getSelectionId() ?>
2633
<div class="field choice">
27-
<input class="bundle-option-<?= $block->escapeHtmlAttr($_option->getId()) ?> checkbox product bundle option change-container-classname"
28-
id="bundle-option-<?= $block->escapeHtmlAttr($_option->getId()) ?>-<?= $block->escapeHtmlAttr($_selection->getSelectionId()) ?>"
34+
<input class="<?= /* @noEscape */ $inputClass ?> change-container-classname"
35+
id="<?= /* @noEscape */ $inputId . '-' . $block->escapeHtmlAttr($sectionId) ?>"
2936
type="checkbox"
30-
<?php if ($_option->getRequired()) { echo 'data-validate="{\'validate-one-required-by-name\':\'input[name^=&quot;bundle_option[' . $block->escapeHtmlAttr($_option->getId()) . ']&quot;]:checked\'}"'; } ?>
31-
name="bundle_option[<?= $block->escapeHtmlAttr($_option->getId()) ?>][<?= $block->escapeHtmlAttr($_selection->getId()) ?>]"
32-
data-selector="bundle_option[<?= $block->escapeHtmlAttr($_option->getId()) ?>][<?= $block->escapeHtmlAttr($_selection->getId()) ?>]"
33-
<?php if ($block->isSelected($_selection)) { echo ' checked="checked"'; } ?>
34-
<?php if (!$_selection->isSaleable()) { echo ' disabled="disabled"'; } ?>
35-
value="<?= $block->escapeHtmlAttr($_selection->getSelectionId()) ?>"/>
37+
<?php if ($_option->getRequired()): ?>
38+
<?= /* @noEscape */ $dataValidation ?>
39+
<?php endif; ?>
40+
name="<?= /* @noEscape */ $inputName . '[' . $block->escapeHtmlAttr($sectionId) ?>]"
41+
data-selector="<?= /* @noEscape */ $inputName.'['.$block->escapeHtmlAttr($sectionId)?>]"
42+
<?php if ($block->isSelected($selection)) { echo ' checked="checked"'; } ?>
43+
<?php if (!$selection->isSaleable()) { echo ' disabled="disabled"'; } ?>
44+
value="<?= $block->escapeHtmlAttr($selection->getSelectionId()) ?>"
45+
data-errors-message-box="#validation-message-box"/>
3646
<label class="label"
37-
for="bundle-option-<?= $block->escapeHtmlAttr($_option->getId()) ?>-<?= $block->escapeHtmlAttr($_selection->getSelectionId()) ?>">
38-
<span><?= /* @noEscape */ $block->getSelectionQtyTitlePrice($_selection) ?></span>
47+
for="<?=/* @noEscape */ $inputId . '-' . $block->escapeHtmlAttr($sectionId) ?>">
48+
<span><?= /* @noEscape */ $block->getSelectionQtyTitlePrice($selection) ?></span>
3949
<br/>
40-
<?= /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selection) ?>
50+
<?= /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($selection) ?>
4151
</label>
4252
</div>
4353
<?php endforeach; ?>
4454
<div id="bundle-option-<?= $block->escapeHtmlAttr($_option->getId()) ?>-container"></div>
55+
<div id="validation-message-box"></div>
4556
<?php endif; ?>
4657
</div>
4758
</div>

app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php

Lines changed: 94 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
namespace Magento\Catalog\Model\Product\Gallery;
99

1010
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Catalog\Model\Product;
1112
use Magento\Framework\App\Filesystem\DirectoryList;
1213
use Magento\Framework\App\ObjectManager;
1314
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
1415
use Magento\MediaStorage\Model\File\Uploader as FileUploader;
16+
use Magento\Store\Model\Store;
1517
use Magento\Store\Model\StoreManagerInterface;
1618

1719
/**
@@ -89,6 +91,15 @@ class CreateHandler implements ExtensionInterface
8991
*/
9092
private $storeManager;
9193

94+
/**
95+
* @var string[]
96+
*/
97+
private $mediaAttributesWithLabels = [
98+
'image',
99+
'small_image',
100+
'thumbnail'
101+
];
102+
92103
/**
93104
* @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
94105
* @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
@@ -190,27 +201,8 @@ public function execute($product, $arguments = [])
190201
$value['duplicate'] = $duplicate;
191202
}
192203

193-
/* @var $mediaAttribute \Magento\Catalog\Api\Data\ProductAttributeInterface */
194-
foreach ($this->getMediaAttributeCodes() as $mediaAttrCode) {
195-
$attrData = $product->getData($mediaAttrCode);
196-
if (empty($attrData) && empty($clearImages) && empty($newImages) && empty($existImages)) {
197-
continue;
198-
}
199-
$this->processMediaAttribute(
200-
$product,
201-
$mediaAttrCode,
202-
$clearImages,
203-
$newImages
204-
);
205-
if (in_array($mediaAttrCode, ['image', 'small_image', 'thumbnail'])) {
206-
$this->processMediaAttributeLabel(
207-
$product,
208-
$mediaAttrCode,
209-
$clearImages,
210-
$newImages,
211-
$existImages
212-
);
213-
}
204+
if (!empty($value['images'])) {
205+
$this->processMediaAttributes($product, $existImages, $newImages, $clearImages);
214206
}
215207

216208
$product->setData($attrCode, $value);
@@ -492,50 +484,59 @@ private function getMediaAttributeCodes()
492484
/**
493485
* Process media attribute
494486
*
495-
* @param \Magento\Catalog\Model\Product $product
487+
* @param Product $product
496488
* @param string $mediaAttrCode
497489
* @param array $clearImages
498490
* @param array $newImages
499491
*/
500492
private function processMediaAttribute(
501-
\Magento\Catalog\Model\Product $product,
502-
$mediaAttrCode,
493+
Product $product,
494+
string $mediaAttrCode,
503495
array $clearImages,
504496
array $newImages
505-
) {
506-
$attrData = $product->getData($mediaAttrCode);
507-
if (in_array($attrData, $clearImages)) {
508-
$product->setData($mediaAttrCode, 'no_selection');
509-
}
510-
511-
if (in_array($attrData, array_keys($newImages))) {
512-
$product->setData($mediaAttrCode, $newImages[$attrData]['new_file']);
513-
}
514-
if (!empty($product->getData($mediaAttrCode))) {
497+
): void {
498+
$storeId = $product->isObjectNew() ? Store::DEFAULT_STORE_ID : (int) $product->getStoreId();
499+
/***
500+
* Attributes values are saved as default value in single store mode
501+
* @see \Magento\Catalog\Model\ResourceModel\AbstractResource::_saveAttributeValue
502+
*/
503+
if ($storeId === Store::DEFAULT_STORE_ID
504+
|| $this->storeManager->hasSingleStore()
505+
|| $this->getMediaAttributeStoreValue($product, $mediaAttrCode, $storeId) !== null
506+
) {
507+
$value = $product->getData($mediaAttrCode);
508+
$newValue = $value;
509+
if (in_array($value, $clearImages)) {
510+
$newValue = 'no_selection';
511+
}
512+
if (in_array($value, array_keys($newImages))) {
513+
$newValue = $newImages[$value]['new_file'];
514+
}
515+
$product->setData($mediaAttrCode, $newValue);
515516
$product->addAttributeUpdate(
516517
$mediaAttrCode,
517-
$product->getData($mediaAttrCode),
518-
$product->getStoreId()
518+
$newValue,
519+
$storeId
519520
);
520521
}
521522
}
522523

523524
/**
524525
* Process media attribute label
525526
*
526-
* @param \Magento\Catalog\Model\Product $product
527+
* @param Product $product
527528
* @param string $mediaAttrCode
528529
* @param array $clearImages
529530
* @param array $newImages
530531
* @param array $existImages
531532
*/
532533
private function processMediaAttributeLabel(
533-
\Magento\Catalog\Model\Product $product,
534-
$mediaAttrCode,
534+
Product $product,
535+
string $mediaAttrCode,
535536
array $clearImages,
536537
array $newImages,
537538
array $existImages
538-
) {
539+
): void {
539540
$resetLabel = false;
540541
$attrData = $product->getData($mediaAttrCode);
541542
if (in_array($attrData, $clearImages)) {
@@ -607,4 +608,57 @@ private function canRemoveImage(ProductInterface $product, string $imageFile) :b
607608

608609
return $canRemoveImage;
609610
}
611+
612+
/**
613+
* Get media attribute value for store view
614+
*
615+
* @param Product $product
616+
* @param string $attributeCode
617+
* @param int|null $storeId
618+
* @return string|null
619+
*/
620+
private function getMediaAttributeStoreValue(Product $product, string $attributeCode, int $storeId = null): ?string
621+
{
622+
$gallery = $this->getImagesForAllStores($product);
623+
$storeId = $storeId === null ? (int) $product->getStoreId() : $storeId;
624+
foreach ($gallery as $image) {
625+
if ($image['attribute_code'] === $attributeCode && ((int)$image['store_id']) === $storeId) {
626+
return $image['filepath'];
627+
}
628+
}
629+
return null;
630+
}
631+
632+
/**
633+
* Update media attributes
634+
*
635+
* @param Product $product
636+
* @param array $existImages
637+
* @param array $newImages
638+
* @param array $clearImages
639+
*/
640+
private function processMediaAttributes(
641+
Product $product,
642+
array $existImages,
643+
array $newImages,
644+
array $clearImages
645+
): void {
646+
foreach ($this->getMediaAttributeCodes() as $mediaAttrCode) {
647+
$this->processMediaAttribute(
648+
$product,
649+
$mediaAttrCode,
650+
$clearImages,
651+
$newImages
652+
);
653+
if (in_array($mediaAttrCode, $this->mediaAttributesWithLabels)) {
654+
$this->processMediaAttributeLabel(
655+
$product,
656+
$mediaAttrCode,
657+
$clearImages,
658+
$newImages,
659+
$existImages
660+
);
661+
}
662+
}
663+
}
610664
}

0 commit comments

Comments
 (0)