Skip to content

Commit d303d7c

Browse files
author
Serhii Balko
committed
Merge remote-tracking branch 'origin/MC-41440' into 2.4-develop-pr55
2 parents 1b82d65 + d2ccf25 commit d303d7c

File tree

2 files changed

+232
-147
lines changed

2 files changed

+232
-147
lines changed

app/code/Magento/ProductAlert/Model/Observer.php

Lines changed: 119 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,27 @@
55
*/
66
namespace Magento\ProductAlert\Model;
77

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+
825
/**
926
* ProductAlert observer
1027
*
11-
* @author Magento Core Team <core@magentocommerce.com>
28+
* @author Magento Core Team <core@magentocommerce.com>
1229
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1330
*/
1431
class Observer
@@ -40,6 +57,11 @@ class Observer
4057
*/
4158
const XML_PATH_STOCK_ALLOW = 'catalog/productalert/allow_stock';
4259

60+
/**
61+
* Default value of bunch size to load alert items
62+
*/
63+
private const DEFAULT_BUNCH_SIZE = 10000;
64+
4365
/**
4466
* Website collection array
4567
*
@@ -57,59 +79,59 @@ class Observer
5779
/**
5880
* Catalog data
5981
*
60-
* @var \Magento\Catalog\Helper\Data
82+
* @var Data
6183
*/
6284
protected $_catalogData = null;
6385

6486
/**
6587
* Core store config
6688
*
67-
* @var \Magento\Framework\App\Config\ScopeConfigInterface
89+
* @var ScopeConfigInterface
6890
*/
6991
protected $_scopeConfig;
7092

7193
/**
72-
* @var \Magento\Store\Model\StoreManagerInterface
94+
* @var StoreManagerInterface
7395
*/
7496
protected $_storeManager;
7597

7698
/**
77-
* @var \Magento\ProductAlert\Model\ResourceModel\Price\CollectionFactory
99+
* @var PriceCollectionFactory
78100
*/
79101
protected $_priceColFactory;
80102

81103
/**
82-
* @var \Magento\Customer\Api\CustomerRepositoryInterface
104+
* @var CustomerRepositoryInterface
83105
*/
84106
protected $customerRepository;
85107

86108
/**
87-
* @var \Magento\Catalog\Api\ProductRepositoryInterface
109+
* @var ProductRepositoryInterface
88110
*/
89111
protected $productRepository;
90112

91113
/**
92-
* @var \Magento\Framework\Stdlib\DateTime\DateTimeFactory
114+
* @var DateTimeFactory
93115
*/
94116
protected $_dateFactory;
95117

96118
/**
97-
* @var \Magento\ProductAlert\Model\ResourceModel\Stock\CollectionFactory
119+
* @var StockCollectionFactory
98120
*/
99121
protected $_stockColFactory;
100122

101123
/**
102-
* @var \Magento\Framework\Mail\Template\TransportBuilder
124+
* @var TransportBuilder
103125
*/
104126
protected $_transportBuilder;
105127

106128
/**
107-
* @var \Magento\ProductAlert\Model\EmailFactory
129+
* @var EmailFactory
108130
*/
109131
protected $_emailFactory;
110132

111133
/**
112-
* @var \Magento\Framework\Translate\Inline\StateInterface
134+
* @var StateInterface
113135
*/
114136
protected $inlineTranslation;
115137

@@ -119,33 +141,40 @@ class Observer
119141
protected $productSalability;
120142

121143
/**
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
133160
* @param ProductSalability|null $productSalability
161+
* @param int $bunchSize
134162
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
135163
*/
136164
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
149178
) {
150179
$this->_catalogData = $catalogData;
151180
$this->_scopeConfig = $scopeConfig;
@@ -158,8 +187,9 @@ public function __construct(
158187
$this->_transportBuilder = $transportBuilder;
159188
$this->_emailFactory = $emailFactory;
160189
$this->inlineTranslation = $inlineTranslation;
161-
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
190+
$objectManager = ObjectManager::getInstance();
162191
$this->productSalability = $productSalability ?: $objectManager->get(ProductSalability::class);
192+
$this->bunchSize = $bunchSize ?: self::DEFAULT_BUNCH_SIZE;
163193
}
164194

165195
/**
@@ -184,40 +214,41 @@ protected function _getWebsites()
184214
/**
185215
* Process price emails
186216
*
187-
* @param \Magento\ProductAlert\Model\Email $email
217+
* @param Email $email
188218
* @return $this
189219
* @throws \Exception
190220
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
191221
* @SuppressWarnings(PHPMD.NPathComplexity)
192222
*/
193-
protected function _processPrice(\Magento\ProductAlert\Model\Email $email)
223+
protected function _processPrice(Email $email)
194224
{
195225
$email->setType('price');
196226
foreach ($this->_getWebsites() as $website) {
197-
/* @var $website \Magento\Store\Model\Website */
227+
/* @var $website Website */
198228
if (!$website->getDefaultGroup() || !$website->getDefaultGroup()->getDefaultStore()) {
199229
continue;
200230
}
201231
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+
)
206236
) {
207237
continue;
208238
}
209239
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');
213244
} catch (\Exception $e) {
214245
$this->_errors[] = $e->getMessage();
215246
throw $e;
216247
}
217248

