Skip to content

Commit 74fcac9

Browse files
committed
ACP2E-4303: Reindexing stuck due to high memory usage
1 parent c1e81cf commit 74fcac9

File tree

2 files changed

+80
-217
lines changed

2 files changed

+80
-217
lines changed

app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandler.php

Lines changed: 52 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77

88
namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule;
99

10-
use Magento\CatalogRule\Model\Rule;
10+
use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider;
1111
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable as ConfigurableProductsResourceModel;
12-
use Magento\Framework\App\ResourceConnection;
1312

1413
/**
1514
* Add configurable sub products to catalog rule indexer on full reindex
@@ -22,174 +21,100 @@ class ConfigurableProductHandler
2221
private ConfigurableProductsResourceModel $configurable;
2322

2423
/**
25-
* @var ResourceConnection
24+
* @var ConfigurableProductsProvider
2625
*/
27-
private ResourceConnection $resourceConnection;
28-
29-
/**
30-
* @var array|null
31-
*/
32-
private static ?array $allConfigurableProductIds = null;
26+
private ConfigurableProductsProvider $configurableProductsProvider;
3327

3428
/**
3529
* @var array
3630
*/
37-
private static array $childrenProducts = [];
31+
private array $childrenProducts = [];
3832

3933
/**
4034
* @param ConfigurableProductsResourceModel $configurable
41-
* @param ResourceConnection $resourceConnection
35+
* @param ConfigurableProductsProvider $configurableProductsProvider
4236
*/
4337
public function __construct(
4438
ConfigurableProductsResourceModel $configurable,
45-
ResourceConnection $resourceConnection
39+
ConfigurableProductsProvider $configurableProductsProvider
4640
) {
4741
$this->configurable = $configurable;
48-
$this->resourceConnection = $resourceConnection;
42+
$this->configurableProductsProvider = $configurableProductsProvider;
4943
}
5044

