Search

Mar 28, 2023

Magento2: Page Cache is not cleared for the parent product on the child product save

We changed price, color on some product, but sometimes it's not updated on the front end, after we cleared cache, it's updated. 

The issue is on Magento 2.4.4-p1 


SOLUTION:

Please check the below patch to fix

diff --git a/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php b/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php
index 2f333e7ca6f6..9c226641b6e3 100644
--- a/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php
+++ b/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php
@@ -4,20 +4,29 @@
  * Copyright © Magento, Inc. All rights reserved.
  * See COPYING.txt for license details.
  */
+declare(strict_types=1);
 
 namespace Magento\ConfigurableProduct\Plugin\Model\ResourceModel;
 
 use Magento\Catalog\Api\Data\ProductAttributeInterface;
 use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
+use Magento\Catalog\Model\Indexer\Product\Category\Action\Rows;
+use Magento\Catalog\Model\Indexer\Product\Price\Processor;
+use Magento\Catalog\Model\Product as ProductModel;
+use Magento\Catalog\Model\ResourceModel\Product as ProductResource;
 use Magento\ConfigurableProduct\Api\Data\OptionInterface;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\Framework\Api\FilterBuilder;
 use Magento\Framework\Api\SearchCriteriaBuilder;
 use Magento\Framework\App\ObjectManager;
+use Magento\Framework\DataObject;
 use Magento\Framework\Indexer\ActionInterface;
+use Magento\Framework\Indexer\IndexerRegistry;
 
 /**
  * Plugin product resource model
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Product
 {
@@ -46,21 +55,35 @@ class Product
      */
     private $filterBuilder;
 
+    /**
+     * @var IndexerRegistry
+     */
+    private $indexerRegistry;
+
+    /**
+     * @var Rows
+     */
+    private $rowsAction;
+
     /**
      * Initialize Product dependencies.
      *
      * @param Configurable $configurable
      * @param ActionInterface $productIndexer
-     * @param ProductAttributeRepositoryInterface $productAttributeRepository
-     * @param SearchCriteriaBuilder $searchCriteriaBuilder
-     * @param FilterBuilder $filterBuilder
+     * @param ProductAttributeRepositoryInterface|null $productAttributeRepository
+     * @param SearchCriteriaBuilder|null $searchCriteriaBuilder
+     * @param FilterBuilder|null $filterBuilder
+     * @param IndexerRegistry|null $indexerRegistry
+     * @param Rows|null $rowsAction
      */
     public function __construct(
         Configurable $configurable,
         ActionInterface $productIndexer,
         ProductAttributeRepositoryInterface $productAttributeRepository = null,
-        SearchCriteriaBuilder $searchCriteriaBuilder = null,
-        FilterBuilder $filterBuilder = null
+        ?SearchCriteriaBuilder $searchCriteriaBuilder = null,
+        ?FilterBuilder $filterBuilder = null,
+        ?IndexerRegistry $indexerRegistry = null,
+        ?Rows $rowsAction = null
     ) {
         $this->configurable = $configurable;
         $this->productIndexer = $productIndexer;
@@ -70,35 +93,62 @@ public function __construct(
             ->get(SearchCriteriaBuilder::class);
         $this->filterBuilder = $filterBuilder ?: ObjectManager::getInstance()
             ->get(FilterBuilder::class);
+        $this->indexerRegistry = $indexerRegistry ?: ObjectManager::getInstance()
+            ->get(IndexerRegistry::class);
+        $this->rowsAction = $rowsAction ?: ObjectManager::getInstance()
+            ->get(Rows::class);
     }
 
     /**
      * We need reset attribute set id to attribute after related simple product was saved
      *
-     * @param \Magento\Catalog\Model\ResourceModel\Product $subject
-     * @param \Magento\Framework\DataObject $object
+     * @param ProductResource $subject
+     * @param DataObject $object
      * @return void
-     * @throws \Magento\Framework\Exception\NoSuchEntityException
      *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function beforeSave(
-        \Magento\Catalog\Model\ResourceModel\Product $subject,
-        \Magento\Framework\DataObject $object
+        ProductResource $subject,
+        DataObject $object
     ) {
-        /** @var \Magento\Catalog\Model\Product $object */
+        /** @var ProductModel $object */
         if ($object->getTypeId() == Configurable::TYPE_CODE) {
             $object->getTypeInstance()->getSetAttributes($object);
             $this->resetConfigurableOptionsData($object);
         }
     }
 
