Skip to content

Commit

Permalink
Merge pull request #5537 from magento-performance/MC-32792
Browse files Browse the repository at this point in the history
Fixed issues:
- MC-32792: Get Categories server side API operation to improve in 2.4
  • Loading branch information
slavvka authored Apr 9, 2020
2 parents c9a246a + 74fe2b5 commit 15dc874
Showing 1 changed file with 87 additions and 29 deletions.
116 changes: 87 additions & 29 deletions app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
*/
namespace Magento\Catalog\Model\ResourceModel\Category;

use Magento\Catalog\Model\Category;
use Magento\Catalog\Model\Product\Visibility;
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\DB\Select;
use Magento\Store\Model\ScopeInterface;

/**
Expand Down Expand Up @@ -68,6 +71,11 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
*/
private $scopeConfig;

/**
* @var Visibility
*/
private $catalogProductVisibility;

/**
* Constructor
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
Expand All @@ -82,6 +90,7 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param Visibility|null $catalogProductVisibility
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Expand All @@ -96,7 +105,8 @@ public function __construct(
\Magento\Framework\Validator\UniversalFactory $universalFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null,
Visibility $catalogProductVisibility = null
) {
parent::__construct(
$entityFactory,
Expand All @@ -113,6 +123,8 @@ public function __construct(
);
$this->scopeConfig = $scopeConfig ?:
\Magento\Framework\App\ObjectManager::getInstance()->get(ScopeConfigInterface::class);
$this->catalogProductVisibility = $catalogProductVisibility ?:
\Magento\Framework\App\ObjectManager::getInstance()->get(Visibility::class);
}

/**
Expand All @@ -122,7 +134,7 @@ public function __construct(
*/
protected function _construct()
{
$this->_init(\Magento\Catalog\Model\Category::class, \Magento\Catalog\Model\ResourceModel\Category::class);
$this->_init(Category::class, \Magento\Catalog\Model\ResourceModel\Category::class);
}

/**
Expand Down Expand Up @@ -259,6 +271,7 @@ protected function _loadProductCount()
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function loadProductCount($items, $countRegular = true, $countAnchor = true)
{
Expand Down Expand Up @@ -310,34 +323,14 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr

if ($countAnchor) {
// Retrieve Anchor categories product counts
$categoryIds = array_keys($anchor);
$countSelect = $this->getProductsCountQuery($categoryIds, (bool)$websiteId);
$categoryProductsCount = $this->_conn->fetchPairs($countSelect);
foreach ($anchor as $item) {
if ($allChildren = $item->getAllChildren()) {
$bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
$select = $this->_conn->select();
$select->from(
['main_table' => $this->getProductTable()],
new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
)->joinInner(
['e' => $this->getTable('catalog_category_entity')],
'main_table.category_id=e.entity_id',
[]
)->where(
'(e.entity_id = :entity_id OR e.path LIKE :c_path)'
);
if ($websiteId) {
$select->join(
['w' => $this->getProductWebsiteTable()],
'main_table.product_id = w.product_id',
[]
)->where(
'w.website_id = ?',
$websiteId
);
}
$item->setProductCount((int)$this->_conn->fetchOne($select, $bind));
} else {
$item->setProductCount(0);
}
$productsCount = isset($categoriesProductsCount[$item->getId()])
? (int)$categoryProductsCount[$item->getId()]
: $this->getProductsCountFromCategoryTable($item, $websiteId);
$item->setProductCount($productsCount);
}
}
return $this;
Expand Down Expand Up @@ -513,4 +506,69 @@ public function getProductTable()
}
return $this->_productTable;
}

/**
* Get products count using catalog_category_entity table
*
* @param Category $item
* @param string $websiteId
* @return int
*/
private function getProductsCountFromCategoryTable(Category $item, string $websiteId): int
{
$productCount = 0;

if ($item->getAllChildren()) {
$bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
$select = $this->_conn->select();
$select->from(
['main_table' => $this->getProductTable()],
new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
)->joinInner(
['e' => $this->getTable('catalog_category_entity')],
'main_table.category_id=e.entity_id',
[]
)->where(
'(e.entity_id = :entity_id OR e.path LIKE :c_path)'
);
if ($websiteId) {
$select->join(
['w' => $this->getProductWebsiteTable()],
'main_table.product_id = w.product_id',
[]
)->where(
'w.website_id = ?',
$websiteId
);
}
$productCount = (int)$this->_conn->fetchOne($select, $bind);
}
return $productCount;
}

/**
* Get query for retrieve count of products per category
*
* @param array $categoryIds
* @param bool $addVisibilityFilter
* @return Select
*/
private function getProductsCountQuery(array $categoryIds, $addVisibilityFilter = true): Select
{
$categoryTable = $this->getTable('catalog_category_product_index');
$select = $this->_conn->select()
->from(
['cat_index' => $categoryTable],
['category_id' => 'cat_index.category_id', 'count' => 'count(cat_index.product_id)']
)
->where('cat_index.category_id in (?)', \array_map('\intval', $categoryIds));
if (true === $addVisibilityFilter) {
$select->where('cat_index.visibility in (?)', $this->catalogProductVisibility->getVisibleInSiteIds());
}
if (count($categoryIds) > 1) {
$select->group('cat_index.category_id');
}

return $select;
}
}

0 comments on commit 15dc874

Please sign in to comment.