Skip to content

Commit

Permalink
Merge branch '2.4-develop' of http://github.com/magento/magento2 into…
Browse files Browse the repository at this point in the history
… fix_issue_26449
  • Loading branch information
engcom-Echo committed Apr 10, 2020
2 parents 43e7715 + a73532a commit 784e733
Show file tree
Hide file tree
Showing 59 changed files with 1,543 additions and 759 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;
}
}
65 changes: 36 additions & 29 deletions app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -1180,9 +1180,33 @@ protected function _getSelectCountSql(?Select $select = null, $resetLeftJoins =
if ($resetLeftJoins) {
$countSelect->resetJoinLeft();
}

$this->removeEntityIdentifierFromGroupBy($countSelect);

return $countSelect;
}

/**
* Using `entity_id` for `GROUP BY` causes COUNT() return {n} rows of value = 1 instead of 1 row of value {n}
*
* @param Select $select
* @throws \Zend_Db_Select_Exception
*/
private function removeEntityIdentifierFromGroupBy(Select $select): void
{
$originalGroupBy = $select->getPart(Select::GROUP);

if (!is_array($originalGroupBy)) {
return;
}

$groupBy = array_filter($originalGroupBy, function ($field) {
return false === strpos($field, $this->getIdFieldName());
});

$select->setPart(Select::GROUP, $groupBy);
}

/**
* Prepare statistics data
*
Expand Down Expand Up @@ -1770,30 +1794,19 @@ public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC)
*/
protected function _prepareProductLimitationFilters()
{
if (isset(
$this->_productLimitationFilters['visibility']
) && !isset(
$this->_productLimitationFilters['store_id']
)
) {
if (isset($this->_productLimitationFilters['visibility'])
&& !isset($this->_productLimitationFilters['store_id'])) {
$this->_productLimitationFilters['store_id'] = $this->getStoreId();
}
if (isset(
$this->_productLimitationFilters['category_id']
) && !isset(
$this->_productLimitationFilters['store_id']
)
) {

if (isset($this->_productLimitationFilters['category_id'])
&& !isset($this->_productLimitationFilters['store_id'])) {
$this->_productLimitationFilters['store_id'] = $this->getStoreId();
}
if (isset(
$this->_productLimitationFilters['store_id']
) && isset(
$this->_productLimitationFilters['visibility']
) && !isset(
$this->_productLimitationFilters['category_id']
)
) {

if (isset($this->_productLimitationFilters['store_id'])
&& isset($this->_productLimitationFilters['visibility'])
&& !isset($this->_productLimitationFilters['category_id'])) {
$this->_productLimitationFilters['category_id'] = $this->_storeManager->getStore(
$this->_productLimitationFilters['store_id']
)->getRootCategoryId();
Expand Down Expand Up @@ -1824,14 +1837,8 @@ protected function _productLimitationJoinWebsite()
$filters['website_ids'],
'int'
);
} elseif (isset(
$filters['store_id']
) && (!isset(
$filters['visibility']
) && !isset(
$filters['category_id']
)) && !$this->isEnabledFlat()
) {
} elseif (isset($filters['store_id']) && !$this->isEnabledFlat()
&& (!isset($filters['visibility']) && !isset($filters['category_id']))) {
$joinWebsite = true;
$websiteId = $this->_storeManager->getStore($filters['store_id'])->getWebsiteId();
$conditions[] = $this->getConnection()->quoteInto('product_website.website_id = ?', $websiteId, 'int');
Expand Down Expand Up @@ -1906,9 +1913,9 @@ protected function _productLimitationJoinPrice()
/**
* Join Product Price Table with left-join possibility
*
* @see \Magento\Catalog\Model\ResourceModel\Product\Collection::_productLimitationJoinPrice()
* @param bool $joinLeft
* @return $this
* @see \Magento\Catalog\Model\ResourceModel\Product\Collection::_productLimitationJoinPrice()
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function _productLimitationPrice($joinLeft = false)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
<actionGroup name="AssertStorefrontNoProductsFoundActionGroup">
<see userInput="We can't find products matching the selection." stepKey="seeEmptyNotice"/>
</actionGroup>
</actionGroups>
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,12 @@
<data key="path">catalog/frontend/grid_per_page_values</data>
<data key="value">1,2</data>
</entity>
<entity name="DefaultGridPerPageDefaultConfigData">
<data key="path">catalog/frontend/grid_per_page</data>
<data key="value">12</data>
</entity>
<entity name="CustomGridPerPageDefaultConfigData">
<data key="path">catalog/frontend/grid_per_page</data>
<data key="value">1</data>
</entity>
</entities>
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@

<!-- # Category should open successfully # <product1> should be absent on the page -->
<see userInput="$$createAnchoredCategory1.name$$" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="seeCategory1Name"/>
<see userInput="We can't find products matching the selection." stepKey="seeEmptyNotice"/>
<actionGroup ref="AssertStorefrontNoProductsFoundActionGroup" stepKey="seeEmptyNotice"/>
<dontSee userInput="$$simpleProduct.name$$" selector="{{StorefrontCategoryMainSection.productName}}" stepKey="dontseeProduct"/>

<!-- Log in to the backend: Admin user is logged in-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

<!-- The category is still empty -->
<see userInput="$$createCategoryA.name$$" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="seeCategoryA1Name"/>
<see userInput="We can't find products matching the selection." stepKey="seeEmptyNotice"/>
<actionGroup ref="AssertStorefrontNoProductsFoundActionGroup" stepKey="seeEmptyNotice"/>
<dontSee userInput="$$createProductA1.name$$" selector="{{StorefrontCategoryMainSection.productName}}" stepKey="dontseeProductA1"/>

<!-- 4. Run cron to reindex -->
Expand Down Expand Up @@ -132,7 +132,7 @@

<!-- Category A is empty now -->
<see userInput="$$createCategoryA.name$$" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="seeOnPageCategoryAName"/>
<see userInput="We can't find products matching the selection." stepKey="seeOnPageEmptyNotice"/>
<actionGroup ref="AssertStorefrontNoProductsFoundActionGroup" stepKey="seeOnPageEmptyNotice"/>
<dontSee userInput="$$createProductA1.name$$" selector="{{StorefrontCategoryMainSection.productName}}" stepKey="dontseeProductA1OnPage"/>

<!-- Case: change product status -->
Expand Down
Loading

0 comments on commit 784e733

Please sign in to comment.