+    /**
+     * Invalidate cache and per<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">diff --git a/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php b/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php
index 2f333e7ca6f6..9c226641b6e3 100644
--- a/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php
+++ b/vendor/magento/module-configurable-product/Plugin/Model/ResourceModel/Product.php
@@ -4,20 +4,29 @@
  * Copyright © Magento, Inc. All rights reserved.
  * See COPYING.txt for license details.
  */
+declare(strict_types=1);
 
 namespace Magento\ConfigurableProduct\Plugin\Model\ResourceModel;
 
 use Magento\Catalog\Api\Data\ProductAttributeInterface;
 use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
+use Magento\Catalog\Model\Indexer\Product\Category\Action\Rows;
+use Magento\Catalog\Model\Indexer\Product\Price\Processor;
+use Magento\Catalog\Model\Product as ProductModel;
+use Magento\Catalog\Model\ResourceModel\Product as ProductResource;
 use Magento\ConfigurableProduct\Api\Data\OptionInterface;
 use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\Framework\Api\FilterBuilder;
 use Magento\Framework\Api\SearchCriteriaBuilder;
 use Magento\Framework\App\ObjectManager;
+use Magento\Framework\DataObject;
 use Magento\Framework\Indexer\ActionInterface;
+use Magento\Framework\Indexer\IndexerRegistry;
 
 /**
  * Plugin product resource model
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Product
 {
@@ -46,21 +55,35 @@ class Product
      */
     private $filterBuilder;
 
+    /**
+     * @var IndexerRegistry
+     */
+    private $indexerRegistry;
+
+    /**
+     * @var Rows
+     */
+    private $rowsAction;
+
     /**
      * Initialize Product dependencies.
      *
      * @param Configurable $configurable
      * @param ActionInterface $productIndexer
-     * @param ProductAttributeRepositoryInterface $productAttributeRepository
-     * @param SearchCriteriaBuilder $searchCriteriaBuilder
-     * @param FilterBuilder $filterBuilder
+     * @param ProductAttributeRepositoryInterface|null $productAttributeRepository
+     * @param SearchCriteriaBuilder|null $searchCriteriaBuilder
+     * @param FilterBuilder|null $filterBuilder
+     * @param IndexerRegistry|null $indexerRegistry
+     * @param Rows|null $rowsAction
      */
     public function __construct(
         Configurable $configurable,
         ActionInterface $productIndexer,
         ProductAttributeRepositoryInterface $productAttributeRepository = null,
-        SearchCriteriaBuilder $searchCriteriaBuilder = null,
-        FilterBuilder $filterBuilder = null
+        ?SearchCriteriaBuilder $searchCriteriaBuilder = null,
+        ?FilterBuilder $filterBuilder = null,
+        ?IndexerRegistry $indexerRegistry = null,
+        ?Rows $rowsAction = null
     ) {
         $this-&gt;configurable = $configurable;
         $this-&gt;productIndexer = $productIndexer;
@@ -70,35 +93,62 @@ public function __construct(
             -&gt;get(SearchCriteriaBuilder::class);
         $this-&gt;filterBuilder = $filterBuilder ?: ObjectManager::getInstance()
             -&gt;get(FilterBuilder::class);
+        $this-&gt;indexerRegistry = $indexerRegistry ?: ObjectManager::getInstance()
+            -&gt;get(IndexerRegistry::class);
+        $this-&gt;rowsAction = $rowsAction ?: ObjectManager::getInstance()
+            -&gt;get(Rows::class);
     }
 
     /**
      * We need reset attribute set id to attribute after related simple product was saved
      *
-     * @param \Magento\Catalog\Model\ResourceModel\Product $subject
-     * @param \Magento\Framework\DataObject $object
+     * @param ProductResource $subject
+     * @param DataObject $object
      * @return void
-     * @throws \Magento\Framework\Exception\NoSuchEntityException
      *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function beforeSave(
-        \Magento\Catalog\Model\ResourceModel\Product $subject,
-        \Magento\Framework\DataObject $object
+        ProductResource $subject,
+        DataObject $object
     ) {
-        /** @var \Magento\Catalog\Model\Product $object */
+        /** @var ProductModel $object */
         if ($object-&gt;getTypeId() == Configurable::TYPE_CODE) {
             $object-&gt;getTypeInstance()-&gt;getSetAttributes($object);
             $this-&gt;resetConfigurableOptionsData($object);
         }
     }
 
