Skip to content

Commit 57b9f84

Browse files
author
Yaroslav Onischenko
committed
MAGETWO-52558: Cache is not invalidated or refreshed when product website visibility changes
1 parent 5967155 commit 57b9f84

File tree

4 files changed

+171
-34
lines changed

4 files changed

+171
-34
lines changed

app/code/Magento/Catalog/Model/Indexer/Product/Category/Action/Rows.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
*/
66
namespace Magento\Catalog\Model\Indexer\Product\Category\Action;
77

8+
use Magento\Catalog\Model\Category;
9+
use Magento\Catalog\Model\Product;
10+
use Magento\Framework\Indexer\CacheContext;
11+
812
class Rows extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractAction
913
{
1014
/**
@@ -14,6 +18,11 @@ class Rows extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
1418
*/
1519
protected $limitationByProducts;
1620

21+
/**
22+
* @var \Magento\Framework\Indexer\CacheContext
23+
*/
24+
private $cacheContext;
25+
1726
/**
1827
* Refresh entities index
1928
*
@@ -30,9 +39,39 @@ public function execute(array $entityIds = [], $useTempTable = false)
3039

3140
$this->reindex();
3241

42+
$this->registerProducts($entityIds);
43+
$this->registerCategories($entityIds);
44+
3345
return $this;
3446
}
3547

48+
/**
49+
* @param array $entityIds
50+
*/
51+
private function registerProducts($entityIds)
52+
{
53+
$this->getCacheContext()->registerEntities(Product::CACHE_TAG, $entityIds);
54+
}
55+
56+
/**
57+
* Register categories assigned to products
58+
*
59+
* @param array $entityIds
60+
* @return void
61+
*/
62+
private function registerCategories($entityIds)
63+
{
64+
$categories = $this->connection->fetchCol(
65+
$this->connection->select()
66+
->from($this->getMainTable(), ['category_id'])
67+
->where('product_id IN (?)', $entityIds)
68+
);
69+
70+
if ($categories) {
71+
$this->getCacheContext()->registerEntities(Category::CACHE_TAG, array_unique($categories));
72+
}
73+
}
74+
3675
/**
3776
* Remove index entries before reindexation
3877
*
@@ -91,4 +130,18 @@ protected function isRangingNeeded()
91130
{
92131
return false;
93132
}
133+
134+
/**
135+
* Get cache context
136+
*
137+
* @return \Magento\Framework\Indexer\CacheContext
138+
* @deprecated
139+
*/
140+
protected function getCacheContext()
141+
{
142+
if ($this->cacheContext === null) {
143+
$this->cacheContext = \Magento\Framework\App\ObjectManager::getInstance()->get(CacheContext::class);
144+
}
145+
return $this->cacheContext;
146+
}
94147
}

app/code/Magento/Catalog/Plugin/Model/Product/Action/UpdateAttributesFlushCache.php

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66
namespace Magento\Catalog\Plugin\Model\Product\Action;
77

8-
use Magento\Catalog\Model\Product;
98
use Magento\Catalog\Model\Product\Action;
109
use Magento\Framework\Indexer\CacheContext;
1110
use Magento\Framework\Event\ManagerInterface as EventManager;
@@ -36,26 +35,28 @@ public function __construct(
3635

3736
/**
3837
* @param Action $subject
39-
* @param \Closure $proceed
40-
* @param array $productIds
41-
* @param array $attrData
42-
* @param int $storeId
38+
* @param Action $result
4339
* @return Action
4440
*
4541
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
4642
*/
47-
public function aroundUpdateAttributes(
48-
Action $subject,
49-
\Closure $proceed,
50-
$productIds,
51-
$attrData,
52-
$storeId
43+
public function afterUpdateAttributes(
44+
\Magento\Catalog\Model\Product\Action $subject,
45+
\Magento\Catalog\Model\Product\Action $result
5346
) {
54-
$returnValue = $proceed($productIds, $attrData, $storeId);
55-
56-
$this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds);
5747
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
48+
return $result;
49+
}
5850

59-
return $returnValue;
51+
/**
52+
* @param Action $subject
53+
* @return Action
54+
*
55+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
56+
*/
57+
public function afterUpdateWebsites(
58+
\Magento\Catalog\Model\Product\Action $subject
59+
) {
60+
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
6061
}
6162
}

app/code/Magento/Catalog/Test/Unit/Plugin/Model/Product/Action/UpdateAttributesFlushCacheTest.php

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,41 @@
99

