Skip to content

Commit 308dd99

Browse files
committed
Merge remote-tracking branch 'origin/MAGETWO-72312' into PANDA-FIXES-2.1
2 parents acfceb8 + 97b753c commit 308dd99

File tree

21 files changed

+982
-108
lines changed

21 files changed

+982
-108
lines changed

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ public function getParentId()
704704
return $parentId;
705705
}
706706
$parentIds = $this->getParentIds();
707-
return intval(array_pop($parentIds));
707+
return (int)array_pop($parentIds);
708708
}
709709

710710
/**
@@ -938,8 +938,11 @@ public function getAnchorsAbove()
938938
*/
939939
public function getProductCount()
940940
{
941-
$count = $this->_getResource()->getProductCount($this);
942-
$this->setData(self::KEY_PRODUCT_COUNT, $count);
941+
if (!$this->hasData(self::KEY_PRODUCT_COUNT)) {
942+
$count = $this->_getResource()->getProductCount($this);
943+
$this->setData(self::KEY_PRODUCT_COUNT, $count);
944+
}
945+
943946
return $this->getData(self::KEY_PRODUCT_COUNT);
944947
}
945948

app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php

Lines changed: 112 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@
88

99
namespace Magento\Catalog\Model\Indexer\Category\Product;
1010

11-
use Magento\Framework\DB\Query\Generator as QueryGenerator;
11+
use Magento\Catalog\Api\Data\ProductInterface;
12+
use Magento\Catalog\Model\Product;
13+
use Magento\Framework\App\ObjectManager;
1214
use Magento\Framework\App\ResourceConnection;
15+
use Magento\Framework\DB\Query\Generator as QueryGenerator;
16+
use Magento\Framework\DB\Select;
1317
use Magento\Framework\EntityManager\MetadataPool;
18+
use Magento\Store\Model\Store;
1419

1520
/**
1621
* Class AbstractAction
@@ -41,21 +46,21 @@ abstract class AbstractAction
4146
/**
4247
* Cached non anchor categories select by store id
4348
*
44-
* @var \Magento\Framework\DB\Select[]
49+
* @var Select[]
4550
*/
4651
protected $nonAnchorSelects = [];
4752

4853
/**
4954
* Cached anchor categories select by store id
5055
*
51-
* @var \Magento\Framework\DB\Select[]
56+
* @var Select[]
5257
*/
5358
protected $anchorSelects = [];
5459

5560
/**
5661
* Cached all product select by store id
5762
*
58-
* @var \Magento\Framework\DB\Select[]
63+
* @var Select[]
5964
*/
6065
protected $productsSelects = [];
6166

@@ -113,19 +118,21 @@ abstract class AbstractAction
113118
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
114119
* @param \Magento\Catalog\Model\Config $config
115120
* @param QueryGenerator $queryGenerator
121+
* @param MetadataPool|null $metadataPool
116122
*/
117123
public function __construct(
118124
\Magento\Framework\App\ResourceConnection $resource,
119125
\Magento\Store\Model\StoreManagerInterface $storeManager,
120126
\Magento\Catalog\Model\Config $config,
121-
QueryGenerator $queryGenerator = null
127+
QueryGenerator $queryGenerator = null,
128+
MetadataPool $metadataPool = null
122129
) {
123130
$this->resource = $resource;
124131
$this->connection = $resource->getConnection();
125132
$this->storeManager = $storeManager;
126133
$this->config = $config;
127-
$this->queryGenerator = $queryGenerator ?: \Magento\Framework\App\ObjectManager::getInstance()
128-
->get(QueryGenerator::class);
134+
$this->queryGenerator = $queryGenerator ?: ObjectManager::getInstance()->get(QueryGenerator::class);
135+
$this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class);
129136
}
130137

