44 * Copyright © Magento, Inc. All rights reserved.
55 * See COPYING.txt for license details.
66 */
7+ declare (strict_types=1 );
78
89namespace Magento \Catalog \Model ;
910
11+ use Magento \Catalog \Api \Data \ProductExtension ;
1012use Magento \Catalog \Api \Data \ProductInterface ;
1113use Magento \Catalog \Model \Product \Gallery \MimeTypeExtensionMap ;
1214use Magento \Catalog \Model \ResourceModel \Product \Collection ;
15+ use Magento \Eav \Model \Entity \Attribute \Exception as AttributeException ;
1316use Magento \Framework \Api \Data \ImageContentInterface ;
1417use Magento \Framework \Api \Data \ImageContentInterfaceFactory ;
1518use Magento \Framework \Api \ImageContentValidatorInterface ;
2225use Magento \Framework \Exception \InputException ;
2326use Magento \Framework \Exception \LocalizedException ;
2427use Magento \Framework \Exception \NoSuchEntityException ;
28+ use Magento \Framework \Exception \TemporaryState \CouldNotSaveException as TemporaryCouldNotSaveException ;
2529use Magento \Framework \Exception \StateException ;
2630use Magento \Framework \Exception \ValidatorException ;
2731
@@ -306,10 +310,10 @@ protected function getCacheKey($data)
306310 * Add product to internal cache and truncate cache if it has more than cacheLimit elements.
307311 *
308312 * @param string $cacheKey
309- * @param \Magento\Catalog\Api\Data\ ProductInterface $product
313+ * @param ProductInterface $product
310314 * @return void
311315 */
312- private function cacheProduct ($ cacheKey , \ Magento \ Catalog \ Api \ Data \ ProductInterface $ product )
316+ private function cacheProduct ($ cacheKey , ProductInterface $ product )
313317 {
314318 $ this ->instancesById [$ product ->getId ()][$ cacheKey ] = $ product ;
315319 $ this ->saveProductInLocalCache ($ product , $ cacheKey );
@@ -326,7 +330,7 @@ private function cacheProduct($cacheKey, \Magento\Catalog\Api\Data\ProductInterf
326330 *
327331 * @param array $productData
328332 * @param bool $createNew
329- * @return \Magento\Catalog\Api\Data\ ProductInterface|Product
333+ * @return ProductInterface|Product
330334 * @throws NoSuchEntityException
331335 */
332336 protected function initializeProductData (array $ productData , $ createNew )
@@ -414,12 +418,12 @@ protected function processNewMediaGalleryEntry(
414418 /**
415419 * Process product links, creating new links, updating and deleting existing links
416420 *
417- * @param \Magento\Catalog\Api\Data\ ProductInterface $product
421+ * @param ProductInterface $product
418422 * @param \Magento\Catalog\Api\Data\ProductLinkInterface[] $newLinks
419423 * @return $this
420424 * @throws NoSuchEntityException
421425 */
422- private function processLinks (\ Magento \ Catalog \ Api \ Data \ ProductInterface $ product , $ newLinks )
426+ private function processLinks (ProductInterface $ product , $ newLinks )
423427 {
424428 if ($ newLinks === null ) {
425429 // If product links were not specified, don't do anything
@@ -547,11 +551,11 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
547551 }
548552
549553 /**
550- * { @inheritdoc}
554+ * @inheritdoc
551555 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
552556 * @SuppressWarnings(PHPMD.NPathComplexity)
553557 */
554- public function save (\ Magento \ Catalog \ Api \ Data \ ProductInterface $ product , $ saveOptions = false )
558+ public function save (ProductInterface $ product , $ saveOptions = false )
555559 {
556560 $ tierPrices = $ product ->getData ('tier_price ' );
557561
@@ -565,12 +569,18 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
565569 if (!$ product ->hasData (Product::STATUS )) {
566570 $ product ->setStatus ($ existingProduct ->getStatus ());
567571 }
572+
573+ /** @var ProductExtension $extensionAttributes */
574+ $ extensionAttributes = $ product ->getExtensionAttributes ();
575+ if (empty ($ extensionAttributes ->__toArray ())) {
576+ $ product ->setExtensionAttributes ($ existingProduct ->getExtensionAttributes ());
577+ }
568578 } catch (NoSuchEntityException $ e ) {
569579 $ existingProduct = null ;
570580 }
571581
572582 $ productDataArray = $ this ->extensibleDataObjectConverter
573- ->toNestedArray ($ product , [], \ Magento \ Catalog \ Api \ Data \ ProductInterface::class);
583+ ->toNestedArray ($ product , [], ProductInterface::class);
574584 $ productDataArray = array_replace ($ productDataArray , $ product ->getData ());
575585 $ ignoreLinksFlag = $ product ->getData ('ignore_links_flag ' );
576586 $ productLinks = null ;
@@ -596,47 +606,11 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
596606 );
597607 }
598608
599- try {
600- if ($ tierPrices !== null ) {
601- $ product ->setData ('tier_price ' , $ tierPrices );
602- }
603- $ this ->removeProductFromLocalCache ($ product ->getSku ());
604- unset($ this ->instancesById [$ product ->getId ()]);
605- $ this ->resourceModel ->save ($ product );
606- } catch (ConnectionException $ exception ) {
607- throw new \Magento \Framework \Exception \TemporaryState \CouldNotSaveException (
608- __ ('Database connection error ' ),
609- $ exception ,
610- $ exception ->getCode ()
611- );
612- } catch (DeadlockException $ exception ) {
613- throw new \Magento \Framework \Exception \TemporaryState \CouldNotSaveException (
614- __ ('Database deadlock found when trying to get lock ' ),
615- $ exception ,
616- $ exception ->getCode ()
617- );
618- } catch (LockWaitException $ exception ) {
619- throw new \Magento \Framework \Exception \TemporaryState \CouldNotSaveException (
620- __ ('Database lock wait timeout exceeded ' ),
621- $ exception ,
622- $ exception ->getCode ()
623- );
624- } catch (\Magento \Eav \Model \Entity \Attribute \Exception $ exception ) {
625- throw \Magento \Framework \Exception \InputException::invalidFieldValue (
626- $ exception ->getAttributeCode (),
627- $ product ->getData ($ exception ->getAttributeCode ()),
628- $ exception
629- );
630- } catch (ValidatorException $ e ) {
631- throw new CouldNotSaveException (__ ($ e ->getMessage ()));
632- } catch (LocalizedException $ e ) {
633- throw $ e ;
634- } catch (\Exception $ e ) {
635- throw new \Magento \Framework \Exception \CouldNotSaveException (
636- __ ('The product was unable to be saved. Please try again. ' ),
637- $ e
638- );
609+ if ($ tierPrices !== null ) {
610+ $ product ->setData ('tier_price ' , $ tierPrices );
639611 }
612+
613+ $ this ->saveProduct ($ product );
640614 $ this ->removeProductFromLocalCache ($ product ->getSku ());
641615 unset($ this ->instancesById [$ product ->getId ()]);
642616
@@ -646,7 +620,7 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
646620 /**
647621 * {@inheritdoc}
648622 */
649- public function delete (\ Magento \ Catalog \ Api \ Data \ ProductInterface $ product )
623+ public function delete (ProductInterface $ product )
650624 {
651625 $ sku = $ product ->getSku ();
652626 $ productId = $ product ->getId ();
@@ -835,4 +809,55 @@ private function prepareSku(string $sku): string
835809 {
836810 return mb_strtolower (trim ($ sku ));
837811 }
812+
813+ /**
814+ * Save product resource model.
815+ *
816+ * @param ProductInterface|Product $product
817+ * @throws TemporaryCouldNotSaveException
818+ * @throws InputException
819+ * @throws CouldNotSaveException
820+ * @throws LocalizedException
821+ */
822+ private function saveProduct ($ product ): void
823+ {
824+ try {
825+ $ this ->removeProductFromLocalCache ($ product ->getSku ());
826+ unset($ this ->instancesById [$ product ->getId ()]);
827+ $ this ->resourceModel ->save ($ product );
828+ } catch (ConnectionException $ exception ) {
829+ throw new TemporaryCouldNotSaveException (
830+ __ ('Database connection error ' ),
831+ $ exception ,
832+ $ exception ->getCode ()
833+ );
834+ } catch (DeadlockException $ exception ) {
835+ throw new TemporaryCouldNotSaveException (
836+ __ ('Database deadlock found when trying to get lock ' ),
837+ $ exception ,
838+ $ exception ->getCode ()
839+ );
840+ } catch (LockWaitException $ exception ) {
841+ throw new TemporaryCouldNotSaveException (
842+ __ ('Database lock wait timeout exceeded ' ),
843+ $ exception ,
844+ $ exception ->getCode ()
845+ );
846+ } catch (AttributeException $ exception ) {
847+ throw InputException::invalidFieldValue (
848+ $ exception ->getAttributeCode (),
849+ $ product ->getData ($ exception ->getAttributeCode ()),
850+ $ exception
851+ );
852+ } catch (ValidatorException $ e ) {
853+ throw new CouldNotSaveException (__ ($ e ->getMessage ()));
854+ } catch (LocalizedException $ e ) {
855+ throw $ e ;
856+ } catch (\Exception $ e ) {
857+ throw new CouldNotSaveException (
858+ __ ('The product was unable to be saved. Please try again. ' ),
859+ $ e
860+ );
861+ }
862+ }
838863}
0 commit comments