@@ -108,40 +108,161 @@ public function __construct(
108108 public function saveMediaGallery (array $ mediaGalleryData )
109109 {
110110 $ this ->initMediaGalleryResources ();
111- $ mediaGalleryDataGlobal = array_replace_recursive (...$ mediaGalleryData );
112- $ imageNames = [];
113- $ multiInsertData = [];
114- $ valueToProductId = [];
115- foreach ($ mediaGalleryDataGlobal as $ productSku => $ mediaGalleryRows ) {
116- $ productId = $ this ->skuProcessor ->getNewSku ($ productSku )[$ this ->getProductEntityLinkField ()];
117- $ insertedGalleryImgs = [];
118- foreach ($ mediaGalleryRows as $ insertValue ) {
119- if (!in_array ($ insertValue ['value ' ], $ insertedGalleryImgs )) {
120- $ valueArr = [
121- 'attribute_id ' => $ insertValue ['attribute_id ' ],
122- 'value ' => $ insertValue ['value ' ],
111+ $ mediaGalleryValues = [];
112+ $ mediaGalleryValueData = [];
113+ $ productMediaGalleryValueData = [];
114+ $ mediaGalleryValueToEntityData = [];
115+ $ mediaGalleryValueToStoreData = [];
116+ $ productLinkIdField = $ this ->getProductEntityLinkField ();
117+ foreach ($ mediaGalleryData as $ storeId => $ storeMediaGalleryData ) {
118+ foreach ($ storeMediaGalleryData as $ sku => $ productMediaGalleryData ) {
119+ $ productId = $ this ->skuProcessor ->getNewSku ($ sku )[$ productLinkIdField ];
120+ $ productMediaGalleryValueData [$ productId ] = $ productMediaGalleryValueData [$ productId ] ?? [];
121+ foreach ($ productMediaGalleryData as $ data ) {
122+ if (!in_array ($ data ['value ' ], $ productMediaGalleryValueData [$ productId ])) {
123+ $ productMediaGalleryValueData [$ productId ][] = $ data ['value ' ];
124+ $ mediaGalleryValueData [] = [
125+ 'attribute_id ' => $ data ['attribute_id ' ],
126+ 'value ' => $ data ['value ' ],
127+ ];
128+ $ mediaGalleryValueToEntityData [] = [
129+ 'value ' => $ data ['value ' ],
130+ $ productLinkIdField => $ productId ,
131+ ];
132+ }
133+ $ mediaGalleryValues [] = $ data ['value ' ];
134+ $ mediaGalleryValueToStoreData [] = [
135+ 'value ' => $ data ['value ' ],
136+ 'store_id ' => $ storeId ,
137+ $ productLinkIdField => $ productId ,
138+ 'label ' => $ data ['label ' ],
139+ 'position ' => $ data ['position ' ],
140+ 'disabled ' => $ data ['disabled ' ],
123141 ];
124- $ valueToProductId [$ insertValue ['value ' ]][] = $ productId ;
125- $ imageNames [] = $ insertValue ['value ' ];
126- $ multiInsertData [] = $ valueArr ;
127- $ insertedGalleryImgs [] = $ insertValue ['value ' ];
128142 }
129143 }
130144 }
131- $ oldMediaValues = $ this ->connection ->fetchAssoc (
132- $ this ->connection ->select ()->from ($ this ->mediaGalleryTableName , ['value_id ' , 'value ' ])
133- ->where ('value IN (?) ' , $ imageNames )
134- );
135- $ this ->connection ->insertOnDuplicate ($ this ->mediaGalleryTableName , $ multiInsertData );
136- $ newMediaSelect = $ this ->connection ->select ()->from ($ this ->mediaGalleryTableName , ['value_id ' , 'value ' ])
137- ->where ('value IN (?) ' , $ imageNames );
138- if (array_keys ($ oldMediaValues )) {
139- $ newMediaSelect ->where ('value_id NOT IN (?) ' , array_keys ($ oldMediaValues ));
145+ try {
146+ $ mediaValueIdValueMap = [];
147+ $ oldMediaValues = $ this ->connection ->fetchCol (
148+ $ this ->connection ->select ()
149+ ->from ($ this ->mediaGalleryTableName , ['value_id ' ])
150+ ->where ('value IN (?) ' , $ mediaGalleryValues )
151+ );
152+ $ this ->connection ->insertOnDuplicate (
153+ $ this ->mediaGalleryTableName ,
154+ $ mediaGalleryValueData
155+ );
156+ $ newMediaSelect = $ this ->connection ->select ()
157+ ->from ($ this ->mediaGalleryTableName , ['value_id ' , 'value ' ])
158+ ->where ('value IN (?) ' , $ mediaGalleryValues );
159+ if ($ oldMediaValues ) {
160+ $ newMediaSelect ->where ('value_id NOT IN (?) ' , $ oldMediaValues );
161+ }
162+ $ mediaValueIdValueMap = $ this ->connection ->fetchPairs ($ newMediaSelect );
163+ $ productIdMediaValueIdMap = $ this ->getProductIdMediaValueIdMap (
164+ $ productMediaGalleryValueData ,
165+ $ mediaValueIdValueMap
166+ );
167+ $ mediaGalleryValueToEntityData = $ this ->prepareMediaGalleryValueToEntityData (
168+ $ mediaGalleryValueToEntityData ,
169+ $ productIdMediaValueIdMap
170+ );
171+ $ this ->connection ->insertOnDuplicate (
172+ $ this ->mediaGalleryEntityToValueTableName ,
173+ $ mediaGalleryValueToEntityData ,
174+ ['value_id ' ]
175+ );
176+ $ mediaGalleryValueToStoreData = $ this ->prepareMediaGalleryValueData (
177+ $ mediaGalleryValueToStoreData ,
178+ $ productIdMediaValueIdMap
179+ );
180+ $ this ->connection ->insertOnDuplicate (
181+ $ this ->mediaGalleryValueTableName ,
182+ $ mediaGalleryValueToStoreData ,
183+ ['value_id ' , 'store_id ' , $ productLinkIdField , 'label ' , 'position ' , 'disabled ' ]
184+ );
185+ } catch (\Throwable $ exception ) {
186+ if ($ mediaValueIdValueMap ) {
187+ $ this ->connection ->delete (
188+ $ this ->mediaGalleryTableName ,
189+ $ this ->connection ->quoteInto ('value_id IN (?) ' , array_keys ($ mediaValueIdValueMap ))
190+ );
191+ }
192+ throw $ exception ;
140193 }
141- $ newMediaValues = $ this ->connection ->fetchAssoc ($ newMediaSelect );
142- foreach ($ mediaGalleryData as $ storeId => $ storeMediaGalleryData ) {
143- $ this ->processMediaPerStore ((int )$ storeId , $ storeMediaGalleryData , $ newMediaValues , $ valueToProductId );
194+ }
195+
196+ /**
197+ * Get media values IDs per products IDs
198+ *
199+ * @param array $productMediaGalleryValueData
200+ * @param array $mediaValueIdValueMap
201+ * @return array
202+ */
203+ private function getProductIdMediaValueIdMap (
204+ array $ productMediaGalleryValueData ,
205+ array $ mediaValueIdValueMap
206+ ): array {
207+ $ productIdMediaValueIdMap = [];
208+ foreach ($ productMediaGalleryValueData as $ productId => $ productMediaGalleryValues ) {
209+ foreach ($ productMediaGalleryValues as $ productMediaGalleryValue ) {
210+ foreach ($ mediaValueIdValueMap as $ valueId => $ value ) {
211+ if ($ productMediaGalleryValue === $ value ) {
212+ $ productIdMediaValueIdMap [$ productId ][$ value ] = $ valueId ;
213+ unset($ mediaValueIdValueMap [$ valueId ]);
214+ break ;
215+ }
216+ }
217+ }
218+ }
219+ return $ productIdMediaValueIdMap ;
220+ }
221+
222+ /**
223+ * Prepare media entity gallery value to entity data for insert
224+ *
225+ * @param array $mediaGalleryValueToEntityData
226+ * @param array $productIdMediaValueIdMap
227+ * @return array
228+ */
229+ private function prepareMediaGalleryValueToEntityData (
230+ array $ mediaGalleryValueToEntityData ,
231+ array $ productIdMediaValueIdMap
232+ ): array {
233+ $ productLinkIdField = $ this ->getProductEntityLinkField ();
234+ foreach ($ mediaGalleryValueToEntityData as $ index => $ data ) {
235+ $ productId = $ data [$ productLinkIdField ];
236+ $ value = $ data ['value ' ];
237+ $ mediaGalleryValueToEntityData [$ index ]['value_id ' ] = $ productIdMediaValueIdMap [$ productId ][$ value ];
238+ unset($ mediaGalleryValueToEntityData [$ index ]['value ' ]);
239+ }
240+ return $ mediaGalleryValueToEntityData ;
241+ }
242+
243+ /**
244+ * Prepare media entity gallery value data for insert
245+ *
246+ * @param array $mediaGalleryValueData
247+ * @param array $productIdMediaValueIdMap
248+ * @return array
249+ */
250+ private function prepareMediaGalleryValueData (
251+ array $ mediaGalleryValueData ,
252+ array $ productIdMediaValueIdMap
253+ ): array {
254+ $ productLinkIdField = $ this ->getProductEntityLinkField ();
255+ $ lastPositions = $ this ->getLastMediaPositionPerProduct (array_keys ($ productIdMediaValueIdMap ));
256+ foreach ($ mediaGalleryValueData as $ index => $ data ) {
257+ $ productId = $ data [$ productLinkIdField ];
258+ $ value = $ data ['value ' ];
259+ $ position = $ data ['position ' ];
260+ $ storeId = $ data ['store_id ' ];
261+ $ mediaGalleryValueData [$ index ]['value_id ' ] = $ productIdMediaValueIdMap [$ productId ][$ value ];
262+ $ mediaGalleryValueData [$ index ]['position ' ] = $ position + ($ lastPositions [$ storeId ][$ productId ] ?? 0 );
263+ unset($ mediaGalleryValueData [$ index ]['value ' ]);
144264 }
265+ return $ mediaGalleryValueData ;
145266 }
146267
147268 /**
@@ -289,13 +410,12 @@ private function initMediaGalleryResources()
289410 }
290411
291412 /**
292- * Get the last media position for each product from the given list
413+ * Get the last media position for each product per store from the given list
293414 *
294- * @param int $storeId
295415 * @param array $productIds
296416 * @return array
297417 */
298- private function getLastMediaPositionPerProduct (int $ storeId , array $ productIds ): array
418+ private function getLastMediaPositionPerProduct (array $ productIds ): array
299419 {
300420 $ result = [];
301421 if ($ productIds ) {
@@ -305,95 +425,25 @@ private function getLastMediaPositionPerProduct(int $storeId, array $productIds)
305425 $ positions = $ this ->connection ->fetchAll (
306426 $ this ->connection
307427 ->select ()
308- ->from ($ this ->mediaGalleryValueTableName , [$ productKeyName , 'position ' ])
428+ ->from ($ this ->mediaGalleryValueTableName , [$ productKeyName , 'store_id ' , ' position ' ])
309429 ->where ("$ productKeyName IN (?) " , $ productIds )
310- ->where ('value_id is not null ' )
311- ->where ('store_id = ? ' , $ storeId )
312430 );
313- // Make sure the result contains all product ids even if the product has no media files
314- $ result = array_fill_keys ($ productIds , 0 );
315431 // Find the largest position for each product
316432 foreach ($ positions as $ record ) {
317433 $ productId = $ record [$ productKeyName ];
318- $ result [$ productId ] = $ result [$ productId ] < $ record ['position ' ]
434+ $ storeId = $ record ['store_id ' ];
435+ if (!isset ($ result [$ storeId ][$ productId ])) {
436+ $ result [$ storeId ][$ productId ] = 0 ;
437+ }
438+ $ result [$ storeId ][$ productId ] = $ result [$ storeId ][$ productId ] < $ record ['position ' ]
319439 ? $ record ['position ' ]
320- : $ result [$ productId ];
440+ : $ result [$ storeId ][ $ productId ];
321441 }
322442 }
323443
324444 return $ result ;
325445 }
326446
327- /**
328- * Save media gallery data per store.
329- *
330- * @param int $storeId
331- * @param array $mediaGalleryData
332- * @param array $newMediaValues
333- * @param array $valueToProductId
334- * @return void
335- */
336- private function processMediaPerStore (
337- int $ storeId ,
338- array $ mediaGalleryData ,
339- array $ newMediaValues ,
340- array $ valueToProductId
341- ) {
342- $ multiInsertData = [];
343- $ dataForSkinnyTable = [];
344- $ lastMediaPositionPerProduct = $ this ->getLastMediaPositionPerProduct (
345- $ storeId ,
346- array_unique (array_merge (...array_values ($ valueToProductId )))
347- );
348-
349- foreach ($ mediaGalleryData as $ mediaGalleryRows ) {
350- foreach ($ mediaGalleryRows as $ insertValue ) {
351- foreach ($ newMediaValues as $ valueId => $ values ) {
352- if ($ values ['value ' ] == $ insertValue ['value ' ]) {
353- $ insertValue ['value_id ' ] = $ valueId ;
354- $ insertValue [$ this ->getProductEntityLinkField ()]
355- = array_shift ($ valueToProductId [$ values ['value ' ]]);
356- unset($ newMediaValues [$ valueId ]);
357- break ;
358- }
359- }
360- if (isset ($ insertValue ['value_id ' ])) {
361- $ productId = $ insertValue [$ this ->getProductEntityLinkField ()];
362- $ valueArr = [
363- 'value_id ' => $ insertValue ['value_id ' ],
364- 'store_id ' => $ storeId ,
365- $ this ->getProductEntityLinkField () => $ productId ,
366- 'label ' => $ insertValue ['label ' ],
367- 'position ' => $ lastMediaPositionPerProduct [$ productId ] + $ insertValue ['position ' ],
368- 'disabled ' => $ insertValue ['disabled ' ],
369- ];
370- $ multiInsertData [] = $ valueArr ;
371- $ dataForSkinnyTable [] = [
372- 'value_id ' => $ insertValue ['value_id ' ],
373- $ this ->getProductEntityLinkField () => $ insertValue [$ this ->getProductEntityLinkField ()],
374- ];
375- }
376- }
377- }
378- try {
379- $ this ->connection ->insertOnDuplicate (
380- $ this ->mediaGalleryValueTableName ,
381- $ multiInsertData ,
382- ['value_id ' , 'store_id ' , $ this ->getProductEntityLinkField (), 'label ' , 'position ' , 'disabled ' ]
383- );
384- $ this ->connection ->insertOnDuplicate (
385- $ this ->mediaGalleryEntityToValueTableName ,
386- $ dataForSkinnyTable ,
387- ['value_id ' ]
388- );
389- } catch (\Exception $ e ) {
390- $ this ->connection ->delete (
391- $ this ->mediaGalleryTableName ,
392- $ this ->connection ->quoteInto ('value_id IN (?) ' , $ newMediaValues )
393- );
394- }
395- }
396-
397447 /**
398448 * Get product entity link field.
399449 *
0 commit comments