131138
/**
@@ -179,9 +186,9 @@ protected function getMainTable()
179186
*/
180187
protected function getMainTmpTable()
181188
{
182-
return $this->useTempTable ? $this->getTable(
183-
self::MAIN_INDEX_TABLE . self::TEMPORARY_TABLE_SUFFIX
184-
) : $this->getMainTable();
189+
return $this->useTempTable
190+
? $this->getTable(self::MAIN_INDEX_TABLE . self::TEMPORARY_TABLE_SUFFIX)
191+
: $this->getMainTable();
185192
}
186193

187194
/**
@@ -209,24 +216,25 @@ protected function getPathFromCategoryId($categoryId)
209216
/**
210217
* Retrieve select for reindex products of non anchor categories
211218
*
212-
* @param \Magento\Store\Model\Store $store
213-
* @return \Magento\Framework\DB\Select
219+
* @param Store $store
220+
* @return Select
221+
* @throws \Exception when metadata not found for ProductInterface
214222
*/
215-
protected function getNonAnchorCategoriesSelect(\Magento\Store\Model\Store $store)
223+
protected function getNonAnchorCategoriesSelect(Store $store)
216224
{
217225
if (!isset($this->nonAnchorSelects[$store->getId()])) {
218226
$statusAttributeId = $this->config->getAttribute(
219-
\Magento\Catalog\Model\Product::ENTITY,
227+
Product::ENTITY,
220228
'status'
221229
)->getId();
222230
$visibilityAttributeId = $this->config->getAttribute(
223-
\Magento\Catalog\Model\Product::ENTITY,
231+
Product::ENTITY,
224232
'visibility'
225233
)->getId();
226234

227235
$rootPath = $this->getPathFromCategoryId($store->getRootCategoryId());
228236

229-
$metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
237+
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
230238
$linkField = $metadata->getLinkField();
231239
$select = $this->connection->select()->from(
232240
['cc' => $this->getTable('catalog_category_entity')],
@@ -295,12 +303,65 @@ protected function getNonAnchorCategoriesSelect(\Magento\Store\Model\Store $stor
295303
]
296304
);
297305

306+
$this->addFilteringByChildProductsToSelect($select, $store);
307+
298308
$this->nonAnchorSelects[$store->getId()] = $select;
299309
}
300310

301311
return $this->nonAnchorSelects[$store->getId()];
302312
}
303313

