Skip to content

Commit f9fc2fa

Browse files
committed
MAGETWO-54645: Smarter Cache Invalidation on Qty Change
1 parent 8bf902a commit f9fc2fa

File tree

4 files changed

+193
-9
lines changed

4 files changed

+193
-9
lines changed

app/code/Magento/CatalogInventory/Block/Stockqty/AbstractStockqty.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ abstract class AbstractStockqty extends \Magento\Framework\View\Element\Template
1515
{
1616
/**
1717
* Threshold qty config path
18+
* @deprecated
19+
* @see \Magento\CatalogInventory\Model\Configuration::XML_PATH_STOCK_THRESHOLD_QTY
1820
*/
1921
const XML_PATH_STOCK_THRESHOLD_QTY = 'cataloginventory/options/stock_threshold_qty';
2022

app/code/Magento/CatalogInventory/Model/Configuration.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ class Configuration implements StockConfigurationInterface
9696
*/
9797
const XML_PATH_DISPLAY_PRODUCT_STOCK_STATUS = 'cataloginventory/options/display_product_stock_status';
9898

99+
/**
100+
* Threshold qty config path
101+
*/
102+
const XML_PATH_STOCK_THRESHOLD_QTY = 'cataloginventory/options/stock_threshold_qty';
103+
99104
/**
100105
* @var ConfigInterface
101106
*/
@@ -385,6 +390,19 @@ public function getDefaultConfigValue($field, $store = null)
385390
);
386391
}
387392

393+
/**
394+
* @param null|string|bool|int|\Magento\Store\Model\Store $store
395+
* @return string|null
396+
*/
397+
public function getStockThresholdQty($store = null)
398+
{
399+
return $this->scopeConfig->getValue(
400+
self::XML_PATH_STOCK_THRESHOLD_QTY,
401+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
402+
$store
403+
);
404+
}
405+
388406
/**
389407
* Retrieve inventory item options (used in config)
390408
*

app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
namespace Magento\CatalogInventory\Model\Indexer\Stock;
1010

11-
use Magento\Catalog\Model\Category;
12-
use Magento\Catalog\Model\Product;
11+
use Magento\Framework\App\ObjectManager;
1312
use Magento\Framework\App\ResourceConnection;
1413

1514
/**
@@ -66,6 +65,11 @@ abstract class AbstractAction
6665
*/
6766
private $eventManager;
6867

68+
/**
69+
* @var CacheCleaner
70+
*/
71+
private $cacheCleaner;
72+
6973
/**
7074
* @param ResourceConnection $resource
7175
* @param \Magento\CatalogInventory\Model\ResourceModel\Indexer\StockFactory $indexerFactory
@@ -219,14 +223,31 @@ protected function _deleteOldRelations($tableName)
219223
* Refresh entities index
220224
*
221225
* @param array $productIds
222-
* @return array Affected ids
226+
* @return $this
223227
*/
224228
protected function _reindexRows($productIds = [])
225229
{
226-
$connection = $this->_getConnection();
227230
if (!is_array($productIds)) {
228231
$productIds = [$productIds];
229232
}
233+
234+
$this->getCacheCleaner()->clean($productIds, function () use ($productIds) {
235+
$this->doReindex($productIds);
236+
});
237+
238+
return $this;
239+
}
240+
241+
/**
242+
* Refresh entities index
243+
*
244+
* @param array $productIds
245+
* @return void
246+
*/
247+
private function doReindex($productIds = [])
248+
{
249+
$connection = $this->_getConnection();
250+
230251
$parentIds = $this->getRelationsByChild($productIds);
231252
$processIds = $parentIds ? array_merge($parentIds, $productIds) : $productIds;
232253

@@ -247,11 +268,17 @@ protected function _reindexRows($productIds = [])
247268
$indexer->reindexEntity($byType[$indexer->getTypeId()]);
248269
}
249270
}
250-
251-
$this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds);
252-
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
253-
254-
return $this;
271+
}
272+
273+
/**
274+
* @return CacheCleaner
275+
*/
276+
private function getCacheCleaner()
277+
{
278+
if (null === $this->cacheCleaner) {
279+
$this->cacheCleaner = ObjectManager::getInstance()->get(CacheCleaner::class);
280+
}
281+
return $this->cacheCleaner;
255282
}
256283