218249
$previousCustomer = null;
219250
$email->setWebsite($website);
220-
foreach ($collection as $alert) {
251+
foreach ($this->loadItems($collection, $this->bunchSize) as $alert) {
221252
$this->setAlertStoreId($alert, $email);
222253
try {
223254
if (!$previousCustomer || $previousCustomer->getId() != $alert->getCustomerId()) {
@@ -274,44 +305,44 @@ protected function _processPrice(\Magento\ProductAlert\Model\Email $email)
274305
/**
275306
* Process stock emails
276307
*
277-
* @param \Magento\ProductAlert\Model\Email $email
308+
* @param Email $email
278309
* @return $this
279310
* @throws \Exception
280311
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
281312
* @SuppressWarnings(PHPMD.NPathComplexity)
282313
*/
283-
protected function _processStock(\Magento\ProductAlert\Model\Email $email)
314+
protected function _processStock(Email $email)
284315
{
285316
$email->setType('stock');
286317

287318
foreach ($this->_getWebsites() as $website) {
288-
/* @var $website \Magento\Store\Model\Website */
319+
/* @var $website Website */
289320

290321
if (!$website->getDefaultGroup() || !$website->getDefaultGroup()->getDefaultStore()) {
291322
continue;
292323
}
293324
if (!$this->_scopeConfig->getValue(
294325
self::XML_PATH_STOCK_ALLOW,
295-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
326+
ScopeInterface::SCOPE_STORE,
296327
$website->getDefaultGroup()->getDefaultStore()->getId()
297328
)
298329
) {
299330
continue;
300331
}
301332
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');
307338
} catch (\Exception $e) {
308339
$this->_errors[] = $e->getMessage();
309340
throw $e;
310341
}
311342

312343
$previousCustomer = null;
313344
$email->setWebsite($website);
314-
foreach ($collection as $alert) {
345+
foreach ($this->loadItems($collection, $this->bunchSize) as $alert) {
315346
$this->setAlertStoreId($alert, $email);
316347
try {
317348
if (!$previousCustomer || $previousCustomer->getId() != $alert->getCustomerId()) {
@@ -374,7 +405,7 @@ protected function _sendErrorEmail()
374405
if (count($this->_errors)) {
375406
if (!$this->_scopeConfig->getValue(
376407
self::XML_PATH_ERROR_TEMPLATE,
377-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
408+
ScopeInterface::SCOPE_STORE
378409
)
379410
) {
380411
return $this;
@@ -385,24 +416,24 @@ protected function _sendErrorEmail()
385416
$transport = $this->_transportBuilder->setTemplateIdentifier(
386417
$this->_scopeConfig->getValue(
387418
self::XML_PATH_ERROR_TEMPLATE,
388-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
419+
ScopeInterface::SCOPE_STORE
389420
)
390421
)->setTemplateOptions(
391422
[
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,
394425
]
395426
)->setTemplateVars(
396427
['warnings' => join("\n", $this->_errors)]
397428
)->setFrom(
398429
$this->_scopeConfig->getValue(
399430
self::XML_PATH_ERROR_IDENTITY,
400-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
431+
ScopeInterface::SCOPE_STORE
401432
)
402433
)->addTo(
403434
$this->_scopeConfig->getValue(
404435
self::XML_PATH_ERROR_RECIPIENT,
405-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
436+
ScopeInterface::SCOPE_STORE
406437
)
407438
)->getTransport();
408439

@@ -421,7 +452,7 @@ protected function _sendErrorEmail()
421452
*/
422453
public function process()
423454
{
424-
/* @var $email \Magento\ProductAlert\Model\Email */
455+
/* @var $email Email */
425456
$email = $this->_emailFactory->create();
426457
$this->_processPrice($email);
427458
$this->_processStock($email);
@@ -433,11 +464,11 @@ public function process()
433464
/**
434465
* Set alert store id.
435466
*
436-
* @param \Magento\ProductAlert\Model\Price|\Magento\ProductAlert\Model\Stock $alert
467+
* @param Price|Stock $alert
437468
* @param Email $email
438469
* @return Observer
439470
*/
440-
private function setAlertStoreId($alert, \Magento\ProductAlert\Model\Email $email) : Observer
471+
private function setAlertStoreId($alert, Email $email): Observer
441472
{
442473
$alertStoreId = $alert->getStoreId();
443474
if ($alertStoreId) {
@@ -446,4 +477,26 @@ private function setAlertStoreId($alert, \Magento\ProductAlert\Model\Email $emai
446477

447478
return $this;
448479
}
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+
}
449502
}

0 commit comments

Comments
 (0)