Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/**
* Copyright 2015 Adobe
* Copyright 2011 Adobe
* All Rights Reserved.
*/
namespace Magento\Catalog\Model\ResourceModel\Category;
Expand All @@ -9,7 +9,6 @@
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;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Ddl\Table;
Expand Down Expand Up @@ -93,7 +92,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
* @param Visibility|null $catalogProductVisibility @deprecated Parameter no longer used.
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Expand Down Expand Up @@ -340,25 +339,19 @@ 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);
$countFromCategoryTable = [];
if (count($categoryIds) > self::BULK_PROCESSING_LIMIT) {
$countFromCategoryTable = $this->getCountFromCategoryTableBulk($categoryIds, (int)$websiteId);
$countFromCategoryTable = $this->getCountFromCategoryTableBulk($categoryIds, $websiteId);
}

foreach ($anchor as $item) {
$productsCount = 0;
if (count($categoryIds) > self::BULK_PROCESSING_LIMIT) {
if (isset($categoryProductsCount[$item->getId()])) {
$productsCount = (int)$categoryProductsCount[$item->getId()];
} elseif (isset($countFromCategoryTable[$item->getId()])) {
if (isset($countFromCategoryTable[$item->getId()])) {
$productsCount = (int)$countFromCategoryTable[$item->getId()];
}
} else {
$productsCount = isset($categoryProductsCount[$item->getId()])
? (int)$categoryProductsCount[$item->getId()]
: $this->getProductsCountFromCategoryTable($item, $websiteId);
$productsCount = $this->getProductsCountFromCategoryTable($item, $websiteId);
}
$item->setProductCount($productsCount);
}
Expand All @@ -370,13 +363,13 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr
* Get products number for each category with bulk query
*
* @param array $categoryIds
* @param int $websiteId
* @param string|int|null $websiteId
* @return array
* @throws \Zend_Db_Exception
*/
private function getCountFromCategoryTableBulk(
array $categoryIds,
int $websiteId
string|int|null $websiteId
) : array {
$connection = $this->_conn;
$tempTableName = 'temp_category_descendants_' . uniqid();
Expand Down Expand Up @@ -452,10 +445,10 @@ private function getCountFromCategoryTableBulk(
* Get products count using catalog_category_entity table
*
* @param Category $item
* @param string $websiteId
* @param string|int|null $websiteId
* @return int
*/
private function getProductsCountFromCategoryTable(Category $item, string $websiteId): int
private function getProductsCountFromCategoryTable(Category $item, string|int|null $websiteId): int
{
$productCount = 0;

Expand Down Expand Up @@ -658,30 +651,4 @@ public function getProductTable()
}
return $this->_productTable;
}

/**
* 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->_resource->getTableName('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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,19 +203,92 @@ public function setUp(): void
);
}

public function testLoadProductCount() : void
/**
* Test that loadProductCount works correctly for regular (non-anchor) categories
*/
public function testLoadProductCountForRegularCategories() : void
{
$this->select->expects($this->exactly(1))
$categoryId = 1;
$websiteId = 1;
$storeId = 1;

$category = $this->getMockBuilder(Category::class)
->addMethods(['getIsAnchor'])
->onlyMethods(['getId', 'setProductCount'])
->disableOriginalConstructor()
->getMock();
$category->method('getId')->willReturn($categoryId);
$category->method('getIsAnchor')->willReturn(false);
$category->expects($this->once())->method('setProductCount')->with(5);

$items = [$categoryId => $category];

$storeMock = $this->createMock(Store::class);
$storeMock->method('getWebsiteId')->willReturn($websiteId);
$this->storeManager->method('getStore')->with($storeId)->willReturn($storeMock);

$this->select->expects($this->once())
->method('from')
->willReturnSelf();
$this->select->expects($this->exactly(1))
$this->select->expects($this->atLeastOnce())
->method('where')
->willReturnSelf();
$this->connection->expects($this->exactly(1))
$this->select->expects($this->once())
->method('group')
->willReturnSelf();
$this->connection->expects($this->once())
->method('fetchPairs')
->with($this->select)
->willReturn([]);
$this->collection->loadProductCount([]);
->willReturn([$categoryId => 5]);

$this->collection->setProductStoreId($storeId);
$this->collection->loadProductCount($items, true, false);
}

/**
* Test that loadProductCount works correctly for anchor categories (small count)
*/
public function testLoadProductCountForAnchorCategories() : void
{
$categoryId = 1;
$websiteId = 1;
$storeId = 1;

$category = $this->getMockBuilder(Category::class)
->addMethods(['getIsAnchor'])
->onlyMethods(['getId', 'setProductCount', 'getAllChildren', 'getPath'])
->disableOriginalConstructor()
->getMock();
$category->method('getId')->willReturn($categoryId);
$category->method('getIsAnchor')->willReturn(true);
$category->method('getAllChildren')->willReturn('1');
$category->method('getPath')->willReturn('1/2');
$category->expects($this->once())->method('setProductCount')->with(3);

$items = [$categoryId => $category];

$storeMock = $this->createMock(Store::class);
$storeMock->method('getWebsiteId')->willReturn($websiteId);
$this->storeManager->method('getStore')->with($storeId)->willReturn($storeMock);

$this->select->expects($this->atLeastOnce())
->method('from')
->willReturnSelf();
$this->select->expects($this->atLeastOnce())
->method('where')
->willReturnSelf();
$this->select->expects($this->atLeastOnce())
->method('joinInner')
->willReturnSelf();
$this->select->method('join')
->willReturnSelf();
$this->connection->expects($this->once())
->method('fetchOne')
->with($this->select)
->willReturn(3);

$this->collection->setProductStoreId($storeId);
$this->collection->loadProductCount($items, false);
}

/**
Expand Down Expand Up @@ -274,6 +347,6 @@ public function testLoadProductCountCallsBulkMethodForLargeCategoryCount()
->with($this->isInstanceOf(Select::class))
->willReturn($counts);
$this->collection->setProductStoreId($storeId);
$this->collection->loadProductCount($items, false, true);
$this->collection->loadProductCount($items, false);
}
}
Loading