12
12
use Magento \Catalog \Model \Product ;
13
13
use Magento \Catalog \Model \Product \Media \Config ;
14
14
use Magento \Catalog \Model \ResourceModel \Product \Gallery ;
15
+ use Magento \Catalog \Model \ResourceModel \Product \MediaGalleryValue ;
16
+ use Magento \Eav \Model \ResourceModel \AttributeValue ;
15
17
use Magento \Framework \App \Filesystem \DirectoryList ;
16
18
use Magento \Framework \App \ObjectManager ;
17
19
use Magento \Framework \EntityManager \MetadataPool ;
30
32
* @api
31
33
*
32
34
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
35
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
36
+ * @SuppressWarnings(PHPMD.TooManyFields)
33
37
* @since 101.0.0
34
38
*/
35
39
class CreateHandler implements ExtensionInterface
@@ -90,7 +94,7 @@ class CreateHandler implements ExtensionInterface
90
94
/**
91
95
* @var array
92
96
*/
93
- private $ imagesGallery ;
97
+ private $ mediaEavCache ;
94
98
95
99
/**
96
100
* @var \Magento\Store\Model\StoreManagerInterface
@@ -102,6 +106,21 @@ class CreateHandler implements ExtensionInterface
102
106
*/
103
107
private $ deleteValidator ;
104
108
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
+
105
124
/**
106
125
* @var string[]
107
126
*/
@@ -121,7 +140,11 @@ class CreateHandler implements ExtensionInterface
121
140
* @param Database $fileStorageDb
122
141
* @param StoreManagerInterface|null $storeManager
123
142
* @param DeleteValidator|null $deleteValidator
143
+ * @param MediaGalleryValue|null $mediaGalleryValue
144
+ * @param AttributeValue|null $attributeValue
145
+ * @param \Magento\Eav\Model\Config|null $config
124
146
* @throws FileSystemException
147
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
125
148
*/
126
149
public function __construct (
127
150
MetadataPool $ metadataPool ,
@@ -132,7 +155,10 @@ public function __construct(
132
155
Filesystem $ filesystem ,
133
156
Database $ fileStorageDb ,
134
157
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
136
162
) {
137
163
$ this ->metadata = $ metadataPool ->getMetadata (\Magento \Catalog \Api \Data \ProductInterface::class);
138
164
$ this ->attributeRepository = $ attributeRepository ;
@@ -143,6 +169,9 @@ public function __construct(
143
169
$ this ->fileStorageDb = $ fileStorageDb ;
144
170
$ this ->storeManager = $ storeManager ?: ObjectManager::getInstance ()->get (StoreManagerInterface::class);
145
171
$ 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);
146
175
}
147
176
148
177
/**
@@ -159,6 +188,7 @@ public function __construct(
159
188
*/
160
189
public function execute ($ product , $ arguments = [])
161
190
{
191
+ $ this ->mediaEavCache = null ;
162
192
$ attrCode = $ this ->getAttribute ()->getAttributeCode ();
163
193
164
194
$ value = $ product ->getData ($ attrCode );
@@ -279,14 +309,15 @@ protected function processDeletedImages($product, array &$images)
279
309
*/
280
310
protected function processNewAndExistingImages ($ product , array &$ images )
281
311
{
312
+ $ existingGalleryStoreValues = $ this ->getExistingGalleryStoreValues ($ product );
282
313
foreach ($ images as &$ image ) {
283
314
if (empty ($ image ['removed ' ])) {
284
315
$ isNew = empty ($ image ['value_id ' ]);
285
316
$ data = $ this ->processNewImage ($ product , $ image );
286
317
287
318
// 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 ;
290
321
$ data ['position ' ] = isset ($ image ['position ' ]) && $ image ['position ' ] !== ''
291
322
? (int )$ image ['position ' ]
292
323
: null ;
@@ -295,34 +326,78 @@ protected function processNewAndExistingImages($product, array &$images)
295
326
296
327
$ data [$ this ->metadata ->getLinkField ()] = (int )$ product ->getData ($ this ->metadata ->getLinkField ());
297
328
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
+ );
305
335
}
336
+
337
+ $ this ->saveGalleryStoreValue ($ data , $ isNew );
306
338
}
307
339
}
308
340
}
309
341
310
342
/**
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
312
365
*
313
366
* @param Product $product
314
- * @param array $data
367
+ * @return array
368
+ * @throws \Exception
315
369
*/
316
- private function saveGalleryStoreValue (Product $ product, array $ data ): void
370
+ private function getExistingGalleryStoreValues (Product $ product ): array
317
371
{
372
+ $ existingMediaGalleryValues = [];
318
373
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 );
324
400
}
325
- $ this ->resourceModel ->insertGalleryValueInStore ($ data );
326
401
}
327
402
328
403
/**
@@ -530,29 +605,26 @@ private function processMediaAttribute(
530
605
array $ clearImages ,
531
606
array $ newImages
532
607
): 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 ;
543
613
$ newValue = $ value ;
544
614
if (in_array ($ value , $ clearImages )) {
545
615
$ newValue = 'no_selection ' ;
546
616
}
547
617
if (in_array ($ value , array_keys ($ newImages ))) {
548
618
$ newValue = $ newImages [$ value ]['new_file ' ];
549
619
}
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
+ }
556
628
}
557
629
}
558
630
@@ -565,6 +637,7 @@ private function processMediaAttribute(
565
637
* @param array $newImages
566
638
* @param array $existImages
567
639
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
640
+ * @SuppressWarnings(PHPMD.NPathComplexity)
568
641
*/
569
642
private function processMediaAttributeLabel (
570
643
Product $ product ,
@@ -573,6 +646,9 @@ private function processMediaAttributeLabel(
573
646
array $ newImages ,
574
647
array $ existImages
575
648
): void {
649
+ $ storeId = $ this ->getStoreIdForUpdate ($ product );
650
+ $ oldAttrLabelValue = $ this ->getMediaAttributeStoreValue ($ product , $ mediaAttrCode . '_label ' , $ storeId );
651
+
576
652
$ resetLabel = false ;
577
653
$ attrData = $ product ->getData ($ mediaAttrCode );
578
654
if (in_array ($ attrData , $ clearImages )) {
@@ -595,33 +671,58 @@ private function processMediaAttributeLabel(
595
671
$ product ->setData ($ mediaAttrCode . '_label ' , null );
596
672
$ resetLabel = true ;
597
673
}
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 ))) {
601
678
$ product ->addAttributeUpdate (
602
679
$ mediaAttrCode . '_label ' ,
603
- $ product -> getData ( $ mediaAttrCode . ' _label ' ) ,
604
- $ product -> getStoreId ()
680
+ $ newAttrLabelValue ,
681
+ $ storeId
605
682
);
606
683
}
607
684
}
608
685
609
686
/**
610
- * Get product images for all stores
687
+ * Get store id to update media attribute
611
688
*
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
614
694
*/
615
- private function getImagesForAllStores ( ProductInterface $ product )
695
+ private function getStoreIdForUpdate ( Product $ product ): int
616
696
{
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
+ }
620
701
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
+ );
622
723
}
623
724
624
- return $ this ->imagesGallery ;
725
+ return $ this ->mediaEavCache ;
625
726
}
626
727
627
728
/**
@@ -630,18 +731,22 @@ private function getImagesForAllStores(ProductInterface $product)
630
731
* @param Product $product
631
732
* @param string $attributeCode
632
733
* @param int|null $storeId
633
- * @return string|null
734
+ * @return mixed|false
634
735
*/
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 ();
638
743
$ 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 ' ];
642
747
}
643
748
}
644
- return null ;
749
+ return false ;
645
750
}
646
751
647
752
/**
0 commit comments