5
5
*/
6
6
namespace Magento \Catalog \Model \ResourceModel \Category ;
7
7
8
+ use Magento \Catalog \Model \Category ;
9
+ use Magento \Catalog \Model \Product \Visibility ;
8
10
use Magento \CatalogUrlRewrite \Model \CategoryUrlRewriteGenerator ;
9
11
use Magento \Framework \App \Config \ScopeConfigInterface ;
12
+ use Magento \Framework \DB \Select ;
10
13
use Magento \Store \Model \ScopeInterface ;
11
14
12
15
/**
@@ -68,6 +71,11 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
68
71
*/
69
72
private $ scopeConfig ;
70
73
74
+ /**
75
+ * @var Visibility
76
+ */
77
+ private $ catalogProductVisibility ;
78
+
71
79
/**
72
80
* Constructor
73
81
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
@@ -82,6 +90,7 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
82
90
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
83
91
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
84
92
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
93
+ * @param Visibility|null $catalogProductVisibility
85
94
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
86
95
*/
87
96
public function __construct (
@@ -96,7 +105,8 @@ public function __construct(
96
105
\Magento \Framework \Validator \UniversalFactory $ universalFactory ,
97
106
\Magento \Store \Model \StoreManagerInterface $ storeManager ,
98
107
\Magento \Framework \DB \Adapter \AdapterInterface $ connection = null ,
99
- \Magento \Framework \App \Config \ScopeConfigInterface $ scopeConfig = null
108
+ \Magento \Framework \App \Config \ScopeConfigInterface $ scopeConfig = null ,
109
+ Visibility $ catalogProductVisibility = null
100
110
) {
101
111
parent ::__construct (
102
112
$ entityFactory ,
@@ -113,6 +123,8 @@ public function __construct(
113
123
);
114
124
$ this ->scopeConfig = $ scopeConfig ?:
115
125
\Magento \Framework \App \ObjectManager::getInstance ()->get (ScopeConfigInterface::class);
126
+ $ this ->catalogProductVisibility = $ catalogProductVisibility ?:
127
+ \Magento \Framework \App \ObjectManager::getInstance ()->get (Visibility::class);
116
128
}
117
129
118
130
/**
@@ -122,7 +134,7 @@ public function __construct(
122
134
*/
123
135
protected function _construct ()
124
136
{
125
- $ this ->_init (\ Magento \ Catalog \ Model \ Category::class, \Magento \Catalog \Model \ResourceModel \Category::class);
137
+ $ this ->_init (Category::class, \Magento \Catalog \Model \ResourceModel \Category::class);
126
138
}
127
139
128
140
/**
@@ -259,6 +271,7 @@ protected function _loadProductCount()
259
271
* @return $this
260
272
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
261
273
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
274
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
262
275
*/
263
276
public function loadProductCount ($ items , $ countRegular = true , $ countAnchor = true )
264
277
{
@@ -310,34 +323,14 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr
310
323
311
324
if ($ countAnchor ) {
312
325
// Retrieve Anchor categories product counts
326
+ $ categoryIds = array_keys ($ anchor );
327
+ $ countSelect = $ this ->getProductsCountQuery ($ categoryIds , (bool )$ websiteId );
328
+ $ categoryProductsCount = $ this ->_conn ->fetchPairs ($ countSelect );
313
329
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
- }
330
+ $ productsCount = isset ($ categoriesProductsCount [$ item ->getId ()])
331
+ ? (int )$ categoryProductsCount [$ item ->getId ()]
332
+ : $ this ->getProductsCountFromCategoryTable ($ item , $ websiteId );
333
+ $ item ->setProductCount ($ productsCount );
341
334
}
342
335
}
343
336
return $ this ;
@@ -513,4 +506,69 @@ public function getProductTable()
513
506
}
514
507
return $ this ->_productTable ;
515
508
}
509
+
510
+ /**
511
+ * Get products count using catalog_category_entity table
512
+ *
513
+ * @param Category $item
514
+ * @param string $websiteId
515
+ * @return int
516
+ */
517
+ private function getProductsCountFromCategoryTable (Category $ item , string $ websiteId ): int
518
+ {
519
+ $ productCount = 0 ;
520
+
521
+ if ($ item ->getAllChildren ()) {
522
+ $ bind = ['entity_id ' => $ item ->getId (), 'c_path ' => $ item ->getPath () . '/% ' ];
523
+ $ select = $ this ->_conn ->select ();
524
+ $ select ->from (
525
+ ['main_table ' => $ this ->getProductTable ()],
526
+ new \Zend_Db_Expr ('COUNT(DISTINCT main_table.product_id) ' )
527
+ )->joinInner (
528
+ ['e ' => $ this ->getTable ('catalog_category_entity ' )],
529
+ 'main_table.category_id=e.entity_id ' ,
530
+ []
531
+ )->where (
532
+ '(e.entity_id = :entity_id OR e.path LIKE :c_path) '
533
+ );
534
+ if ($ websiteId ) {
535
+ $ select ->join (
536
+ ['w ' => $ this ->getProductWebsiteTable ()],
537
+ 'main_table.product_id = w.product_id ' ,
538
+ []
539
+ )->where (
540
+ 'w.website_id = ? ' ,
541
+ $ websiteId
542
+ );
543
+ }
544
+ $ productCount = (int )$ this ->_conn ->fetchOne ($ select , $ bind );
545
+ }
546
+ return $ productCount ;
547
+ }
548
+
549
+ /**
550
+ * Get query for retrieve count of products per category
551
+ *
552
+ * @param array $categoryIds
553
+ * @param bool $addVisibilityFilter
554
+ * @return Select
555
+ */
556
+ private function getProductsCountQuery (array $ categoryIds , $ addVisibilityFilter = true ): Select
557
+ {
558
+ $ categoryTable = $ this ->getTable ('catalog_category_product_index ' );
559
+ $ select = $ this ->_conn ->select ()
560
+ ->from (
561
+ ['cat_index ' => $ categoryTable ],
562
+ ['category_id ' => 'cat_index.category_id ' , 'count ' => 'count(cat_index.product_id) ' ]
563
+ )
564
+ ->where ('cat_index.category_id in (?) ' , \array_map ('\intval ' , $ categoryIds ));
565
+ if (true === $ addVisibilityFilter ) {
566
+ $ select ->where ('cat_index.visibility in (?) ' , $ this ->catalogProductVisibility ->getVisibleInSiteIds ());
567
+ }
568
+ if (count ($ categoryIds ) > 1 ) {
569
+ $ select ->group ('cat_index.category_id ' );
570
+ }
571
+
572
+ return $ select ;
573
+ }
516
574
}
0 commit comments