Skip to content

Commit c9166c7

Browse files
committed
Merge branch 'ACP2E-2672' of https://github.com/magento-l3/magento2ce into PR-01-26-2024
2 parents 095906c + 792bc7e commit c9166c7

File tree

2 files changed

+244
-58
lines changed

2 files changed

+244
-58
lines changed

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

Lines changed: 163 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
use Magento\Catalog\Model\Product;
1313
use Magento\Catalog\Model\Product\Media\Config;
1414
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
15+
use Magento\Catalog\Model\ResourceModel\Product\MediaGalleryValue;
16+
use Magento\Eav\Model\ResourceModel\AttributeValue;
1517
use Magento\Framework\App\Filesystem\DirectoryList;
1618
use Magento\Framework\App\ObjectManager;
1719
use Magento\Framework\EntityManager\MetadataPool;
@@ -30,6 +32,8 @@
3032
* @api
3133
*
3234
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
35+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
36+
* @SuppressWarnings(PHPMD.TooManyFields)
3337
* @since 101.0.0
3438
*/
3539
class CreateHandler implements ExtensionInterface
@@ -90,7 +94,7 @@ class CreateHandler implements ExtensionInterface
9094
/**
9195
* @var array
9296
*/
93-
private $imagesGallery;
97+
private $mediaEavCache;
9498

9599
/**
96100
* @var \Magento\Store\Model\StoreManagerInterface
@@ -102,6 +106,21 @@ class CreateHandler implements ExtensionInterface
102106
*/
103107
private $deleteValidator;
104108

109+
/**
110+
* @var MediaGalleryValue
111+
*/
112+
private $mediaGalleryValue;
113+
114+
/**
115+
* @var AttributeValue
116+
*/
117+
private $attributeValue;
118+
119+
/**
120+
* @var \Magento\Eav\Model\Config
121+
*/
122+
private $eavConfig;
123+
105124
/**
106125
* @var string[]
107126
*/
@@ -121,7 +140,11 @@ class CreateHandler implements ExtensionInterface
121140
* @param Database $fileStorageDb
122141
* @param StoreManagerInterface|null $storeManager
123142
* @param DeleteValidator|null $deleteValidator
143+
* @param MediaGalleryValue|null $mediaGalleryValue
144+
* @param AttributeValue|null $attributeValue
145+
* @param \Magento\Eav\Model\Config|null $config
124146
* @throws FileSystemException
147+
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
125148
*/
126149
public function __construct(
127150
MetadataPool $metadataPool,
@@ -132,7 +155,10 @@ public function __construct(
132155
Filesystem $filesystem,
133156
Database $fileStorageDb,
134157
StoreManagerInterface $storeManager = null,
135-
?DeleteValidator $deleteValidator = null
158+
?DeleteValidator $deleteValidator = null,
159+
?MediaGalleryValue $mediaGalleryValue = null,
160+
?AttributeValue $attributeValue = null,
161+
?\Magento\Eav\Model\Config $config = null
136162
) {
137163
$this->metadata = $metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
138164
$this->attributeRepository = $attributeRepository;
@@ -143,6 +169,9 @@ public function __construct(
143169
$this->fileStorageDb = $fileStorageDb;
144170
$this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class);
145171
$this->deleteValidator = $deleteValidator ?: ObjectManager::getInstance()->get(DeleteValidator::class);
172+
$this->mediaGalleryValue = $mediaGalleryValue ?? ObjectManager::getInstance()->get(MediaGalleryValue::class);
173+
$this->attributeValue = $attributeValue ?? ObjectManager::getInstance()->get(AttributeValue::class);
174+
$this->eavConfig = $config ?? ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class);
146175
}
147176

