Skip to content

Commit 9ab6691

Browse files
committed
Merge branch 'ACP2E-2652' of https://github.com/magento-l3/magento2ce into PR-01-26-2024
2 parents 01a525c + 4c9b323 commit 9ab6691

File tree

20 files changed

+1092
-169
lines changed

20 files changed

+1092
-169
lines changed

app/code/Magento/Catalog/Model/Indexer/Product/Full.php

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
namespace Magento\Catalog\Model\Indexer\Product;
88

9+
use Magento\Framework\App\ObjectManager;
910
use Magento\Framework\Indexer\ActionInterface;
11+
use Magento\Framework\Indexer\ConfigInterface;
1012
use Magento\Framework\Indexer\IndexerRegistry;
1113

1214
/**
@@ -24,26 +26,35 @@ class Full implements ActionInterface
2426
*/
2527
private $indexerList;
2628

29+
/**
30+
* @var ConfigInterface
31+
*/
32+
private $config;
33+
2734
/**
2835
* Initialize dependencies
2936
*
3037
* @param IndexerRegistry $indexerRegistry
3138
* @param string[] $indexerList
39+
* @param ConfigInterface|null $config
3240
*/
3341
public function __construct(
3442
IndexerRegistry $indexerRegistry,
35-
array $indexerList
43+
array $indexerList,
44+
?ConfigInterface $config = null
3645
) {
3746
$this->indexerRegistry = $indexerRegistry;
3847
$this->indexerList = $indexerList;
48+
$this->config = $config
49+
?? ObjectManager::getInstance()->get(ConfigInterface::class);
3950
}
4051

