5
5
*/
6
6
namespace Magento \ProductAlert \Model ;
7
7
8
+ use Magento \Backend \App \Area \FrontNameResolver ;
9
+ use Magento \Catalog \Api \ProductRepositoryInterface ;
10
+ use Magento \Catalog \Helper \Data ;
11
+ use Magento \Customer \Api \CustomerRepositoryInterface ;
12
+ use Magento \Framework \App \Config \ScopeConfigInterface ;
13
+ use Magento \Framework \App \ObjectManager ;
14
+ use Magento \Framework \Mail \Template \TransportBuilder ;
15
+ use Magento \Framework \Model \ResourceModel \Db \Collection \AbstractCollection ;
16
+ use Magento \Framework \Stdlib \DateTime \DateTimeFactory ;
17
+ use Magento \Framework \Translate \Inline \StateInterface ;
18
+ use Magento \ProductAlert \Model \ResourceModel \Stock \CollectionFactory as StockCollectionFactory ;
19
+ use Magento \ProductAlert \Model \ResourceModel \Price \CollectionFactory as PriceCollectionFactory ;
20
+ use Magento \Store \Model \ScopeInterface ;
21
+ use Magento \Store \Model \Store ;
22
+ use Magento \Store \Model \StoreManagerInterface ;
23
+ use Magento \Store \Model \Website ;
24
+
8
25
/**
9
26
* ProductAlert observer
10
27
*
11
- * @author Magento Core Team <core@magentocommerce.com>
28
+ * @author Magento Core Team <core@magentocommerce.com>
12
29
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
13
30
*/
14
31
class Observer
@@ -40,6 +57,11 @@ class Observer
40
57
*/
41
58
const XML_PATH_STOCK_ALLOW = 'catalog/productalert/allow_stock ' ;
42
59
60
+ /**
61
+ * Default value of bunch size to load alert items
62
+ */
63
+ private const DEFAULT_BUNCH_SIZE = 10000 ;
64
+
43
65
/**
44
66
* Website collection array
45
67
*
@@ -57,59 +79,59 @@ class Observer
57
79
/**
58
80
* Catalog data
59
81
*
60
- * @var \Magento\Catalog\Helper\ Data
82
+ * @var Data
61
83
*/
62
84
protected $ _catalogData = null ;
63
85
64
86
/**
65
87
* Core store config
66
88
*
67
- * @var \Magento\Framework\App\Config\ ScopeConfigInterface
89
+ * @var ScopeConfigInterface
68
90
*/
69
91
protected $ _scopeConfig ;
70
92
71
93
/**
72
- * @var \Magento\Store\Model\ StoreManagerInterface
94
+ * @var StoreManagerInterface
73
95
*/
74
96
protected $ _storeManager ;
75
97
76
98
/**
77
- * @var \Magento\ProductAlert\Model\ResourceModel\Price\CollectionFactory
99
+ * @var PriceCollectionFactory
78
100
*/
79
101
protected $ _priceColFactory ;
80
102
81
103
/**
82
- * @var \Magento\Customer\Api\ CustomerRepositoryInterface
104
+ * @var CustomerRepositoryInterface
83
105
*/
84
106
protected $ customerRepository ;
85
107
86
108
/**
87
- * @var \Magento\Catalog\Api\ ProductRepositoryInterface
109
+ * @var ProductRepositoryInterface
88
110
*/
89
111
protected $ productRepository ;
90
112
91
113
/**
92
- * @var \Magento\Framework\Stdlib\DateTime\ DateTimeFactory
114
+ * @var DateTimeFactory
93
115
*/
94
116
protected $ _dateFactory ;
95
117
96
118
/**
97
- * @var \Magento\ProductAlert\Model\ResourceModel\Stock\CollectionFactory
119
+ * @var StockCollectionFactory
98
120
*/
99
121
protected $ _stockColFactory ;
100
122
101
123
/**
102
- * @var \Magento\Framework\Mail\Template\ TransportBuilder
124
+ * @var TransportBuilder
103
125
*/
104
126
protected $ _transportBuilder ;
105
127
106
128
/**
107
- * @var \Magento\ProductAlert\Model\ EmailFactory
129
+ * @var EmailFactory
108
130
*/
109
131
protected $ _emailFactory ;
110
132
111
133
/**
112
- * @var \Magento\Framework\Translate\Inline\ StateInterface
134
+ * @var StateInterface
113
135
*/
114
136
protected $ inlineTranslation ;
115
137
@@ -119,33 +141,40 @@ class Observer
119
141
protected $ productSalability ;
120
142
121
143
/**
122
- * @param \Magento\Catalog\Helper\Data $catalogData
123
- * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
124
- * @param \Magento\Store\Model\StoreManagerInterface $storeManager
125
- * @param \Magento\ProductAlert\Model\ResourceModel\Price\CollectionFactory $priceColFactory
126
- * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository
127
- * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
128
- * @param \Magento\Framework\Stdlib\DateTime\DateTimeFactory $dateFactory
129
- * @param \Magento\ProductAlert\Model\ResourceModel\Stock\CollectionFactory $stockColFactory
130
- * @param \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder
131
- * @param \Magento\ProductAlert\Model\EmailFactory $emailFactory
132
- * @param \Magento\Framework\Translate\Inline\StateInterface $inlineTranslation
144
+ * @var int
145
+ */
146
+ private $ bunchSize ;
147
+
148
+ /**
149
+ * @param Data $catalogData
150
+ * @param ScopeConfigInterface $scopeConfig
151
+ * @param StoreManagerInterface $storeManager
152
+ * @param PriceCollectionFactory $priceColFactory
153
+ * @param CustomerRepositoryInterface $customerRepository
154
+ * @param ProductRepositoryInterface $productRepository
155
+ * @param DateTimeFactory $dateFactory
156
+ * @param StockCollectionFactory $stockColFactory
157
+ * @param TransportBuilder $transportBuilder
158
+ * @param EmailFactory $emailFactory
159
+ * @param StateInterface $inlineTranslation
133
160
* @param ProductSalability|null $productSalability
161
+ * @param int $bunchSize
134
162
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
135
163
*/
136
164
public function __construct (
137
- \Magento \Catalog \Helper \Data $ catalogData ,
138
- \Magento \Framework \App \Config \ScopeConfigInterface $ scopeConfig ,
139
- \Magento \Store \Model \StoreManagerInterface $ storeManager ,
140
- \Magento \ProductAlert \Model \ResourceModel \Price \CollectionFactory $ priceColFactory ,
141
- \Magento \Customer \Api \CustomerRepositoryInterface $ customerRepository ,
142
- \Magento \Catalog \Api \ProductRepositoryInterface $ productRepository ,
143
- \Magento \Framework \Stdlib \DateTime \DateTimeFactory $ dateFactory ,
144
- \Magento \ProductAlert \Model \ResourceModel \Stock \CollectionFactory $ stockColFactory ,
145
- \Magento \Framework \Mail \Template \TransportBuilder $ transportBuilder ,
146
- \Magento \ProductAlert \Model \EmailFactory $ emailFactory ,
147
- \Magento \Framework \Translate \Inline \StateInterface $ inlineTranslation ,
148
- ProductSalability $ productSalability = null
165
+ Data $ catalogData ,
166
+ ScopeConfigInterface $ scopeConfig ,
167
+ StoreManagerInterface $ storeManager ,
168
+ PriceCollectionFactory $ priceColFactory ,
169
+ CustomerRepositoryInterface $ customerRepository ,
170
+ ProductRepositoryInterface $ productRepository ,
171
+ DateTimeFactory $ dateFactory ,
172
+ StockCollectionFactory $ stockColFactory ,
173
+ TransportBuilder $ transportBuilder ,
174
+ EmailFactory $ emailFactory ,
175
+ StateInterface $ inlineTranslation ,
176
+ ProductSalability $ productSalability = null ,
177
+ int $ bunchSize = 0
149
178
) {
150
179
$ this ->_catalogData = $ catalogData ;
151
180
$ this ->_scopeConfig = $ scopeConfig ;
@@ -158,8 +187,9 @@ public function __construct(
158
187
$ this ->_transportBuilder = $ transportBuilder ;
159
188
$ this ->_emailFactory = $ emailFactory ;
160
189
$ this ->inlineTranslation = $ inlineTranslation ;
161
- $ objectManager = \ Magento \ Framework \ App \ ObjectManager::getInstance ();
190
+ $ objectManager = ObjectManager::getInstance ();
162
191
$ this ->productSalability = $ productSalability ?: $ objectManager ->get (ProductSalability::class);
192
+ $ this ->bunchSize = $ bunchSize ?: self ::DEFAULT_BUNCH_SIZE ;
163
193
}
164
194
165
195
/**
@@ -184,40 +214,41 @@ protected function _getWebsites()
184
214
/**
185
215
* Process price emails
186
216
*
187
- * @param \Magento\ProductAlert\Model\ Email $email
217
+ * @param Email $email
188
218
* @return $this
189
219
* @throws \Exception
190
220
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
191
221
* @SuppressWarnings(PHPMD.NPathComplexity)
192
222
*/
193
- protected function _processPrice (\ Magento \ ProductAlert \ Model \ Email $ email )
223
+ protected function _processPrice (Email $ email )
194
224
{
195
225
$ email ->setType ('price ' );
196
226
foreach ($ this ->_getWebsites () as $ website ) {
197
- /* @var $website \Magento\Store\Model\ Website */
227
+ /* @var $website Website */
198
228
if (!$ website ->getDefaultGroup () || !$ website ->getDefaultGroup ()->getDefaultStore ()) {
199
229
continue ;
200
230
}
201
231
if (!$ this ->_scopeConfig ->getValue (
202
- self ::XML_PATH_PRICE_ALLOW ,
203
- \ Magento \ Store \ Model \ ScopeInterface::SCOPE_STORE ,
204
- $ website ->getDefaultGroup ()->getDefaultStore ()->getId ()
205
- )
232
+ self ::XML_PATH_PRICE_ALLOW ,
233
+ ScopeInterface::SCOPE_STORE ,
234
+ $ website ->getDefaultGroup ()->getDefaultStore ()->getId ()
235
+ )
206
236
) {
207
237
continue ;
208
238
}
209
239
try {
210
- $ collection = $ this ->_priceColFactory ->create ()->addWebsiteFilter (
211
- $ website ->getId ()
212
- )->setCustomerOrder ();
240
+ $ collection = $ this ->_priceColFactory ->create ()
241
+ ->addWebsiteFilter ($ website ->getId ())
242
+ ->setCustomerOrder ()
243
+ ->addOrder ('product_id ' );
213
244
} catch (\Exception $ e ) {
214
245
$ this ->_errors [] = $ e ->getMessage ();
215
246
throw $ e ;
216
247
}
217
248
218
249
$ previousCustomer = null ;
219
250
$ email ->setWebsite ($ website );
220
- foreach ($ collection as $ alert ) {
251
+ foreach ($ this -> loadItems ( $ collection, $ this -> bunchSize ) as $ alert ) {
221
252
$ this ->setAlertStoreId ($ alert , $ email );
222
253
try {
223
254
if (!$ previousCustomer || $ previousCustomer ->getId () != $ alert ->getCustomerId ()) {
@@ -274,44 +305,44 @@ protected function _processPrice(\Magento\ProductAlert\Model\Email $email)
274
305
/**
275
306
* Process stock emails
276
307
*
277
- * @param \Magento\ProductAlert\Model\ Email $email
308
+ * @param Email $email
278
309
* @return $this
279
310
* @throws \Exception
280
311
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
281
312
* @SuppressWarnings(PHPMD.NPathComplexity)
282
313
*/
283
- protected function _processStock (\ Magento \ ProductAlert \ Model \ Email $ email )
314
+ protected function _processStock (Email $ email )
284
315
{
285
316
$ email ->setType ('stock ' );
286
317
287
318
foreach ($ this ->_getWebsites () as $ website ) {
288
- /* @var $website \Magento\Store\Model\ Website */
319
+ /* @var $website Website */
289
320
290
321
if (!$ website ->getDefaultGroup () || !$ website ->getDefaultGroup ()->getDefaultStore ()) {
291
322
continue ;
292
323
}
293
324
if (!$ this ->_scopeConfig ->getValue (
294
325
self ::XML_PATH_STOCK_ALLOW ,
295
- \ Magento \ Store \ Model \ ScopeInterface::SCOPE_STORE ,
326
+ ScopeInterface::SCOPE_STORE ,
296
327
$ website ->getDefaultGroup ()->getDefaultStore ()->getId ()
297
328
)
298
329
) {
299
330
continue ;
300
331
}
301
332
try {
302
- $ collection = $ this ->_stockColFactory ->create ()-> addWebsiteFilter (
303
- $ website ->getId ()
304
- ) ->addStatusFilter (
305
- 0
306
- )-> setCustomerOrder ( );
333
+ $ collection = $ this ->_stockColFactory ->create ()
334
+ -> addWebsiteFilter ( $ website ->getId () )
335
+ ->addStatusFilter (0 )
336
+ -> setCustomerOrder ()
337
+ -> addOrder ( ' product_id ' );
307
338
} catch (\Exception $ e ) {
308
339
$ this ->_errors [] = $ e ->getMessage ();
309
340
throw $ e ;
310
341
}
311
342
312
343
$ previousCustomer = null ;
313
344
$ email ->setWebsite ($ website );
314
- foreach ($ collection as $ alert ) {
345
+ foreach ($ this -> loadItems ( $ collection, $ this -> bunchSize ) as $ alert ) {
315
346
$ this ->setAlertStoreId ($ alert , $ email );
316
347
try {
317
348
if (!$ previousCustomer || $ previousCustomer ->getId () != $ alert ->getCustomerId ()) {
@@ -374,7 +405,7 @@ protected function _sendErrorEmail()
374
405
if (count ($ this ->_errors )) {
375
406
if (!$ this ->_scopeConfig ->getValue (
376
407
self ::XML_PATH_ERROR_TEMPLATE ,
377
- \ Magento \ Store \ Model \ ScopeInterface::SCOPE_STORE
408
+ ScopeInterface::SCOPE_STORE
378
409
)
379
410
) {
380
411
return $ this ;
@@ -385,24 +416,24 @@ protected function _sendErrorEmail()
385
416
$ transport = $ this ->_transportBuilder ->setTemplateIdentifier (
386
417
$ this ->_scopeConfig ->getValue (
387
418
self ::XML_PATH_ERROR_TEMPLATE ,
388
- \ Magento \ Store \ Model \ ScopeInterface::SCOPE_STORE
419
+ ScopeInterface::SCOPE_STORE
389
420
)
390
421
)->setTemplateOptions (
391
422
[
392
- 'area ' => \ Magento \ Backend \ App \ Area \ FrontNameResolver::AREA_CODE ,
393
- 'store ' => \ Magento \ Store \ Model \ Store::DEFAULT_STORE_ID ,
423
+ 'area ' => FrontNameResolver::AREA_CODE ,
424
+ 'store ' => Store::DEFAULT_STORE_ID ,
394
425
]
395
426
)->setTemplateVars (
396
427
['warnings ' => join ("\n" , $ this ->_errors )]
397
428
)->setFrom (
398
429
$ this ->_scopeConfig ->getValue (
399
430
self ::XML_PATH_ERROR_IDENTITY ,
400
- \ Magento \ Store \ Model \ ScopeInterface::SCOPE_STORE
431
+ ScopeInterface::SCOPE_STORE
401
432
)
402
433
)->addTo (
403
434
$ this ->_scopeConfig ->getValue (
404
435
self ::XML_PATH_ERROR_RECIPIENT ,
405
- \ Magento \ Store \ Model \ ScopeInterface::SCOPE_STORE
436
+ ScopeInterface::SCOPE_STORE
406
437
)
407
438
)->getTransport ();
408
439
@@ -421,7 +452,7 @@ protected function _sendErrorEmail()
421
452
*/
422
453
public function process ()
423
454
{
424
- /* @var $email \Magento\ProductAlert\Model\ Email */
455
+ /* @var $email Email */
425
456
$ email = $ this ->_emailFactory ->create ();
426
457
$ this ->_processPrice ($ email );
427
458
$ this ->_processStock ($ email );
@@ -433,11 +464,11 @@ public function process()
433
464
/**
434
465
* Set alert store id.
435
466
*
436
- * @param \Magento\ProductAlert\Model\ Price|\Magento\ProductAlert\Model\ Stock $alert
467
+ * @param Price|Stock $alert
437
468
* @param Email $email
438
469
* @return Observer
439
470
*/
440
- private function setAlertStoreId ($ alert , \ Magento \ ProductAlert \ Model \ Email $ email ) : Observer
471
+ private function setAlertStoreId ($ alert , Email $ email ): Observer
441
472
{
442
473
$ alertStoreId = $ alert ->getStoreId ();
443
474
if ($ alertStoreId ) {
@@ -446,4 +477,26 @@ private function setAlertStoreId($alert, \Magento\ProductAlert\Model\Email $emai
446
477
447
478
return $ this ;
448
479
}
480
+
481
+ /**
482
+ * Load items by bunch size
483
+ *
484
+ * @param AbstractCollection $collection
485
+ * @param int $bunchSize
486
+ * @return \Generator
487
+ */
488
+ private function loadItems (AbstractCollection $ collection , int $ bunchSize ): \Generator
489
+ {
490
+ $ collection ->setPageSize ($ bunchSize );
491
+ $ pageCount = $ collection ->getLastPageNumber ();
492
+ $ curPage = 1 ;
493
+ while ($ curPage <= $ pageCount ) {
494
+ $ collection ->clear ();
495
+ $ collection ->setCurPage ($ curPage );
496
+ foreach ($ collection as $ item ) {
497
+ yield $ item ;
498
+ }
499
+ $ curPage ++;
500
+ }
501
+ }
449
502
}
0 commit comments