148177
/**
@@ -159,6 +188,7 @@ public function __construct(
159188
*/
160189
public function execute($product, $arguments = [])
161190
{
191+
$this->mediaEavCache = null;
162192
$attrCode = $this->getAttribute()->getAttributeCode();
163193

164194
$value = $product->getData($attrCode);
@@ -279,14 +309,15 @@ protected function processDeletedImages($product, array &$images)
279309
*/
280310
protected function processNewAndExistingImages($product, array &$images)
281311
{
312+
$existingGalleryStoreValues = $this->getExistingGalleryStoreValues($product);
282313
foreach ($images as &$image) {
283314
if (empty($image['removed'])) {
284315
$isNew = empty($image['value_id']);
285316
$data = $this->processNewImage($product, $image);
286317

287318
// Add per store labels, position, disabled
288-
$data['value_id'] = $image['value_id'];
289-
$data['label'] = isset($image['label']) ? $image['label'] : '';
319+
$data['value_id'] = (int) $image['value_id'];
320+
$data['label'] = !empty($image['label']) ? $image['label'] : null;
290321
$data['position'] = isset($image['position']) && $image['position'] !== ''
291322
? (int)$image['position']
292323
: null;
@@ -295,34 +326,78 @@ protected function processNewAndExistingImages($product, array &$images)
295326

296327
$data[$this->metadata->getLinkField()] = (int)$product->getData($this->metadata->getLinkField());
297328

298-
$this->saveGalleryStoreValue($product, $data);
299-
if ($isNew && $data['store_id'] !== Store::DEFAULT_STORE_ID) {
300-
$dataForDefaultScope = $data;
301-
$dataForDefaultScope['store_id'] = Store::DEFAULT_STORE_ID;
302-
$dataForDefaultScope['disabled'] = 0;
303-
$dataForDefaultScope['label'] = null;
304-
$this->saveGalleryStoreValue($product, $dataForDefaultScope);
329+
if (!$isNew) {
330+
$data += (array) $this->getExistingGalleryStoreValue(
331+
$existingGalleryStoreValues,
332+
$data['value_id'],
333+
$data['store_id']
334+
);
305335
}
336+
337+
$this->saveGalleryStoreValue($data, $isNew);
306338
}
307339
}
308340
}
309341

310342
/**
311-
* Save media gallery store value
343+
* Returns existing gallery store value by value id and store id
344+
*
345+
* @param array $existingGalleryStoreValues
346+
* @param int $valueId
347+
* @param int $storeId
348+
* @return array|null
349+
*/
350+
private function getExistingGalleryStoreValue(array $existingGalleryStoreValues, int $valueId, int $storeId): ?array
351+
{
352+
foreach ($existingGalleryStoreValues as $existingGalleryStoreValue) {
353+
if (((int) $existingGalleryStoreValue['value_id']) === $valueId
354+
&& ((int) $existingGalleryStoreValue['store_id']) === $storeId
355+
) {
356+
return $existingGalleryStoreValue;
357+
}
358+
}
359+
360+
return null;
361+
}
362+
363+
/**
364+
* Get existing gallery store values
312365
*
313366
* @param Product $product
314-
* @param array $data
367+
* @return array
368+
* @throws \Exception
315369
*/
316-
private function saveGalleryStoreValue(Product $product, array $data): void
370+
private function getExistingGalleryStoreValues(Product $product): array
317371
{
372+
$existingMediaGalleryValues = [];
318373
if (!$product->isObjectNew()) {
319-
$this->resourceModel->deleteGalleryValueInStore(
320-
$data['value_id'],
321-
$data[$this->metadata->getLinkField()],
322-
$data['store_id']
323-
);
374+
$productId = (int)$product->getData($this->metadata->getLinkField());
375+
$existingMediaGalleryValues = $this->mediaGalleryValue->getAllByEntityId($productId);
376+
}
377+
return $existingMediaGalleryValues;
378+
}
379+
380+
/**
381+
* Save media gallery store value
382+
*
383+
* @param array $data
384+
* @param bool $isNewImage
385+
*/
386+
private function saveGalleryStoreValue(array $data, bool $isNewImage): void
387+
{
388+
$items = [];
389+
$items[] = $data;
390+
if ($isNewImage && $data['store_id'] !== Store::DEFAULT_STORE_ID) {
391+
$dataForDefaultScope = $data;
392+
$dataForDefaultScope['store_id'] = Store::DEFAULT_STORE_ID;
393+
$dataForDefaultScope['disabled'] = 0;
394+
$dataForDefaultScope['label'] = null;
395+
$items[] = $dataForDefaultScope;
396+
}
397+
398+
foreach ($items as $item) {
399+
$this->mediaGalleryValue->saveGalleryStoreValue($item);
324400
}
325-
$this->resourceModel->insertGalleryValueInStore($data);
326401
}
327402

328403
/**
@@ -530,29 +605,26 @@ private function processMediaAttribute(
530605
array $clearImages,
531606
array $newImages
532607
): void {
533-
$storeId = $product->isObjectNew() ? Store::DEFAULT_STORE_ID : (int) $product->getStoreId();
534-
/***
535-
* Attributes values are saved as default value in single store mode
536-
* @see \Magento\Catalog\Model\ResourceModel\AbstractResource::_saveAttributeValue
537-
*/
538-
if ($storeId === Store::DEFAULT_STORE_ID
539-
|| $this->storeManager->hasSingleStore()
540-
|| $this->getMediaAttributeStoreValue($product, $mediaAttrCode, $storeId) !== null
541-
) {
542-
$value = $product->getData($mediaAttrCode);
608+
$storeId = $this->getStoreIdForUpdate($product);
609+
$oldValue = $this->getMediaAttributeStoreValue($product, $mediaAttrCode, $storeId);
610+
// Prevent from breaking store inheritance
611+
if ($oldValue !== false || $storeId === Store::DEFAULT_STORE_ID) {
612+
$value = $product->hasData($mediaAttrCode) ? $product->getData($mediaAttrCode) : $oldValue;
543613
$newValue = $value;
544614
if (in_array($value, $clearImages)) {
545615
$newValue = 'no_selection';
546616
}
547617
if (in_array($value, array_keys($newImages))) {
548618
$newValue = $newImages[$value]['new_file'];
549619
}
550-
$product->setData($mediaAttrCode, $newValue);
551-
$product->addAttributeUpdate(
552-
$mediaAttrCode,
553-
$newValue,
554-
$storeId
555-
);
620+
if ($oldValue !== $newValue) {
621+
$product->setData($mediaAttrCode, $newValue);
622+
$product->addAttributeUpdate(
623+
$mediaAttrCode,
624+
$newValue,
625+
$storeId
626+
);
627+
}
556628
}
557629
}
558630

@@ -565,6 +637,7 @@ private function processMediaAttribute(
565637
* @param array $newImages
566638
* @param array $existImages
567639
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
640+
* @SuppressWarnings(PHPMD.NPathComplexity)
568641
*/
569642
private function processMediaAttributeLabel(
570643
Product $product,
@@ -573,6 +646,9 @@ private function processMediaAttributeLabel(
573646
array $newImages,
574647
array $existImages
575648
): void {
649+
$storeId = $this->getStoreIdForUpdate($product);
650+
$oldAttrLabelValue = $this->getMediaAttributeStoreValue($product, $mediaAttrCode . '_label', $storeId);
651+
576652
$resetLabel = false;
577653
$attrData = $product->getData($mediaAttrCode);
578654
if (in_array($attrData, $clearImages)) {
@@ -595,33 +671,58 @@ private function processMediaAttributeLabel(
595671
$product->setData($mediaAttrCode . '_label', null);
596672
$resetLabel = true;
597673
}
598-
if (!empty($product->getData($mediaAttrCode . '_label'))
599-
|| $resetLabel === true
600-
) {
674+
675+
$newAttrLabelValue = $product->getData($mediaAttrCode . '_label');
676+
677+
if ($newAttrLabelValue !== $oldAttrLabelValue && ($resetLabel || !empty($newAttrLabelValue))) {
601678
$product->addAttributeUpdate(
602679
$mediaAttrCode . '_label',
603-
$product->getData($mediaAttrCode . '_label'),
604-
$product->getStoreId()
680+
$newAttrLabelValue,
681+
$storeId
605682
);
606683
}
607684
}
608685

609686
/**
610-
* Get product images for all stores
687+
* Get store id to update media attribute
611688
*
612-
* @param ProductInterface $product
613-
* @return array
689+
* Attributes values are saved in "all store views" in single store mode
690+
*
691+
* @param Product $product
692+
* @return int
693+
* @see \Magento\Catalog\Model\ResourceModel\AbstractResource::_saveAttributeValue
614694
*/
615-
private function getImagesForAllStores(ProductInterface $product)
695+
private function getStoreIdForUpdate(Product $product): int
616696
{
617-
if ($this->imagesGallery === null) {
618-
$storeIds = array_keys($this->storeManager->getStores());
619-
$storeIds[] = 0;
697+
return $product->isObjectNew() || $this->storeManager->hasSingleStore()
698+
? Store::DEFAULT_STORE_ID
699+
: (int) $product->getStoreId();
700+
}
620701

621-
$this->imagesGallery = $this->resourceModel->getProductImages($product, $storeIds);
702+
/**
703+
* Get all media attributes values
704+
*
705+
* @param Product $product
706+
* @return array
707+
*/
708+
private function getMediaAttributesValues(Product $product): array
709+
{
710+
if ($this->mediaEavCache === null) {
711+
$attributeCodes = [];
712+
foreach ($this->mediaConfig->getMediaAttributeCodes() as $attributeCode) {
713+
$attributeCodes[] = $attributeCode;
714+
if (in_array($attributeCode, $this->mediaAttributesWithLabels)) {
715+
$attributeCodes[] = $attributeCode . '_label';
716+
}
717+
}
718+
$this->mediaEavCache = $this->attributeValue->getValues(
719+
ProductInterface::class,
720+
(int) $product->getData($this->metadata->getLinkField()),
721+
$attributeCodes
722+
);
622723
}
623724

624-
return $this->imagesGallery;
725+
return $this->mediaEavCache;
625726
}
626727

627728
/**
@@ -630,18 +731,22 @@ private function getImagesForAllStores(ProductInterface $product)
630731
* @param Product $product
631732
* @param string $attributeCode
632733
* @param int|null $storeId
633-
* @return string|null
734+
* @return mixed|false
634735
*/
635-
private function getMediaAttributeStoreValue(Product $product, string $attributeCode, int $storeId = null): ?string
636-
{
637-
$gallery = $this->getImagesForAllStores($product);
736+
private function getMediaAttributeStoreValue(
737+
Product $product,
738+
string $attributeCode,
739+
int $storeId = null
740+
): mixed {
741+
$attributes = $this->eavConfig->getEntityAttributes(Product::ENTITY);
742+
$attributeId = $attributes[$attributeCode]->getAttributeId();
638743
$storeId = $storeId === null ? (int) $product->getStoreId() : $storeId;
639-
foreach ($gallery as $image) {
640-
if ($image['attribute_code'] === $attributeCode && ((int)$image['store_id']) === $storeId) {
641-
return $image['filepath'];
744+
foreach ($this->getMediaAttributesValues($product) as $value) {
745+
if ($value['attribute_id'] === $attributeId && ((int)$value['store_id']) === $storeId) {
746+
return $value['value'];
642747
}
643748
}
644-
return null;
749+
return false;
645750
}
646751

647752
/**

0 commit comments

Comments
 (0)