4152
/**
42-
* {@inheritdoc}
53+
* @inheritdoc
4354
*/
4455
public function executeFull()
4556
{
46-
foreach ($this->indexerList as $indexerName) {
57+
foreach ($this->getIndexerList() as $indexerName) {
4758
$indexer = $this->indexerRegistry->get($indexerName);
4859
if (!$indexer->isScheduled()) {
4960
$indexer->reindexAll();
@@ -52,12 +63,12 @@ public function executeFull()
5263
}
5364

5465
/**
55-
* {@inheritdoc}
66+
* @inheritdoc
5667
*/
5768
public function executeList(array $ids)
5869
{
5970
if (!empty($ids)) {
60-
foreach ($this->indexerList as $indexerName) {
71+
foreach ($this->getIndexerList() as $indexerName) {
6172
$indexer = $this->indexerRegistry->get($indexerName);
6273
if (!$indexer->isScheduled()) {
6374
$indexer->reindexList($ids);
@@ -67,17 +78,34 @@ public function executeList(array $ids)
6778
}
6879

6980
/**
70-
* {@inheritDoc}
81+
* @inheritDoc
7182
*/
7283
public function executeRow($id)
7384
{
7485
if (!empty($id)) {
75-
foreach ($this->indexerList as $indexerName) {
86+
foreach ($this->getIndexerList() as $indexerName) {
7687
$indexer = $this->indexerRegistry->get($indexerName);
7788
if (!$indexer->isScheduled()) {
7889
$indexer->reindexRow($id);
7990
}
8091
}
8192
}
8293
}
94+
95+
/**
96+
* Returns indexers in the order according to dependency tree
97+
*
98+
* @return array
99+
*/
100+
private function getIndexerList(): array
101+
{
102+
$indexers = [];
103+
foreach (array_keys($this->config->getIndexers()) as $indexerId) {
104+
if (in_array($indexerId, $this->indexerList, true)) {
105+
$indexers[] = $indexerId;
106+
}
107+
}
108+
109+
return $indexers;
110+
}
83111
}

app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\Catalog\Test\Unit\Model\Indexer\Product;
99

1010
use Magento\Catalog\Model\Indexer\Product\Full;
11+
use Magento\Framework\Indexer\ConfigInterface;
1112
use Magento\Framework\Indexer\IndexerInterface;
1213
use Magento\Framework\Indexer\IndexerRegistry;
1314
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
@@ -31,46 +32,104 @@ class FullTest extends TestCase
3132
*/
3233
private $full;
3334

35+
/**
36+
* @var string[]
37+
*/
38+
private $indexerList;
39+
40+
/**
41+
* @var string[]
42+
*/
43+
private $orderedIndexerList;
44+
45+
/**
46+
* @var ConfigInterface|MockObject
47+
*/
48+
private $configMock;
49+
3450
protected function setUp(): void
3551
{
3652
$this->objectManager = new ObjectManager($this);
3753
$this->indexerRegistryMock = $this->createMock(IndexerRegistry::class);
54+
$this->indexerList = ['search_indexer', 'eav_indexer', 'product_indexer', 'stock_indexer', 'invalid'];
55+
$this->orderedIndexerList = [
56+
'eav_indexer',
57+
'product_indexer',
58+
'stock_indexer',
59+
'price_indexer',
60+
'search_indexer'
61+
];
62+
$this->configMock = $this->createMock(ConfigInterface::class);
3863

39-
$this->full = $this->objectManager->getObject(
40-
Full::class,
41-
[
42-
'indexerRegistry' => $this->indexerRegistryMock,
43-
'indexerList' => ['catalog_indexer', 'product_indexer', 'stock_indexer', 'search_indexer']
44-
]
64+
$this->full = new Full(
65+
$this->indexerRegistryMock,
66+
$this->indexerList,
67+
$this->configMock
4568
);
4669
}
4770

4871
public function testExecuteFull()
4972
{
73+
$this->configMock->method('getIndexers')->willReturn(array_flip($this->orderedIndexerList));
5074
$indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false);
5175
$indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false);
5276
$indexerMock->expects($this->exactly(4))->method('reindexAll');
53-
$this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock);
77+
$orderedIndexerList = array_intersect($this->orderedIndexerList, $this->indexerList);
78+
$this->indexerRegistryMock->expects($this->exactly(4))
79+
->method('get')
80+
->with(
81+
// workaround for deprecated method withConsecutive
82+
$this->callback(
83+
static function ($indexerName) use (&$orderedIndexerList) {
84+
return $indexerName === array_shift($orderedIndexerList);
85+
}
86+
)
87+
)
88+
->willReturn($indexerMock);
5489

5590
$this->full->executeFull();
5691
}
5792

5893
public function testExecuteList()
5994
{
95+
$this->configMock->method('getIndexers')->willReturn(array_flip($this->orderedIndexerList));
6096
$indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false);
6197
$indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false);
6298
$indexerMock->expects($this->exactly(4))->method('reindexList')->with([1, 2]);
63-
$this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock);
99+
$orderedIndexerList = array_intersect($this->orderedIndexerList, $this->indexerList);
100+
$this->indexerRegistryMock->expects($this->exactly(4))
101+
->method('get')
102+
->with(
103+
// workaround for deprecated method withConsecutive
104+
$this->callback(
105+
static function ($indexerName) use (&$orderedIndexerList) {
106+
return $indexerName === array_shift($orderedIndexerList);
107+
}
108+
)
109+
)
110+
->willReturn($indexerMock);
64111

65112
$this->full->executeList([1, 2]);
66113
}
67114

68115
public function testExecuteRow()
69116
{
117+
$this->configMock->method('getIndexers')->willReturn(array_flip($this->orderedIndexerList));
70118
$indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false);
71119
$indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false);
72120
$indexerMock->expects($this->exactly(4))->method('reindexRow')->with(1);
73-
$this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock);
121+
$orderedIndexerList = array_intersect($this->orderedIndexerList, $this->indexerList);
122+
$this->indexerRegistryMock->expects($this->exactly(4))
123+
->method('get')
124+
->with(
125+
// workaround for deprecated method withConsecutive
126+
$this->callback(
127+
static function ($indexerName) use (&$orderedIndexerList) {
128+
return $indexerName === array_shift($orderedIndexerList);
129+
}
130+
)
131+
)
132+
->willReturn($indexerMock);
74133

