Skip to content

Commit 9e48a58

Browse files
author
Leonid Poluianov
committed
MC-32792: Get Categories server side API operation to improve in 2.4
1 parent 8ec21ff commit 9e48a58

File tree

1 file changed

+83
-29
lines changed

1 file changed

+83
-29
lines changed

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

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
*/
66
namespace Magento\Catalog\Model\ResourceModel\Category;
77

8+
use Magento\Catalog\Model\Category;
9+
use Magento\Catalog\Model\Product\Visibility;
810
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
911
use Magento\Framework\App\Config\ScopeConfigInterface;
12+
use Magento\Framework\DB\Select;
1013
use Magento\Store\Model\ScopeInterface;
1114

1215
/**
@@ -68,6 +71,11 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
6871
*/
6972
private $scopeConfig;
7073

74+
/**
75+
* @var Visibility
76+
*/
77+
private $catalogProductVisibility;
78+
7179
/**
7280
* Constructor
7381
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
@@ -96,7 +104,8 @@ public function __construct(
96104
\Magento\Framework\Validator\UniversalFactory $universalFactory,
97105
\Magento\Store\Model\StoreManagerInterface $storeManager,
98106
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
99-
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
107+
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null,
108+
Visibility $catalogProductVisibility = null
100109
) {
101110
parent::__construct(
102111
$entityFactory,
@@ -113,6 +122,8 @@ public function __construct(
113122
);
114123
$this->scopeConfig = $scopeConfig ?:
115124
\Magento\Framework\App\ObjectManager::getInstance()->get(ScopeConfigInterface::class);
125+
$this->catalogProductVisibility = $catalogProductVisibility ?:
126+
\Magento\Framework\App\ObjectManager::getInstance()->get(Visibility::class);
116127
}
117128

118129
/**
@@ -122,7 +133,7 @@ public function __construct(
122133
*/
123134
protected function _construct()
124135
{
125-
$this->_init(\Magento\Catalog\Model\Category::class, \Magento\Catalog\Model\ResourceModel\Category::class);
136+
$this->_init(Category::class, \Magento\Catalog\Model\ResourceModel\Category::class);
126137
}
127138

128139
/**
@@ -259,6 +270,7 @@ protected function _loadProductCount()
259270
* @return $this
260271
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
261272
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
273+
* @throws \Magento\Framework\Exception\NoSuchEntityException
262274
*/
263275
public function loadProductCount($items, $countRegular = true, $countAnchor = true)
264276
{
@@ -310,34 +322,14 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr
310322

311323
if ($countAnchor) {
312324
// Retrieve Anchor categories product counts
325+
$categoryIds = array_keys($anchor);
326+
$countSelect = $this->getProductsCountQuery($categoryIds, (bool)$websiteId);
327+
$categoryProductsCount = $this->_conn->fetchPairs($countSelect);
313328
foreach ($anchor as $item) {
314-
if ($allChildren = $item->getAllChildren()) {
315-
$bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
316-
$select = $this->_conn->select();
317-
$select->from(
318-
['main_table' => $this->getProductTable()],
319-
new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
320-
)->joinInner(
321-
['e' => $this->getTable('catalog_category_entity')],
322-
'main_table.category_id=e.entity_id',
323-
[]
324-
)->where(
325-
'(e.entity_id = :entity_id OR e.path LIKE :c_path)'
326-
);
327-
if ($websiteId) {
328-
$select->join(
329-
['w' => $this->getProductWebsiteTable()],
330-
'main_table.product_id = w.product_id',
331-
[]
332-
)->where(
333-
'w.website_id = ?',
334-
$websiteId
335-
);
336-
}
337-
$item->setProductCount((int)$this->_conn->fetchOne($select, $bind));
338-
} else {
339-
$item->setProductCount(0);
340-
}
329+
$productsCount = isset($categoriesProductsCount[$item->getId()])
330+
? (int)$categoryProductsCount[$item->getId()]
331+
: $this->getProductsCountFromCategoryTable($item, $websiteId);
332+
$item->setProductCount($productsCount);
341333
}
342334
}
343335
return $this;
@@ -513,4 +505,66 @@ public function getProductTable()
513505
}
514506
return $this->_productTable;
515507
}
508+
509+
/**
510+
* @param Category $item
511+
* @param string $websiteId
512+
* @return int
513+
*/
514+
private function getProductsCountFromCategoryTable(Category $item, string $websiteId): int
515+
{
516+
$productCount = 0;
517+
518+
if ($item->getAllChildren()) {
519+
$bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
520+
$select = $this->_conn->select();
521+
$select->from(
522+
['main_table' => $this->getProductTable()],
523+
new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
524+
)->joinInner(
525+
['e' => $this->getTable('catalog_category_entity')],
526+
'main_table.category_id=e.entity_id',
527+
[]
528+
)->where(
529+
'(e.entity_id = :entity_id OR e.path LIKE :c_path)'
530+
);
531+
if ($websiteId) {
532+
$select->join(
533+
['w' => $this->getProductWebsiteTable()],
534+
'main_table.product_id = w.product_id',
535+
[]
536+
)->where(
537+
'w.website_id = ?',
538+
$websiteId
539+
);
540+
}
541+
$productCount = (int)$this->_conn->fetchOne($select, $bind);
542+
}
543+
return $productCount;
544+
}
545+
546+
/**
547+
* Get query for retrieve count of products per category
548+
*
549+
* @param array $categoryIds
550+
* @return Select
551+
*/
552+
private function getProductsCountQuery(array $categoryIds, $addVisibilityFilter = true): Select
553+
{
554+
$categoryTable = $this->getTable('catalog_category_product_index');
555+
$select = $this->_conn->select()
556+
->from(
557+
['cat_index' => $categoryTable],
558+
['category_id' => 'cat_index.category_id', 'count' => 'count(cat_index.product_id)']
559+
)
560+
->where('cat_index.category_id in (?)', \array_map('\intval', $categoryIds));
561+
if (true === $addVisibilityFilter) {
562+
$select->where('cat_index.visibility in (?)', $this->catalogProductVisibility->getVisibleInSiteIds());
563+
}
564+
if (count($categoryIds) > 1) {
565+
$select->group('cat_index.category_id');
566+
}
567+
568+
return $select;
569+
}
516570
}

0 commit comments

Comments
 (0)