314+
/**
315+
* Add filtering by child products to select
316+
*
317+
* It's used for correct handling of composite products.
318+
* This method makes assumption that select already joins `catalog_product_entity` as `cpe`.
319+
*
320+
* @param Select $select
321+
* @param Store $store
322+
* @return void
323+
* @throws \Exception when metadata not found for ProductInterface
324+
*/
325+
private function addFilteringByChildProductsToSelect(Select $select, Store $store)
326+
{
327+
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
328+
$linkField = $metadata->getLinkField();
329+
330+
$statusAttributeId = $this->config->getAttribute(Product::ENTITY, 'status')->getId();
331+
332+
$select->joinLeft(
333+
['relation' => $this->getTable('catalog_product_relation')],
334+
'cpe.' . $linkField . ' = relation.parent_id',
335+
[]
336+
)->joinLeft(
337+
['relation_product_entity' => $this->getTable('catalog_product_entity')],
338+
'relation.child_id = relation_product_entity.entity_id',
339+
[]
340+
)->joinLeft(
341+
['child_cpsd' => $this->getTable('catalog_product_entity_int')],
342+
'child_cpsd.' . $linkField . ' = '. 'relation_product_entity.' . $linkField
343+
. ' AND child_cpsd.store_id = 0'
344+
. ' AND child_cpsd.attribute_id = ' . $statusAttributeId,
345+
[]
346+
)->joinLeft(
347+
['child_cpss' => $this->getTable('catalog_product_entity_int')],
348+
'child_cpss.' . $linkField . ' = '. 'relation_product_entity.' . $linkField . ''
349+
. ' AND child_cpss.attribute_id = child_cpsd.attribute_id'
350+
. ' AND child_cpss.store_id = ' . $store->getId(),
351+
[]
352+
)->where(
353+
'relation.child_id IS NULL OR '
354+
. $this->connection->getIfNullSql('child_cpss.value', 'child_cpsd.value') . ' = ?',
355+
\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
356+
)->group(
357+
[
358+
'cc.entity_id',
359+
'ccp.product_id',
360+
'visibility'
361+
]
362+
);
363+
}
364+
304365
/**
305366
* Check whether select ranging is needed
306367
*
@@ -314,16 +375,13 @@ protected function isRangingNeeded()
314375
/**
315376
* Return selects cut by min and max.
316377
*
317-
* @param \Magento\Framework\DB\Select $select
378+
* @param Select $select
318379
* @param string $field
319380
* @param int $range
320-
* @return \Magento\Framework\DB\Select[]
381+
* @return Select[]
321382
*/
322-
protected function prepareSelectsByRange(
323-
\Magento\Framework\DB\Select $select,
324-
$field,
325-
$range = self::RANGE_CATEGORY_STEP
326-
) {
383+
protected function prepareSelectsByRange(Select $select, $field, $range = self::RANGE_CATEGORY_STEP)
384+
{
327385
if ($this->isRangingNeeded()) {
328386
$iterator = $this->queryGenerator->generate(
329387
$field,
@@ -346,10 +404,10 @@ protected function prepareSelectsByRange(
346404
/**
347405
* Reindex products of non anchor categories
348406
*
349-
* @param \Magento\Store\Model\Store $store
407+
* @param Store $store
350408
* @return void
351409
*/
352-
protected function reindexNonAnchorCategories(\Magento\Store\Model\Store $store)
410+
protected function reindexNonAnchorCategories(Store $store)
353411
{
354412
$selects = $this->prepareSelectsByRange($this->getNonAnchorCategoriesSelect($store), 'entity_id');
355413
foreach ($selects as $select) {
@@ -367,43 +425,44 @@ protected function reindexNonAnchorCategories(\Magento\Store\Model\Store $store)
367425
/**
368426
* Check if anchor select isset
369427
*
370-
* @param \Magento\Store\Model\Store $store
428+
* @param Store $store
371429
* @return bool
372430
*/
373-
protected function hasAnchorSelect(\Magento\Store\Model\Store $store)
431+
protected function hasAnchorSelect(Store $store)
374432
{
375433
return isset($this->anchorSelects[$store->getId()]);
376434
}
377435

378436
/**
379437
* Create anchor select
380438
*
381-
* @param \Magento\Store\Model\Store $store
382-
* @return \Magento\Framework\DB\Select
439+
* @param Store $store
440+
* @return Select
441+
* @throws \Exception when metadata not found for ProductInterface or CategoryInterface
383442
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
384443
*/
385-
protected function createAnchorSelect(\Magento\Store\Model\Store $store)
444+
protected function createAnchorSelect(Store $store)
386445
{
387446
$isAnchorAttributeId = $this->config->getAttribute(
388447
\Magento\Catalog\Model\Category::ENTITY,
389448
'is_anchor'
390449
)->getId();
391-
$statusAttributeId = $this->config->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'status')->getId();
450+
$statusAttributeId = $this->config->getAttribute(Product::ENTITY, 'status')->getId();
392451
$visibilityAttributeId = $this->config->getAttribute(
393-
\Magento\Catalog\Model\Product::ENTITY,
452+
Product::ENTITY,
394453
'visibility'
395454
)->getId();
396455
$rootCatIds = explode('/', $this->getPathFromCategoryId($store->getRootCategoryId()));
397456
array_pop($rootCatIds);
398457

399458
$temporaryTreeTable = $this->makeTempCategoryTreeIndex();
400459

401-
$productMetadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
402-
$categoryMetadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\CategoryInterface::class);
460+
$productMetadata = $this->metadataPool->getMetadata(ProductInterface::class);
461+
$categoryMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\CategoryInterface::class);
403462
$productLinkField = $productMetadata->getLinkField();
404463
$categoryLinkField = $categoryMetadata->getLinkField();
405464

406-
return $this->connection->select()->from(
465+
$select = $this->connection->select()->from(
407466
['cc' => $this->getTable('catalog_category_entity')],
408467
[]
409468
)->joinInner(
@@ -485,6 +544,10 @@ protected function createAnchorSelect(\Magento\Store\Model\Store $store)
485544
'visibility' => new \Zend_Db_Expr($this->connection->getIfNullSql('cpvs.value', 'cpvd.value')),
486545
]
487546
);
547+
548+
$this->addFilteringByChildProductsToSelect($select, $store);
549+
550+
return $select;
488551
}
489552

490553
/**
@@ -576,10 +639,10 @@ protected function fillTempCategoryTreeIndex($temporaryName)
576639
/**
577640
* Retrieve select for reindex products of non anchor categories
578641
*
579-
* @param \Magento\Store\Model\Store $store
580-
* @return \Magento\Framework\DB\Select
642+
* @param Store $store
643+
* @return Select
581644
*/
582-
protected function getAnchorCategoriesSelect(\Magento\Store\Model\Store $store)
645+
protected function getAnchorCategoriesSelect(Store $store)
583646
{
584647
if (!$this->hasAnchorSelect($store)) {
585648
$this->anchorSelects[$store->getId()] = $this->createAnchorSelect($store);
@@ -590,10 +653,10 @@ protected function getAnchorCategoriesSelect(\Magento\Store\Model\Store $store)
590653
/**
591654
* Reindex products of anchor categories
592655
*
593-
* @param \Magento\Store\Model\Store $store
656+
* @param Store $store
594657
* @return void
595658
*/
596-
protected function reindexAnchorCategories(\Magento\Store\Model\Store $store)
659+
protected function reindexAnchorCategories(Store $store)
597660
{
598661
$selects = $this->prepareSelectsByRange($this->getAnchorCategoriesSelect($store), 'entity_id');
599662

@@ -612,22 +675,23 @@ protected function reindexAnchorCategories(\Magento\Store\Model\Store $store)
612675
/**
613676
* Get select for all products
614677
*
615-
* @param \Magento\Store\Model\Store $store
616-
* @return \Magento\Framework\DB\Select
678+
* @param Store $store
679+
* @return Select
680+
* @throws \Exception when metadata not found for ProductInterface
617681
*/
618-
protected function getAllProducts(\Magento\Store\Model\Store $store)
682+
protected function getAllProducts(Store $store)
619683
{
620684
if (!isset($this->productsSelects[$store->getId()])) {
621685
$statusAttributeId = $this->config->getAttribute(
622-
\Magento\Catalog\Model\Product::ENTITY,
686+
Product::ENTITY,
623687
'status'
624688
)->getId();
625689
$visibilityAttributeId = $this->config->getAttribute(
626-
\Magento\Catalog\Model\Product::ENTITY,
690+
Product::ENTITY,
627691
'visibility'
628692
)->getId();
629693

630-
$metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
694+
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
631695
$linkField = $metadata->getLinkField();
632696

633697
$select = $this->connection->select()->from(
@@ -716,10 +780,10 @@ protected function isIndexRootCategoryNeeded()
716780
/**
717781
* Reindex all products to root category
718782
*
719-
* @param \Magento\Store\Model\Store $store
783+
* @param Store $store
720784
* @return void
721785
*/
722-
protected function reindexRootCategory(\Magento\Store\Model\Store $store)
786+
protected function reindexRootCategory(Store $store)
723787
{
724788
if ($this->isIndexRootCategoryNeeded()) {
725789
$selects = $this->prepareSelectsByRange(
@@ -740,16 +804,4 @@ protected function reindexRootCategory(\Magento\Store\Model\Store $store)
740804
}
741805
}
742806
}
743-
744-
/**
745-
* @return \Magento\Framework\EntityManager\MetadataPool
746-
*/
747-
private function getMetadataPool()
748-
{
749-
if (null === $this->metadataPool) {
750-
$this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
751-
->get('Magento\Framework\EntityManager\MetadataPool');
752-
}
753-
return $this->metadataPool;
754-
}
755807
}

0 commit comments

Comments
 (0)