+    /**
+     * Invalidate cache and perform reindexing for configurable associated product
+     *
+     * @param ProductResource $subject
+     * @param ProductResource $result
+     * @param DataObject $object
+     * @return ProductResource
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterSave(
+        ProductResource $subject,
+        ProductResource $result,
+        DataObject $object
+    ): ProductResource {
+        $productId = $object-&gt;getId();
+        $priceIndexer = $this-&gt;indexerRegistry-&gt;get(Processor::INDEXER_ID);
+        if ($priceIndexer-&gt;isScheduled()
+            &amp;&amp; count($this-&gt;configurable-&gt;getParentIdsByChild($productId)) &gt; 0) {
+            $this-&gt;rowsAction-&gt;execute([$productId]);
+        }
+
+        return $result;
+    }
+
     /**
      * Set null for configurable options attribute of configurable product
      *
-     * @param \Magento\Catalog\Model\Product $object
+     * @param ProductModel $object
      * @return void
-     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
     private function resetConfigurableOptionsData($object)
     {
@@ -128,16 +178,16 @@ private function resetConfigurableOptionsData($object)
     /**
      * Gather configurable parent ids of product being deleted and reindex after delete is complete.
      *
-     * @param \Magento\Catalog\Model\ResourceModel\Product $subject
+     * @param ProductResource $subject
      * @param \Closure $proceed
-     * @param \Magento\Catalog\Model\Product $product
-     * @return \Magento\Catalog\Model\ResourceModel\Product
+     * @param ProductModel $product
+     * @return ProductResource
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function aroundDelete(
-        \Magento\Catalog\Model\ResourceModel\Product $subject,
+        ProductResource $subject,
         \Closure $proceed,
-        \Magento\Catalog\Model\Product $product
+        ProductModel $product
     ) {
         $configurableProductIds = $this-&gt;configurable-&gt;getParentIdsByChild($product-&gt;getId());
         $result = $proceed($product);
</pre></div>
form reindexing for configurable associated product
+     *
+     * @param ProductResource $subject
+     * @param ProductResource $result
+     * @param DataObject $object
+     * @return ProductResource
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterSave(
+        ProductResource $subject,
+        ProductResource $result,
+        DataObject $object
+    ): ProductResource {
+        $productId = $object->getId();
+        $priceIndexer = $this->indexerRegistry->get(Processor::INDEXER_ID);
+        if ($priceIndexer->isScheduled()
+            && count($this->configurable->getParentIdsByChild($productId)) > 0) {
+            $this->rowsAction->execute([$productId]);
+        }
+
+        return $result;
+    }
+
     /**
      * Set null for configurable options attribute of configurable product
      *
-     * @param \Magento\Catalog\Model\Product $object
+     * @param ProductModel $object
      * @return void
-     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
     private function resetConfigurableOptionsData($object)
     {
@@ -128,16 +178,16 @@ private function resetConfigurableOptionsData($object)
     /**
      * Gather configurable parent ids of product being deleted and reindex after delete is complete.
      *
-     * @param \Magento\Catalog\Model\ResourceModel\Product $subject
+     * @param ProductResource $subject
      * @param \Closure $proceed
-     * @param \Magento\Catalog\Model\Product $product
-     * @return \Magento\Catalog\Model\ResourceModel\Product
+     * @param ProductModel $product
+     * @return ProductResource
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function aroundDelete(
-        \Magento\Catalog\Model\ResourceModel\Product $subject,
+        ProductResource $subject,
         \Closure $proceed,
-        \Magento\Catalog\Model\Product $product
+        ProductModel $product
     ) {
         $configurableProductIds = $this->configurable->getParentIdsByChild($product->getId());
         $result = $proceed($product);

No comments:

Post a Comment