diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php b/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php index 259399ece827b..e6d3c5880c858 100644 --- a/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php +++ b/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php @@ -1,7 +1,7 @@ getProductsCountQuery($categoryIds, (bool)$websiteId); $categoryProductsCount = $this->_conn->fetchPairs($countSelect); + $countFromCategoryTable = []; + if (count($categoryIds) > self::BULK_PROCESSING_LIMIT) { + $countFromCategoryTable = $this->getCountFromCategoryTableBulk($categoryIds, (int)$websiteId); + } + foreach ($anchor as $item) { - $productsCount = isset($categoryProductsCount[$item->getId()]) - ? (int)$categoryProductsCount[$item->getId()] - : $this->getProductsCountFromCategoryTable($item, $websiteId); + $productsCount = 0; + if (count($categoryIds) > self::BULK_PROCESSING_LIMIT) { + if (isset($categoryProductsCount[$item->getId()])) { + $productsCount = (int)$categoryProductsCount[$item->getId()]; + } elseif (isset($countFromCategoryTable[$item->getId()])) { + $productsCount = (int)$countFromCategoryTable[$item->getId()]; + } + } else { + $productsCount = isset($categoryProductsCount[$item->getId()]) + ? (int)$categoryProductsCount[$item->getId()] + : $this->getProductsCountFromCategoryTable($item, $websiteId); + } $item->setProductCount($productsCount); } } return $this; } + /** + * Get products number for each category with bulk query + * + * @param array $categoryIds + * @param int $websiteId + * @return array + */ + private function getCountFromCategoryTableBulk( + array $categoryIds, + int $websiteId + ) : array { + $subSelect = clone $this->_conn->select(); + $subSelect->from(['ce2' => $this->getTable('catalog_category_entity')], 'ce2.entity_id') + ->where("ce2.path LIKE CONCAT(ce.path, '/%') OR ce2.path = ce.path"); + + $select = clone $this->_conn->select(); + $select->from( + ['ce' => $this->getTable('catalog_category_entity')], + 'ce.entity_id' + ); + $joinCondition = new \Zend_Db_Expr("cp.category_id IN ({$subSelect})"); + $select->joinLeft( + ['cp' => $this->getProductTable()], + $joinCondition, + 'COUNT(DISTINCT cp.product_id) AS product_count' + ); + if ($websiteId) { + $select->join( + ['w' => $this->getProductWebsiteTable()], + 'cp.product_id = w.product_id', + [] + )->where( + 'w.website_id = ?', + $websiteId + ); + } + $select->where('ce.entity_id IN(?)', $categoryIds); + $select->group('ce.entity_id'); + + return $this->_conn->fetchPairs($select); + } + + /** + * 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; + } + /** * Add category path filter * @@ -519,45 +617,6 @@ 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 *