1010
class UpdateAttributesFlushCacheTest extends \PHPUnit_Framework_TestCase
1111
{
12-
public function testAroundUpdateAttributes()
13-
{
14-
$productIds = [1, 2, 3];
15-
$attrData = [];
16-
$storeId = 1;
17-
18-
$productActionMock = $this->getMock('Magento\Catalog\Model\Product\Action', [], [], '', false);
19-
20-
$cacheContextMock = $this->getMock('Magento\Framework\Indexer\CacheContext', [], [], '', false);
21-
$cacheContextMock->expects($this->once())
22-
->method('registerEntities')
23-
->with(Product::CACHE_TAG, $productIds);
12+
/**
13+
* @var \Magento\Catalog\Plugin\Model\Product\Action\UpdateAttributesFlushCache
14+
*/
15+
private $model;
2416

17+
protected function setUp()
18+
{
19+
$cacheContextMock = $this->getMock(\Magento\Framework\Indexer\CacheContext::class, [], [], '', false);
2520

26-
$eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface');
21+
$eventManagerMock = $this->getMock(\Magento\Framework\Event\ManagerInterface::class);
2722
$eventManagerMock->expects($this->once())
2823
->method('dispatch')
2924
->with('clean_cache_by_tags', ['object' => $cacheContextMock]);
3025

3126
$objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
32-
$model = $objectManager->getObject(
33-
'Magento\Catalog\Plugin\Model\Product\Action\UpdateAttributesFlushCache',
27+
$this->model = $objectManager->getObject(
28+
\Magento\Catalog\Plugin\Model\Product\Action\UpdateAttributesFlushCache::class,
3429
[
3530
'cacheContext' => $cacheContextMock,
3631
'eventManager' => $eventManagerMock,
3732
]
3833
);
34+
}
3935

40-
$closureMock = function () use ($productActionMock) {
41-
return $productActionMock;
42-
};
36+
public function testAroundUpdateAttributes()
37+
{
38+
/** @var \Magento\Catalog\Model\Product\Action $productActionMock */
39+
$productActionMock = $this->getMock(\Magento\Catalog\Model\Product\Action::class, [], [], '', false);
40+
$this->model->afterUpdateAttributes($productActionMock, $productActionMock);
41+
}
4342

44-
$model->aroundUpdateAttributes($productActionMock, $closureMock, $productIds, $attrData, $storeId);
43+
public function testAroundUpdateWebsites()
44+
{
45+
/** @var \Magento\Catalog\Model\Product\Action $productActionMock */
46+
$productActionMock = $this->getMock(\Magento\Catalog\Model\Product\Action::class, [], [], '', false);
47+
$this->model->afterUpdateWebsites($productActionMock, $productActionMock);
4548
}
4649
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Model\Product;
7+
8+
use Magento\CatalogSearch\Model\Indexer\Fulltext;
9+
10+
class ActionTest extends \PHPUnit_Framework_TestCase
11+
{
12+
/**
13+
* @var \Magento\Catalog\Model\Product\Action
14+
*/
15+
private $action;
16+
17+
/**
18+
* @var \Magento\Framework\ObjectManagerInterface
19+
*/
20+
private $objectManager;
21+
22+
protected function setUp()
23+
{
24+
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
25+
26+
/** @var \Magento\Framework\App\Cache\StateInterface $cacheState */
27+
$cacheState = $this->objectManager->get(\Magento\Framework\App\Cache\StateInterface::class);
28+
$cacheState->setEnabled(\Magento\PageCache\Model\Cache\Type::TYPE_IDENTIFIER, true);
29+
30+
$this->action = $this->objectManager->create(\Magento\Catalog\Model\Product\Action\Interceptor::class);
31+
}
32+
33+
/**
34+
* @magentoDataFixture Magento/Catalog/_files/product_simple.php
35+
* @magentoDataFixture Magento/Store/_files/core_second_third_fixturestore.php
36+
* @magentoAppArea adminhtml
37+
*/
38+
public function testUpdateWebsites()
39+
{
40+
/** @var \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry */
41+
$indexerRegistry = $this->objectManager->get(\Magento\Framework\Indexer\IndexerRegistry::class);
42+
$indexerRegistry->get(Fulltext::INDEXER_ID)->setScheduled(true);
43+
44+
/** @var \Magento\Store\Api\WebsiteRepositoryInterface $websiteRepository */
45+
$websiteRepository = $this->objectManager->create(\Magento\Store\Api\WebsiteRepositoryInterface::class);
46+
47+
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
48+
$productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
49+
50+
/** @var \Magento\Framework\App\CacheInterface $cacheManager */
51+
$pageCache = $this->objectManager->create(\Magento\PageCache\Model\Cache\Type::class);
52+
53+
/** @var \Magento\Catalog\Model\Product $product */
54+
$product = $productRepository->get('simple');
55+
foreach ($product->getCategoryIds() as $categoryId) {
56+
$pageCache->save(
57+
'test_data',
58+
'test_data_category_id_' . $categoryId,
59+
[\Magento\Catalog\Model\Category::CACHE_TAG . '_' . $categoryId]
60+
);
61+
$this->assertEquals('test_data', $pageCache->load('test_data_category_id_' . $categoryId));
62+
}
63+
64+
$websites = $websiteRepository->getList();
65+
$websiteIds = [];
66+
foreach ($websites as $websiteCode => $website) {
67+
if (in_array($websiteCode, ['secondwebsite', 'thirdwebsite'])) {
68+
$websiteIds[] = $website->getId();
69+
}
70+
}
71+
72+
$this->action->updateWebsites([$product->getId()], $websiteIds, 'add');
73+
74+
foreach ($product->getCategoryIds() as $categoryId) {
75+
$this->assertEmpty(
76+
$pageCache->load('test_data_category_id_' . $categoryId)
77+
);
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)