Skip to content
This repository was archived by the owner on Apr 29, 2019. It is now read-only.

Commit d56861a

Browse files
committed
MAGETWO-71554: Category edit performance issue - for 2.2
1 parent b888131 commit d56861a

File tree

8 files changed

+215
-97
lines changed

8 files changed

+215
-97
lines changed

app/code/Magento/Catalog/Model/Category.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
* @method Category setUrlPath(string $urlPath)
2929
* @method Category getSkipDeleteChildren()
3030
* @method Category setSkipDeleteChildren(boolean $value)
31+
* @method Category setChangedProductIds(array $categoryIds) Set products ids that inserted or deleted for category
32+
* @method array getChangedProductIds() Get products ids that inserted or deleted for category
3133
*
3234
* @SuppressWarnings(PHPMD.LongVariable)
3335
* @SuppressWarnings(PHPMD.ExcessivePublicCount)

app/code/Magento/Catalog/Model/ResourceModel/Category.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@ protected function _saveCategoryProducts($category)
423423
'catalog_category_change_products',
424424
['category' => $category, 'product_ids' => $productIds]
425425
);
426+
427+
$category->setChangedProductIds($productIds);
426428
}
427429

428430
if (!empty($insert) || !empty($update) || !empty($delete)) {

app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\CatalogRule\Model\Rule;
1212
use Magento\Framework\App\ObjectManager;
1313
use Magento\Framework\Pricing\PriceCurrencyInterface;
14+
use Magento\CatalogRule\Model\Indexer\IndexBuilder\ProductLoader;
1415

1516
/**
1617
* @api
@@ -135,6 +136,11 @@ class IndexBuilder
135136
*/
136137
private $activeTableSwitcher;
137138

139+
/**
140+
* @var ProductLoader
141+
*/
142+
private $productLoader;
143+
138144
/**
139145
* @param RuleCollectionFactory $ruleCollectionFactory
140146
* @param PriceCurrencyInterface $priceCurrency
@@ -153,6 +159,7 @@ class IndexBuilder
153159
* @param \Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice|null $reindexRuleProductPrice
154160
* @param \Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor|null $pricesPersistor
155161
* @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
162+
* @param ProductLoader|null $productLoader
156163
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
157164
*/
158165
public function __construct(
@@ -172,7 +179,8 @@ public function __construct(
172179
\Magento\CatalogRule\Model\Indexer\RuleProductsSelectBuilder $ruleProductsSelectBuilder = null,
173180
\Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice $reindexRuleProductPrice = null,
174181
\Magento\CatalogRule\Model\Indexer\RuleProductPricesPersistor $pricesPersistor = null,
175-
\Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null
182+
\Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null,
183+
ProductLoader $productLoader = null
176184
) {
177185
$this->resource = $resource;
178186
$this->connection = $resource->getConnection();
@@ -207,6 +215,8 @@ public function __construct(
207215
$this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
208216
\Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
209217
);
218+
$this->productLoader = $productLoader ?:
219+
ObjectManager::getInstance()->get(ProductLoader::class);
210220
}
211221

212222
/**
@@ -251,9 +261,10 @@ protected function doReindexByIds($ids)
251261
{
252262
$this->cleanByIds($ids);
253263

264+
$products = $this->productLoader->getProducts($ids);
254265
foreach ($this->getActiveRules() as $rule) {
255-
foreach ($ids as $productId) {
256-
$this->applyRule($rule, $this->getProduct($productId));
266+
foreach ($products as $product) {
267+
$this->applyRule($rule, $product);
257268
}
258269
}
259270
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\CatalogRule\Model\Indexer\IndexBuilder;
7+
8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Framework\Api\SearchCriteriaBuilder;
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
12+
/**
13+
* Product loader that gets products by ids via product repository
14+
*/
15+
class ProductLoader
16+
{
17+
/**
18+
* @var ProductRepositoryInterface
19+
*/
20+
private $productRepository;
21+
22+
/**
23+
* @var SearchCriteriaBuilder
24+
*/
25+
private $searchCriteriaBuilder;
26+
27+
/**
28+
* @param ProductRepositoryInterface $productRepository
29+
* @param SearchCriteriaBuilder $searchCriteriaBuilder
30+
*/
31+
public function __construct(
32+
ProductRepositoryInterface $productRepository,
33+
SearchCriteriaBuilder $searchCriteriaBuilder
34+
) {
35+
$this->productRepository = $productRepository;
36+
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
37+
}
38+
39+
/**
40+
* Get products by ids
41+
*
42+
* @param array $productIds
43+
* @return ProductInterface[]
44+
*/
45+
public function getProducts($productIds)
46+
{
47+
$this->searchCriteriaBuilder->addFilter('entity_id', $productIds, 'in');
48+
$searchCriteria = $this->searchCriteriaBuilder->create();
49+
$products = $this->productRepository->getList($searchCriteria)->getItems();
50+
51+
return $products;
52+
}
53+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\CatalogRule\Test\Unit\Model\Indexer\IndexBuilder;
8+
9+
use Magento\CatalogRule\Model\Indexer\IndexBuilder\ProductLoader;
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Framework\Api\SearchCriteriaBuilder;
12+
use Magento\Catalog\Api\Data\ProductSearchResultsInterface;
13+
use Magento\Catalog\Model\Product;
14+
use Magento\Framework\Api\SearchCriteria;
15+
16+
class ProductLoaderTest extends \PHPUnit\Framework\TestCase
17+
{
18+
/**
19+
* @var ProductLoader
20+
*/
21+
protected $productLoader;
22+
23+
/**
24+
* @var ProductRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
25+
*/
26+
private $productRepository;
27+
28+
/**
29+
* @var SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject
30+
*/
31+
private $searchCriteriaBuilder;
32+
33+
/**
34+
* @var ProductSearchResultsInterface|\PHPUnit_Framework_MockObject_MockObject
35+
*/
36+
private $productSearchResultsInterface;
37+
38+
/**
39+
* @var \Magento\Framework\Api\SearchCriteria|\PHPUnit_Framework_MockObject_MockObject
40+
*/
41+
private $searchCriteria;
42+
43+
/**
44+
* @var Product|\PHPUnit_Framework_MockObject_MockObject
45+
*/
46+
protected $product;
47+
48+
/**
49+
* Set up test
50+
*
51+
* @return void
52+
*/
53+
protected function setUp()
54+
{
55+
$this->productRepository = $this->getMockBuilder(ProductRepositoryInterface::class)
56+
->disableOriginalConstructor()
57+
->getMock();
58+
$this->searchCriteriaBuilder = $this->getMockBuilder(SearchCriteriaBuilder::class)
59+
->disableOriginalConstructor()
60+
->getMock();
61+
$this->productSearchResultsInterface = $this->getMockBuilder(ProductSearchResultsInterface::class)
62+
->disableOriginalConstructor()
63+
->getMockForAbstractClass();
64+
$this->searchCriteria = $this->getMockBuilder(SearchCriteria::class)
65+
->disableOriginalConstructor()
66+
->getMock();
67+
$this->product = $this->getMockBuilder(Product::class)
68+
->disableOriginalConstructor()
69+
->getMock();
70+
71+
$this->productLoader = new ProductLoader(
72+
$this->productRepository,
73+
$this->searchCriteriaBuilder
74+
);
75+
}
76+
77+
public function testGetProducts()
78+
{
79+
$this->searchCriteriaBuilder->expects($this->once())
80+
->method('addFilter')
81+
->willReturnSelf();
82+
$this->searchCriteriaBuilder->expects($this->once())
83+
->method('create')
84+
->willReturn($this->searchCriteria);
85+
$this->productRepository->expects($this->once())
86+
->method('getList')
87+
->with($this->searchCriteria)
88+
->willReturn($this->productSearchResultsInterface);
89+
$iterator = new \ArrayIterator([$this->product]);
90+
$this->productSearchResultsInterface->expects($this->once())
91+
->method('getItems')
92+
->willReturn($iterator);
93+
94+
$this->assertSame($iterator, $this->productLoader->getProducts([1]));
95+
}
96+
}

app/code/Magento/CatalogRule/Test/Unit/Model/Indexer/IndexBuilderTest.php

Lines changed: 14 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66

77
namespace Magento\CatalogRule\Test\Unit\Model\Indexer;
88

9+
use Magento\CatalogRule\Model\Indexer\IndexBuilder\ProductLoader;
910
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
10-
use Magento\Catalog\Api\ProductRepositoryInterface;
11-
use Magento\Framework\Api\SearchCriteriaBuilder;
12-
use Magento\Catalog\Api\Data\ProductSearchResultsInterface;
13-
use Magento\Framework\Api\SearchCriteria;
1411

1512
/**
1613
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -118,26 +115,6 @@ class IndexBuilderTest extends \PHPUnit\Framework\TestCase
118115
*/
119116
protected $backend;
120117

121-
/**
122-
* @var ProductRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
123-
*/
124-
private $productRepository;
125-
126-
/**
127-
* @var SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject
128-
*/
129-
private $searchCriteriaBuilder;
130-
131-
/**
132-
* @var ProductSearchResultsInterface|\PHPUnit_Framework_MockObject_MockObject
133-
*/
134-
private $productSearchResults;
135-
136-
/**
137-
* @var SearchCriteria|\PHPUnit_Framework_MockObject_MockObject
138-
*/
139-
private $searchCriteria;
140-
141118
/**
142119
* @var \PHPUnit_Framework_MockObject_MockObject
143120
*/
@@ -148,6 +125,11 @@ class IndexBuilderTest extends \PHPUnit\Framework\TestCase
148125
*/
149126
private $reindexRuleGroupWebsite;
150127

128+
/**
129+
* @var ProductLoader|\PHPUnit_Framework_MockObject_MockObject
130+
*/
131+
private $productLoader;
132+
151133
/**
152134
* Set up test
153135
*
@@ -211,19 +193,7 @@ protected function setUp()
211193
$this->rules->expects($this->any())->method('validate')->with($this->product)->willReturn(true);
212194
$this->attribute->expects($this->any())->method('getBackend')->will($this->returnValue($this->backend));
213195
$this->productFactory->expects($this->any())->method('create')->will($this->returnValue($this->product));
214-
215-
$this->productRepository = $this->getMockBuilder(ProductRepositoryInterface::class)
216-
->disableOriginalConstructor()
217-
->getMock();
218-
$this->searchCriteriaBuilder = $this->getMockBuilder(SearchCriteriaBuilder::class)
219-
->disableOriginalConstructor()
220-
->getMock();
221-
222-
$this->productSearchResults = $this->getMockBuilder(ProductSearchResultsInterface::class)
223-
->disableOriginalConstructor()
224-
->getMockForAbstractClass();
225-
226-
$this->searchCriteria = $this->getMockBuilder(SearchCriteria::class)
196+
$this->productLoader = $this->getMockBuilder(ProductLoader::class)
227197
->disableOriginalConstructor()
228198
->getMock();
229199

@@ -240,19 +210,18 @@ protected function setUp()
240210
'dateTime' => $this->dateTime,
241211
'productFactory' => $this->productFactory,
242212
1000,
243-
'productRepository' => $this->productRepository,
244-
'searchCriteriaBuilder' => $this->searchCriteriaBuilder
213+
'productLoader' => $this->productLoader
245214
]
246215
);
247216

248217
$this->reindexRuleProductPrice =
249218
$this->getMockBuilder(\Magento\CatalogRule\Model\Indexer\ReindexRuleProductPrice::class)
250-
->disableOriginalConstructor()
251-
->getMock();
219+
->disableOriginalConstructor()
220+
->getMock();
252221
$this->reindexRuleGroupWebsite =
253222
$this->getMockBuilder(\Magento\CatalogRule\Model\Indexer\ReindexRuleGroupWebsite::class)
254-
->disableOriginalConstructor()
255-
->getMock();
223+
->disableOriginalConstructor()
224+
->getMock();
256225
$this->setProperties($this->indexBuilder, [
257226
'metadataPool' => $this->metadataPool,
258227
'reindexRuleProductPrice' => $this->reindexRuleProductPrice,
@@ -288,18 +257,8 @@ public function testUpdateCatalogRuleGroupWebsiteData()
288257
->will($this->returnValue($backendModelMock));
289258

290259
$iterator = new \ArrayIterator([$this->product]);
291-
$this->searchCriteriaBuilder->expects($this->once())
292-
->method('addFilter')
293-
->willReturnSelf();
294-
$this->searchCriteriaBuilder->expects($this->once())
295-
->method('create')
296-
->willReturn($this->searchCriteria);
297-
$this->productRepository->expects($this->once())
298-
->method('getList')
299-
->with($this->searchCriteria)
300-
->willReturn($this->productSearchResults);
301-
$this->productSearchResults->expects($this->once())
302-
->method('getItems')
260+
$this->productLoader->expects($this->once())
261+
->method('getProducts')
303262
->willReturn($iterator);
304263

305264
$this->reindexRuleProductPrice->expects($this->once())->method('execute')->willReturn(true);

app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
8585
$mapsGenerated = false;
8686
if ($category->dataHasChangedFor('url_key')
8787
|| $category->dataHasChangedFor('is_anchor')
88-
|| $category->getIsChangedProductList()
88+
|| $category->getChangedProductIds()
8989
) {
9090
if ($category->dataHasChangedFor('url_key')) {
9191
$categoryUrlRewriteResult = $this->categoryUrlRewriteGenerator->generate($category);

0 commit comments

Comments
 (0)