75134
$this->full->executeRow(1);
76135
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\CatalogRule\Model\Indexer\Rule;
20+
21+
use Magento\CatalogRule\Model\ResourceModel\Rule as RuleResourceModel;
22+
use Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory;
23+
use Magento\CatalogRule\Model\Rule;
24+
25+
class GetAffectedProductIds
26+
{
27+
/**
28+
* @param CollectionFactory $ruleCollectionFactory
29+
* @param RuleResourceModel $ruleResourceModel
30+
*/
31+
public function __construct(
32+
private readonly CollectionFactory $ruleCollectionFactory,
33+
private readonly RuleResourceModel $ruleResourceModel
34+
) {
35+
}
36+
37+
/**
38+
* Get affected product ids by rule ids
39+
*
40+
* @param array $ids
41+
* @return array
42+
*/
43+
public function execute(array $ids): array
44+
{
45+
$productIds = $this->ruleResourceModel->getProductIdsByRuleIds($ids);
46+
$rules = $this->ruleCollectionFactory->create()
47+
->addFieldToFilter('rule_id', ['in' => array_map('intval', $ids)]);
48+
foreach ($rules as $rule) {
49+
/** @var Rule $rule */
50+
array_push($productIds, ...array_keys($rule->getMatchingProductIds()));
51+
}
52+
return array_values(array_unique($productIds));
53+
}
54+
}

app/code/Magento/CatalogRule/Model/Indexer/Rule/RuleProductIndexer.php

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,63 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\CatalogRule\Model\Indexer\Rule;
78

89
use Magento\CatalogRule\Model\Indexer\AbstractIndexer;
10+
use Magento\CatalogRule\Model\Indexer\IndexBuilder;
11+
use Magento\CatalogRule\Model\Indexer\Product\ProductRuleProcessor;
12+
use Magento\Framework\App\ObjectManager;
13+
use Magento\Framework\Event\ManagerInterface;
914

1015
class RuleProductIndexer extends AbstractIndexer
1116
{
1217
/**
13-
* {@inheritdoc}
14-
*
15-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
18+
* @var ProductRuleProcessor
19+
*/
20+
private $productRuleProcessor;
21+
22+
/**
23+
* @var GetAffectedProductIds
24+
*/
25+
private $getAffectedProductIds;
26+
27+
/**
28+
* @param IndexBuilder $indexBuilder
29+
* @param ManagerInterface $eventManager
30+
* @param ProductRuleProcessor|null $productRuleProcessor
31+
* @param GetAffectedProductIds|null $getAffectedProductIds
32+
*/
33+
public function __construct(
34+
IndexBuilder $indexBuilder,
35+
ManagerInterface $eventManager,
36+
?ProductRuleProcessor $productRuleProcessor = null,
37+
?GetAffectedProductIds $getAffectedProductIds = null
38+
) {
39+
$this->productRuleProcessor = $productRuleProcessor
40+
?? ObjectManager::getInstance()->get(ProductRuleProcessor::class);
41+
$this->getAffectedProductIds = $getAffectedProductIds
42+
?? ObjectManager::getInstance()->get(GetAffectedProductIds::class);
43+
parent::__construct($indexBuilder, $eventManager);
44+
}
45+
46+
/**
47+
* @inheritdoc
1648
*/
1749
protected function doExecuteList($ids)
1850
{
19-
$this->indexBuilder->reindexFull();
20-
$this->getCacheContext()->registerTags($this->getIdentities());
51+
$affectedProductIds = $this->getAffectedProductIds->execute($ids);
52+
if (!$affectedProductIds) {
53+
return;
54+
}
55+
$this->productRuleProcessor->reindexList($affectedProductIds, true);
2156
}
2257

2358
/**
24-
* {@inheritdoc}
25-
*
26-
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
59+
* @inheritdoc
2760
*/
2861
protected function doExecuteRow($id)
2962
{
30-
$this->indexBuilder->reindexFull();
63+
$this->doExecuteList([$id]);
3164
}
3265
}

0 commit comments

Comments
 (0)