257284
/**
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
/**
3+
* @category Magento
4+
* @package Magento_CatalogInventory
5+
* Copyright © 2016 Magento. All rights reserved.
6+
* See COPYING.txt for license details.
7+
*/
8+
9+
namespace Magento\CatalogInventory\Model\Indexer\Stock;
10+
11+
use Magento\CatalogInventory\Api\StockConfigurationInterface;
12+
use Magento\Framework\App\ResourceConnection;
13+
use Magento\Framework\DB\Adapter\AdapterInterface;
14+
use Magento\Framework\Event\ManagerInterface;
15+
use Magento\Framework\Indexer\CacheContext;
16+
use Magento\CatalogInventory\Model\Stock;
17+
use Magento\Catalog\Model\Product;
18+
19+
/**
20+
* Clean product cache only when stock status was updated
21+
*/
22+
class CacheCleaner
23+
{
24+
/**
25+
* @var ResourceConnection
26+
*/
27+
private $resource;
28+
29+
/**
30+
* @var StockConfigurationInterface
31+
*/
32+
private $stockConfiguration;
33+
34+
/**
35+
* @var CacheContext
36+
*/
37+
private $cacheContext;
38+
39+
/**
40+
* @var ManagerInterface
41+
*/
42+
private $eventManager;
43+
44+
/**
45+
* @var AdapterInterface
46+
*/
47+
private $connection;
48+
49+
/**
50+
* @param ResourceConnection $resource
51+
* @param StockConfigurationInterface $stockConfiguration
52+
* @param CacheContext $cacheContext
53+
* @param ManagerInterface $eventManager
54+
*/
55+
public function __construct(
56+
ResourceConnection $resource,
57+
StockConfigurationInterface $stockConfiguration,
58+
CacheContext $cacheContext,
59+
ManagerInterface $eventManager
60+
) {
61+
62+
$this->resource = $resource;
63+
$this->stockConfiguration = $stockConfiguration;
64+
$this->cacheContext = $cacheContext;
65+
$this->eventManager = $eventManager;
66+
}
67+
68+
/**
69+
* @param array $productIds
70+
* @param callable $reindex
71+
* @return void
72+
*/
73+
public function clean(array $productIds, callable $reindex)
74+
{
75+
$productStatusesBefore = $this->getProductStockStatuses($productIds);
76+
$reindex();
77+
$productStatusesAfter = $this->getProductStockStatuses($productIds);
78+
$productIds = $this->getProductIds($productStatusesBefore, $productStatusesAfter);
79+
if ($productIds) {
80+
$this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds);
81+
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
82+
}
83+
}
84+
85+
/**
86+
* @param array $productIds
87+
* @return array
88+
*/
89+
private function getProductStockStatuses(array $productIds)
90+
{
91+
$select = $this->getConnection()->select()
92+
->from(
93+
$this->resource->getTableName('cataloginventory_stock_status'),
94+
['product_id', 'stock_status', 'qty']
95+
)->where('product_id IN (?)', $productIds)
96+
->where('stock_id = ?', Stock::DEFAULT_STOCK_ID)
97+
->where('website_id = ?', $this->stockConfiguration->getDefaultScopeId());
98+
99+
$statuses = [];
100+
foreach ($this->getConnection()->fetchAll($select) as $item) {
101+
$statuses[$item['product_id']] = $item;
102+
}
103+
return $statuses;
104+
}
105+
106+
/**
107+
* @param array $productStatusesBefore
108+
* @param array $productStatusesAfter
109+
* @return array
110+
*/
111+
private function getProductIds(array $productStatusesBefore, array $productStatusesAfter)
112+
{
113+
$productIds = [];
114+
$stockThresholdQty = $this->stockConfiguration->getStockThresholdQty();
115+
foreach ($productStatusesBefore as $productId => $statusBefore) {
116+
$statusAfter = $productStatusesAfter[$productId];
117+
if ($statusBefore['stock_status'] !== $statusAfter['stock_status']
118+
|| ($stockThresholdQty && $statusAfter['qty'] <= $stockThresholdQty)) {
119+
$productIds[] = $productId;
120+
}
121+
}
122+
123+
return $productIds;
124+
}
125+
126+
/**
127+
* @return AdapterInterface
128+
*/
129+
private function getConnection()
130+
{
131+
if (null === $this->connection) {
132+
$this->connection = $this->resource->getConnection();
133+
}
134+
135+
return $this->connection;
136+
}
137+
}

0 commit comments

Comments
 (0)