5145
/**
52-
* Match configurable child products if configurable product matches the condition
46+
* Match configurable child products if configurable product match the condition
5347
*
54-
* @param Rule $rule
48+
* @param \Magento\CatalogRule\Model\Rule $rule
5549
* @param \Closure $proceed
5650
* @return array
5751
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
52+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
53+
* @SuppressWarnings(PHPMD.NPathComplexity)
54+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
5855
*/
5956
public function aroundGetMatchingProductIds(
60-
Rule $rule,
57+
\Magento\CatalogRule\Model\Rule $rule,
6158
\Closure $proceed
6259
): array {
6360
$productsFilter = $rule->getProductsFilter() ? (array) $rule->getProductsFilter() : [];
64-
65-
$this->updateProductsFilter($rule, $productsFilter);
66-
67-
$productIds = $proceed();
68-
69-
if (self::$allConfigurableProductIds === null) {
70-
self::$allConfigurableProductIds = $this->loadAllConfigurableProductIds();
71-
}
72-
73-
return $this->processConfigurableProducts($productIds, $productsFilter);
74-
}
75-
76-
/**
77-
* Update products filter to include parent IDs and remove duplicate children
78-
*
79-
* @param Rule $rule
80-
* @param array $productsFilter
81-
* @return void
82-
*/
83-
private function updateProductsFilter(
84-
Rule $rule,
85-
array $productsFilter
86-
): void {
87-
if (!$productsFilter) {
88-
return;
89-
}
90-
91-
$parentIds = $this->configurable->getParentIdsByChild($productsFilter);
92-
if (!$parentIds) {
93-
return;
94-
}
95-
96-
$childrenToRemove = $this->getChildrenToRemove($productsFilter, $parentIds);
97-
$filteredProducts = array_diff($productsFilter, $childrenToRemove);
98-
99-
$rule->setProductsFilter(
100-
array_unique(
101-
array_merge(
102-
$filteredProducts,
103-
$parentIds
61+
if ($productsFilter) {
62+
$rule->setProductsFilter(
63+
array_unique(
64+
array_merge(
65+
$productsFilter,
66+
$this->configurable->getParentIdsByChild($productsFilter)
67+
)
10468
)
105-
)
106-
);
107-
}
108-
109-
/**
110-
* Get children to remove from filter to avoid redundancy
111-
*
112-
* @param array $productsFilter
113-
* @param array $parentIds
114-
* @return array
115-
*/
116-
private function getChildrenToRemove(array $productsFilter, array $parentIds): array
117-
{
118-
$childrenToRemove = [];
69+
);
70+
}
11971

120-
foreach ($parentIds as $parentId) {
121-
if (in_array($parentId, $productsFilter)) {
122-
continue;
72+
$productIds = $proceed();
73+
foreach ($productIds as $productId => $productData) {
74+
if ($this->hasAntecedentRule((int) $productId)) {
75+
$productIds[$productId]['has_antecedent_rule'] = true;
12376
}
77+
}
12478

125-
if (!isset(self::$childrenProducts[$parentId])) {
126-
self::$childrenProducts[$parentId] = $this->configurable->getChildrenIds($parentId)[0];
79+
foreach ($this->configurableProductsProvider->getIds(array_keys($productIds)) as $configurableProductId) {
80+
if (!isset($this->childrenProducts[$configurableProductId])) {
81+
$this->childrenProducts[$configurableProductId] =
82+
$this->configurable->getChildrenIds($configurableProductId)[0];
12783
}
128-
$children = self::$childrenProducts[$parentId];
12984

130-
$childrenInFilter = array_intersect($productsFilter, $children);
131-
if (count($childrenInFilter) > 1) {
132-
$childrenInFilterArray = array_values($childrenInFilter);
133-
$childrenCount = count($childrenInFilterArray);
134-
for ($i = 1; $i < $childrenCount; $i++) {
135-
$childrenToRemove[] = $childrenInFilterArray[$i];
85+
$parentValidationResult = isset($productIds[$configurableProductId])
86+
? array_filter($productIds[$configurableProductId])
87+
: [];
88+
$processAllChildren = !$productsFilter || in_array($configurableProductId, $productsFilter);
89+
foreach ($this->childrenProducts[$configurableProductId] as $childrenProductId) {
90+
if ($processAllChildren || in_array($childrenProductId, $productsFilter)) {
91+
$childValidationResult = isset($productIds[$childrenProductId])
92+
? array_filter($productIds[$childrenProductId])
93+
: [];
94+
$productIds[$childrenProductId] = $parentValidationResult + $childValidationResult;
13695
}
13796
}
97+
unset($productIds[$configurableProductId]);
13898
}
13999

140-
return $childrenToRemove;
100+
return $productIds;
141101
}
142102

143103
/**
144-
* Process configurable products and apply parent validation to children
104+
* Check if simple product has previously applied rule.
145105
*
146-
* @param array $productIds
147-
* @param array $productsFilter
148-
* @return array
106+
* @param int $productId
107+
* @return bool
108+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
149109
*/
150-
private function processConfigurableProducts(array $productIds, array $productsFilter): array
110+
private function hasAntecedentRule(int $productId): bool
151111
{
152-
foreach (array_keys($productIds) as $productId) {
153-
if (isset(self::$allConfigurableProductIds[$productId])) {
154-
if (!isset(self::$childrenProducts[$productId])) {
155-
self::$childrenProducts[$productId] = $this->configurable->getChildrenIds($productId)[0];
156-
}
157-
158-
$parentValidationResult = array_filter($productIds[$productId]);
159-
$processAllChildren = !$productsFilter || in_array($productId, $productsFilter);
160-
161-
foreach (self::$childrenProducts[$productId] as $childProductId) {
162-
if ($processAllChildren || in_array($childProductId, $productsFilter)) {
163-
$childValidationResult = isset($productIds[$childProductId])
164-
? array_filter($productIds[$childProductId])
165-
: [];
166-
$productIds[$childProductId] = $parentValidationResult + $childValidationResult;
167-
}
168-
}
169-
unset($productIds[$productId]);
112+
foreach ($this->childrenProducts as $parent => $children) {
113+
if (in_array($productId, $children)) {
114+
return true;
170115
}
171116
}
172117

173-
return $productIds;
174-
}
175-
176-
/**
177-
* Load all configurable product IDs at once
178-
*
179-
* @return array
180-
*/
181-
private function loadAllConfigurableProductIds(): array
182-
{
183-
$connection = $this->resourceConnection->getConnection();
184-
$select = $connection->select()
185-
->from(
186-
['e' => $this->resourceConnection->getTableName('catalog_product_entity')],
187-
['entity_id']
188-
)
189-
->where('e.type_id = ?', 'configurable');
190-
191-
$result = $connection->fetchCol($select);
192-
193-
return array_flip($result);
118+
return false;
194119
}
195120
}

0 commit comments

Comments
 (0)