11<?php
22/**
3- *
43 * Copyright © Magento, Inc. All rights reserved.
54 * See COPYING.txt for license details.
65 */
76
87namespace Magento \Catalog \Model ;
98
9+ use Magento \Catalog \Api \CategoryLinkManagementInterface ;
1010use Magento \Catalog \Api \Data \ProductExtension ;
1111use Magento \Catalog \Api \Data \ProductInterface ;
1212use Magento \Catalog \Model \Product \Gallery \MimeTypeExtensionMap ;
13+ use Magento \Catalog \Model \ProductRepository \MediaGalleryProcessor ;
1314use Magento \Catalog \Model \ResourceModel \Product \Collection ;
1415use Magento \Eav \Model \Entity \Attribute \Exception as AttributeException ;
15- use Magento \Framework \Api \Data \ImageContentInterface ;
1616use Magento \Framework \Api \Data \ImageContentInterfaceFactory ;
1717use Magento \Framework \Api \ImageContentValidatorInterface ;
1818use Magento \Framework \Api \ImageProcessorInterface ;
2525use Magento \Framework \Exception \InputException ;
2626use Magento \Framework \Exception \LocalizedException ;
2727use Magento \Framework \Exception \NoSuchEntityException ;
28- use Magento \Framework \Exception \TemporaryState \CouldNotSaveException as TemporaryCouldNotSaveException ;
2928use Magento \Framework \Exception \StateException ;
29+ use Magento \Framework \Exception \TemporaryState \CouldNotSaveException as TemporaryCouldNotSaveException ;
3030use Magento \Framework \Exception \ValidatorException ;
3131
3232/**
@@ -122,11 +122,15 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
122122 protected $ fileSystem ;
123123
124124 /**
125+ * @deprecated
126+ *
125127 * @var ImageContentInterfaceFactory
126128 */
127129 protected $ contentFactory ;
128130
129131 /**
132+ * @deprecated
133+ *
130134 * @var ImageProcessorInterface
131135 */
132136 protected $ imageProcessor ;
@@ -137,10 +141,17 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
137141 protected $ extensionAttributesJoinProcessor ;
138142
139143 /**
144+ * @deprecated
145+ *
140146 * @var \Magento\Catalog\Model\Product\Gallery\Processor
141147 */
142148 protected $ mediaGalleryProcessor ;
143149
150+ /**
151+ * @var MediaGalleryProcessor
152+ */
153+ private $ mediaProcessor ;
154+
144155 /**
145156 * @var CollectionProcessorInterface
146157 */
@@ -161,6 +172,11 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
161172 */
162173 private $ readExtensions ;
163174
175+ /**
176+ * @var CategoryLinkManagementInterface
177+ */
178+ private $ linkManagement ;
179+
164180 /**
165181 * ProductRepository constructor.
166182 * @param ProductFactory $productFactory
@@ -186,7 +202,8 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
186202 * @param CollectionProcessorInterface $collectionProcessor [optional]
187203 * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
188204 * @param int $cacheLimit [optional]
189- * @param ReadExtensions|null $readExtensions
205+ * @param ReadExtensions $readExtensions
206+ * @param CategoryLinkManagementInterface $linkManagement
190207 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
191208 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
192209 */
@@ -214,7 +231,8 @@ public function __construct(
214231 CollectionProcessorInterface $ collectionProcessor = null ,
215232 \Magento \Framework \Serialize \Serializer \Json $ serializer = null ,
216233 $ cacheLimit = 1000 ,
217- ReadExtensions $ readExtensions = null
234+ ReadExtensions $ readExtensions = null ,
235+ CategoryLinkManagementInterface $ linkManagement = null
218236 ) {
219237 $ this ->productFactory = $ productFactory ;
220238 $ this ->collectionFactory = $ collectionFactory ;
@@ -239,6 +257,8 @@ public function __construct(
239257 $ this ->cacheLimit = (int )$ cacheLimit ;
240258 $ this ->readExtensions = $ readExtensions ?: \Magento \Framework \App \ObjectManager::getInstance ()
241259 ->get (ReadExtensions::class);
260+ $ this ->linkManagement = $ linkManagement ?: \Magento \Framework \App \ObjectManager::getInstance ()
261+ ->get (CategoryLinkManagementInterface::class);
242262 }
243263
244264 /**
@@ -381,6 +401,9 @@ private function assignProductToWebsites(\Magento\Catalog\Model\Product $product
381401 /**
382402 * Process new gallery media entry.
383403 *
404+ * @deprecated
405+ * @see MediaGalleryProcessor::processNewMediaGalleryEntry()
406+ *
384407 * @param ProductInterface $product
385408 * @param array $newEntry
386409 * @return $this
@@ -392,40 +415,8 @@ protected function processNewMediaGalleryEntry(
392415 ProductInterface $ product ,
393416 array $ newEntry
394417 ) {
395- /** @var ImageContentInterface $contentDataObject */
396- $ contentDataObject = $ newEntry ['content ' ];
418+ $ this ->getMediaGalleryProcessor ()->processNewMediaGalleryEntry ($ product , $ newEntry );
397419
398- /** @var \Magento\Catalog\Model\Product\Media\Config $mediaConfig */
399- $ mediaConfig = $ product ->getMediaConfig ();
400- $ mediaTmpPath = $ mediaConfig ->getBaseTmpMediaPath ();
401-
402- $ relativeFilePath = $ this ->imageProcessor ->processImageContent ($ mediaTmpPath , $ contentDataObject );
403- $ tmpFilePath = $ mediaConfig ->getTmpMediaShortUrl ($ relativeFilePath );
404-
405- if (!$ product ->hasGalleryAttribute ()) {
406- throw new StateException (
407- __ ("The product that was requested doesn't exist. Verify the product and try again. " )
408- );
409- }
410-
411- $ imageFileUri = $ this ->getMediaGalleryProcessor ()->addImage (
412- $ product ,
413- $ tmpFilePath ,
414- isset ($ newEntry ['types ' ]) ? $ newEntry ['types ' ] : [],
415- true ,
416- isset ($ newEntry ['disabled ' ]) ? $ newEntry ['disabled ' ] : true
417- );
418- // Update additional fields that are still empty after addImage call
419- $ this ->getMediaGalleryProcessor ()->updateImage (
420- $ product ,
421- $ imageFileUri ,
422- [
423- 'label ' => $ newEntry ['label ' ],
424- 'position ' => $ newEntry ['position ' ],
425- 'disabled ' => $ newEntry ['disabled ' ],
426- 'media_type ' => $ newEntry ['media_type ' ],
427- ]
428- );
429420 return $ this ;
430421 }
431422
@@ -500,68 +491,13 @@ private function processLinks(ProductInterface $product, $newLinks)
500491 * @return $this
501492 * @throws InputException
502493 * @throws StateException
494+ * @throws LocalizedException
503495 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
504496 */
505497 protected function processMediaGallery (ProductInterface $ product , $ mediaGalleryEntries )
506498 {
507- $ existingMediaGallery = $ product ->getMediaGallery ('images ' );
508- $ newEntries = [];
509- $ entriesById = [];
510- if (!empty ($ existingMediaGallery )) {
511- foreach ($ mediaGalleryEntries as $ entry ) {
512- if (isset ($ entry ['value_id ' ])) {
513- $ entriesById [$ entry ['value_id ' ]] = $ entry ;
514- } else {
515- $ newEntries [] = $ entry ;
516- }
517- }
518- foreach ($ existingMediaGallery as $ key => &$ existingEntry ) {
519- if (isset ($ entriesById [$ existingEntry ['value_id ' ]])) {
520- $ updatedEntry = $ entriesById [$ existingEntry ['value_id ' ]];
521- if ($ updatedEntry ['file ' ] === null ) {
522- unset($ updatedEntry ['file ' ]);
523- }
524- $ existingMediaGallery [$ key ] = array_merge ($ existingEntry , $ updatedEntry );
525- } else {
526- //set the removed flag
527- $ existingEntry ['removed ' ] = true ;
528- }
529- }
530- $ product ->setData ('media_gallery ' , ["images " => $ existingMediaGallery ]);
531- } else {
532- $ newEntries = $ mediaGalleryEntries ;
533- }
534-
535- $ images = (array )$ product ->getMediaGallery ('images ' );
536- $ images = $ this ->determineImageRoles ($ product , $ images );
537-
538- $ this ->getMediaGalleryProcessor ()->clearMediaAttribute ($ product , array_keys ($ product ->getMediaAttributes ()));
539-
540- foreach ($ images as $ image ) {
541- if (!isset ($ image ['removed ' ]) && !empty ($ image ['types ' ])) {
542- $ this ->getMediaGalleryProcessor ()->setMediaAttribute ($ product , $ image ['types ' ], $ image ['file ' ]);
543- }
544- }
499+ $ this ->getMediaGalleryProcessor ()->processMediaGallery ($ product , $ mediaGalleryEntries );
545500
546- foreach ($ newEntries as $ newEntry ) {
547- if (!isset ($ newEntry ['content ' ])) {
548- throw new InputException (__ ('The image content is invalid. Verify the content and try again. ' ));
549- }
550- /** @var ImageContentInterface $contentDataObject */
551- $ contentDataObject = $ this ->contentFactory ->create ()
552- ->setName ($ newEntry ['content ' ]['data ' ][ImageContentInterface::NAME ])
553- ->setBase64EncodedData ($ newEntry ['content ' ]['data ' ][ImageContentInterface::BASE64_ENCODED_DATA ])
554- ->setType ($ newEntry ['content ' ]['data ' ][ImageContentInterface::TYPE ]);
555- $ newEntry ['content ' ] = $ contentDataObject ;
556- $ this ->processNewMediaGalleryEntry ($ product , $ newEntry );
557-
558- $ finalGallery = $ product ->getData ('media_gallery ' );
559- $ newEntryId = key (array_diff_key ($ product ->getData ('media_gallery ' )['images ' ], $ entriesById ));
560- $ newEntry = array_replace_recursive ($ newEntry , $ finalGallery ['images ' ][$ newEntryId ]);
561- $ entriesById [$ newEntryId ] = $ newEntry ;
562- $ finalGallery ['images ' ][$ newEntryId ] = $ newEntry ;
563- $ product ->setData ('media_gallery ' , $ finalGallery );
564- }
565501 return $ this ;
566502 }
567503
@@ -572,6 +508,7 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
572508 */
573509 public function save (ProductInterface $ product , $ saveOptions = false )
574510 {
511+ $ assignToCategories = false ;
575512 $ tierPrices = $ product ->getData ('tier_price ' );
576513
577514 try {
@@ -589,6 +526,7 @@ public function save(ProductInterface $product, $saveOptions = false)
589526 $ extensionAttributes = $ product ->getExtensionAttributes ();
590527 if (empty ($ extensionAttributes ->__toArray ())) {
591528 $ product ->setExtensionAttributes ($ existingProduct ->getExtensionAttributes ());
529+ $ assignToCategories = true ;
592530 }
593531 } catch (NoSuchEntityException $ e ) {
594532 $ existingProduct = null ;
@@ -626,6 +564,12 @@ public function save(ProductInterface $product, $saveOptions = false)
626564 }
627565
628566 $ this ->saveProduct ($ product );
567+ if ($ assignToCategories === true && $ product ->getCategoryIds ()) {
568+ $ this ->linkManagement ->assignProductToCategories (
569+ $ product ->getSku (),
570+ $ product ->getCategoryIds ()
571+ );
572+ }
629573 $ this ->removeProductFromLocalCache ($ product ->getSku ());
630574 unset($ this ->instancesById [$ product ->getId ()]);
631575
@@ -763,44 +707,19 @@ public function cleanCache()
763707 $ this ->instancesById = null ;
764708 }
765709
766- /**
767- * Ascertain image roles, if they are not set against the gallery entries
768- *
769- * @param ProductInterface $product
770- * @param array $images
771- * @return array
772- */
773- private function determineImageRoles (ProductInterface $ product , array $ images ) : array
774- {
775- $ imagesWithRoles = [];
776- foreach ($ images as $ image ) {
777- if (!isset ($ image ['types ' ])) {
778- $ image ['types ' ] = [];
779- if (isset ($ image ['file ' ])) {
780- foreach (array_keys ($ product ->getMediaAttributes ()) as $ attribute ) {
781- if ($ image ['file ' ] == $ product ->getData ($ attribute )) {
782- $ image ['types ' ][] = $ attribute ;
783- }
784- }
785- }
786- }
787- $ imagesWithRoles [] = $ image ;
788- }
789- return $ imagesWithRoles ;
790- }
791-
792710 /**
793711 * Retrieve media gallery processor.
794712 *
795- * @return Product\Gallery\Processor
713+ * @return MediaGalleryProcessor
796714 */
797715 private function getMediaGalleryProcessor ()
798716 {
799- if (null === $ this ->mediaGalleryProcessor ) {
800- $ this ->mediaGalleryProcessor = \Magento \Framework \App \ObjectManager::getInstance ()
801- ->get (\ Magento \ Catalog \ Model \ Product \ Gallery \Processor ::class);
717+ if (null === $ this ->mediaProcessor ) {
718+ $ this ->mediaProcessor = \Magento \Framework \App \ObjectManager::getInstance ()
719+ ->get (MediaGalleryProcessor ::class);
802720 }
803- return $ this ->mediaGalleryProcessor ;
721+
722+ return $ this ->mediaProcessor ;
804723 }
805724
806725 /**
@@ -912,6 +831,7 @@ private function saveProduct($product): void
912831 throw new CouldNotSaveException (__ ($ e ->getMessage ()));
913832 } catch (LocalizedException $ e ) {
914833 throw $ e ;
834+ // phpcs:disable Magento2.Exceptions.ThrowCatch
915835 } catch (\Exception $ e ) {
916836 throw new CouldNotSaveException (
917837 __ ('The product was unable to be saved. Please try again. ' ),
0 commit comments