7
7
namespace Magento \Catalog \Block \Product ;
8
8
9
9
use Magento \Catalog \Api \CategoryRepositoryInterface ;
10
+ use Magento \Catalog \Block \Product \ProductList \Toolbar ;
10
11
use Magento \Catalog \Model \Category ;
11
12
use Magento \Catalog \Model \Product ;
13
+ use Magento \Catalog \Model \ResourceModel \Product \Collection ;
12
14
use Magento \Eav \Model \Entity \Collection \AbstractCollection ;
13
15
use Magento \Framework \Exception \NoSuchEntityException ;
14
16
use Magento \Framework \DataObject \IdentityInterface ;
@@ -24,7 +26,7 @@ class ListProduct extends AbstractProduct implements IdentityInterface
24
26
*
25
27
* @var string
26
28
*/
27
- protected $ _defaultToolbarBlock = \ Magento \ Catalog \ Block \ Product \ ProductList \ Toolbar::class;
29
+ protected $ _defaultToolbarBlock = Toolbar::class;
28
30
29
31
/**
30
32
* Product Collection
@@ -84,50 +86,23 @@ public function __construct(
84
86
/**
85
87
* Retrieve loaded category collection
86
88
*
89
+ * The goal of this method is to choose whether the existing collection should be returned
90
+ * or a new one should be initialized.
91
+ *
92
+ * It is not just a caching logic, but also is a real logical check
93
+ * because there are two ways how collection may be stored inside the block:
94
+ * - Product collection may be passed externally by 'setCollection' method
95
+ * - Product collection may be requested internally from the current Catalog Layer.
96
+ *
97
+ * And this method will return collection anyway,
98
+ * even when it did not pass externally and therefore isn't cached yet
99
+ *
87
100
* @return AbstractCollection
88
101
*/
89
102
protected function _getProductCollection ()
90
103
{
91
104
if ($ this ->_productCollection === null ) {
92
- $ layer = $ this ->getLayer ();
93
- /* @var $layer \Magento\Catalog\Model\Layer */
94
- if ($ this ->getShowRootCategory ()) {
95
- $ this ->setCategoryId ($ this ->_storeManager ->getStore ()->getRootCategoryId ());
96
- }
97
-
98
- // if this is a product view page
99
- if ($ this ->_coreRegistry ->registry ('product ' )) {
100
- // get collection of categories this product is associated with
101
- $ categories = $ this ->_coreRegistry ->registry ('product ' )
102
- ->getCategoryCollection ()->setPage (1 , 1 )
103
- ->load ();
104
- // if the product is associated with any category
105
- if ($ categories ->count ()) {
106
- // show products from this category
107
- $ this ->setCategoryId (current ($ categories ->getIterator ()));
108
- }
109
- }
110
-
111
- $ origCategory = null ;
112
- if ($ this ->getCategoryId ()) {
113
- try {
114
- $ category = $ this ->categoryRepository ->get ($ this ->getCategoryId ());
115
- } catch (NoSuchEntityException $ e ) {
116
- $ category = null ;
117
- }
118
-
119
- if ($ category ) {
120
- $ origCategory = $ layer ->getCurrentCategory ();
121
- $ layer ->setCurrentCategory ($ category );
122
- }
123
- }
124
- $ this ->_productCollection = $ layer ->getProductCollection ();
125
-
126
- $ this ->prepareSortableFieldsByCategory ($ layer ->getCurrentCategory ());
127
-
128
- if ($ origCategory ) {
129
- $ layer ->setCurrentCategory ($ origCategory );
130
- }
105
+ $ this ->_productCollection = $ this ->initializeProductCollection ();
131
106
}
132
107
133
108
return $ this ->_productCollection ;
@@ -170,47 +145,17 @@ public function getMode()
170
145
*/
171
146
protected function _beforeToHtml ()
172
147
{
173
- $ toolbar = $ this ->getToolbarBlock ();
174
-
175
- // called prepare sortable parameters
176
148
$ collection = $ this ->_getProductCollection ();
177
-
178
- // use sortable parameters
179
- $ orders = $ this ->getAvailableOrders ();
180
- if ($ orders ) {
181
- $ toolbar ->setAvailableOrders ($ orders );
182
- }
183
- $ sort = $ this ->getSortBy ();
184
- if ($ sort ) {
185
- $ toolbar ->setDefaultOrder ($ sort );
186
- }
187
- $ dir = $ this ->getDefaultDirection ();
188
- if ($ dir ) {
189
- $ toolbar ->setDefaultDirection ($ dir );
190
- }
191
- $ modes = $ this ->getModes ();
192
- if ($ modes ) {
193
- $ toolbar ->setModes ($ modes );
194
- }
195
-
196
- // set collection to toolbar and apply sort
197
- $ toolbar ->setCollection ($ collection );
198
-
199
- $ this ->setChild ('toolbar ' , $ toolbar );
200
- $ this ->_eventManager ->dispatch (
201
- 'catalog_block_product_list_collection ' ,
202
- ['collection ' => $ this ->_getProductCollection ()]
203
- );
204
-
205
- $ this ->_getProductCollection ()->load ();
149
+ $ this ->configureToolbar ($ this ->getToolbarBlock (), $ collection );
150
+ $ collection ->load ();
206
151
207
152
return parent ::_beforeToHtml ();
208
153
}
209
154
210
155
/**
211
156
* Retrieve Toolbar block
212
157
*
213
- * @return \Magento\Catalog\Block\Product\ProductList\ Toolbar
158
+ * @return Toolbar
214
159
*/
215
160
public function getToolbarBlock ()
216
161
{
@@ -379,4 +324,107 @@ protected function getPriceRender()
379
324
{
380
325
return $ this ->getLayout ()->getBlock ('product.price.render.default ' );
381
326
}
327
+
328
+ /**
329
+ * Configures product collection from a layer and returns its instance.
330
+ *
331
+ * Also in the scope of a product collection configuration, this method initiates configuration of Toolbar.
332
+ * The reason to do this is because we have a bunch of legacy code
333
+ * where Toolbar configures several options of a collection and therefore this block depends on the Toolbar.
334
+ *
335
+ * This dependency leads to a situation where Toolbar sometimes called to configure a product collection,
336
+ * and sometimes not.
337
+ *
338
+ * To unify this behavior and prevent potential bugs this dependency is explicitly called
339
+ * when product collection initialized.
340
+ *
341
+ * @return Collection
342
+ */
343
+ private function initializeProductCollection ()
344
+ {
345
+ $ layer = $ this ->getLayer ();
346
+ /* @var $layer \Magento\Catalog\Model\Layer */
347
+ if ($ this ->getShowRootCategory ()) {
348
+ $ this ->setCategoryId ($ this ->_storeManager ->getStore ()->getRootCategoryId ());
349
+ }
350
+
351
+ // if this is a product view page
352
+ if ($ this ->_coreRegistry ->registry ('product ' )) {
353
+ // get collection of categories this product is associated with
354
+ $ categories = $ this ->_coreRegistry ->registry ('product ' )
355
+ ->getCategoryCollection ()->setPage (1 , 1 )
356
+ ->load ();
357
+ // if the product is associated with any category
358
+ if ($ categories ->count ()) {
359
+ // show products from this category
360
+ $ this ->setCategoryId (current ($ categories ->getIterator ()));
361
+ }
362
+ }
363
+
364
+ $ origCategory = null ;
365
+ if ($ this ->getCategoryId ()) {
366
+ try {
367
+ $ category = $ this ->categoryRepository ->get ($ this ->getCategoryId ());
368
+ } catch (NoSuchEntityException $ e ) {
369
+ $ category = null ;
370
+ }
371
+
372
+ if ($ category ) {
373
+ $ origCategory = $ layer ->getCurrentCategory ();
374
+ $ layer ->setCurrentCategory ($ category );
375
+ }
376
+ }
377
+ $ collection = $ layer ->getProductCollection ();
378
+
379
+ $ this ->prepareSortableFieldsByCategory ($ layer ->getCurrentCategory ());
380
+
381
+ if ($ origCategory ) {
382
+ $ layer ->setCurrentCategory ($ origCategory );
383
+ }
384
+
385
+ $ toolbar = $ this ->getToolbarBlock ();
386
+ $ this ->configureToolbar ($ toolbar , $ collection );
387
+
388
+ $ this ->_eventManager ->dispatch (
389
+ 'catalog_block_product_list_collection ' ,
390
+ ['collection ' => $ collection ]
391
+ );
392
+
393
+ return $ collection ;
394
+ }
395
+
396
+ /**
397
+ * Configures the Toolbar block with options from this block and configured product collection.
398
+ *
399
+ * The purpose of this method is the one-way sharing of different sorting related data
400
+ * between this block, which is responsible for product list rendering,
401
+ * and the Toolbar block, whose responsibility is a rendering of these options.
402
+ *
403
+ * @param ProductList\Toolbar $toolbar
404
+ * @param Collection $collection
405
+ * @return void
406
+ */
407
+ private function configureToolbar (Toolbar $ toolbar , Collection $ collection )
408
+ {
409
+ // use sortable parameters
410
+ $ orders = $ this ->getAvailableOrders ();
411
+ if ($ orders ) {
412
+ $ toolbar ->setAvailableOrders ($ orders );
413
+ }
414
+ $ sort = $ this ->getSortBy ();
415
+ if ($ sort ) {
416
+ $ toolbar ->setDefaultOrder ($ sort );
417
+ }
418
+ $ dir = $ this ->getDefaultDirection ();
419
+ if ($ dir ) {
420
+ $ toolbar ->setDefaultDirection ($ dir );
421
+ }
422
+ $ modes = $ this ->getModes ();
423
+ if ($ modes ) {
424
+ $ toolbar ->setModes ($ modes );
425
+ }
426
+ // set collection to toolbar and apply sort
427
+ $ toolbar ->setCollection ($ collection );
428
+ $ this ->setChild ('toolbar ' , $ toolbar );
429
+ }
382
430
}
0 commit comments