Skip to content

Commit f3e16fa

Browse files
author
Oleksii Korshenko
authored
Merge pull request #430 from magento-performance/MAGETWO-54645
Fixed issue: - MAGETWO-54645: Smarter Cache Invalidation on Qty Change
2 parents fb6faf5 + 7119e97 commit f3e16fa

File tree

5 files changed

+361
-9
lines changed

5 files changed

+361
-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: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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+
$this->resource = $resource;
62+
$this->stockConfiguration = $stockConfiguration;
63+
$this->cacheContext = $cacheContext;
64+
$this->eventManager = $eventManager;
65+
}
66+
67+
/**
68+
* @param array $productIds
69+
* @param callable $reindex
70+
* @return void
71+
*/
72+
public function clean(array $productIds, callable $reindex)
73+
{
74+
$productStatusesBefore = $this->getProductStockStatuses($productIds);
75+
$reindex();
76+
$productStatusesAfter = $this->getProductStockStatuses($productIds);
77+
$productIds = $this->getProductIds($productStatusesBefore, $productStatusesAfter);
78+
if ($productIds) {
79+
$this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds);
80+
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
81+
}
82+
}
83+
84+
/**
85+
* @param array $productIds
86+
* @return array
87+
*/
88+
private function getProductStockStatuses(array $productIds)
89+
{
90+
$select = $this->getConnection()->select()
91+
->from(
92+
$this->resource->getTableName('cataloginventory_stock_status'),
93+
['product_id', 'stock_status', 'qty']
94+
)->where('product_id IN (?)', $productIds)
95+
->where('stock_id = ?', Stock::DEFAULT_STOCK_ID)
96+
->where('website_id = ?', $this->stockConfiguration->getDefaultScopeId());
97+
98+
$statuses = [];
99+
foreach ($this->getConnection()->fetchAll($select) as $item) {
100+
$statuses[$item['product_id']] = $item;
101+
}
102+
return $statuses;
103+
}
104+
105+
/**
106+
* @param array $productStatusesBefore
107+
* @param array $productStatusesAfter
108+
* @return array
109+
*/
110+
private function getProductIds(array $productStatusesBefore, array $productStatusesAfter)
111+
{
112+
$productIds = [];
113+
$stockThresholdQty = $this->stockConfiguration->getStockThresholdQty();
114+
foreach ($productStatusesBefore as $productId => $statusBefore) {
115+
$statusAfter = $productStatusesAfter[$productId];
116+
if ($statusBefore['stock_status'] !== $statusAfter['stock_status']
117+
|| ($stockThresholdQty && $statusAfter['qty'] <= $stockThresholdQty)) {
118+
$productIds[] = $productId;
119+
}
120+
}
121+
122+
return $productIds;
123+
}
124+
125+
/**
126+
* @return AdapterInterface
127+
*/
128+
private function getConnection()
129+
{
130+
if (null === $this->connection) {
131+
$this->connection = $this->resource->getConnection();
132+
}
133+
134+
return $this->connection;
135+
}
136+
}

0 commit comments

Comments
 (0)