diff --git a/app/code/Magento/ProductAlert/Model/Email.php b/app/code/Magento/ProductAlert/Model/Email.php index 7bc4aba351546..8f69a6fb4c7d2 100644 --- a/app/code/Magento/ProductAlert/Model/Email.php +++ b/app/code/Magento/ProductAlert/Model/Email.php @@ -1,10 +1,36 @@ _productAlertData = $productAlertData; @@ -153,6 +179,7 @@ public function __construct( * Set model type * * @param string $type + * * @return void */ public function setType($type) @@ -173,7 +200,8 @@ public function getType() /** * Set website model * - * @param \Magento\Store\Model\Website $website + * @param Website $website + * * @return $this */ public function setWebsite(\Magento\Store\Model\Website $website) @@ -186,7 +214,9 @@ public function setWebsite(\Magento\Store\Model\Website $website) * Set website id * * @param int $websiteId + * * @return $this + * @throws LocalizedException */ public function setWebsiteId($websiteId) { @@ -198,7 +228,10 @@ public function setWebsiteId($websiteId) * Set customer by id * * @param int $customerId + * * @return $this + * @throws LocalizedException + * @throws NoSuchEntityException */ public function setCustomerId($customerId) { @@ -209,7 +242,8 @@ public function setCustomerId($customerId) /** * Set customer model * - * @param \Magento\Customer\Api\Data\CustomerInterface $customer + * @param CustomerInterface $customer + * * @return $this */ public function setCustomerData($customer) @@ -235,7 +269,8 @@ public function clean() /** * Add product (price change) to collection * - * @param \Magento\Catalog\Model\Product $product + * @param Product $product + * * @return $this */ public function addPriceProduct(\Magento\Catalog\Model\Product $product) @@ -247,7 +282,8 @@ public function addPriceProduct(\Magento\Catalog\Model\Product $product) /** * Add product (back in stock) to collection * - * @param \Magento\Catalog\Model\Product $product + * @param Product $product + * * @return $this */ public function addStockProduct(\Magento\Catalog\Model\Product $product) @@ -259,12 +295,13 @@ public function addStockProduct(\Magento\Catalog\Model\Product $product) /** * Retrieve price block * - * @return \Magento\ProductAlert\Block\Email\Price + * @return Price + * @throws LocalizedException */ protected function _getPriceBlock() { if ($this->_priceBlock === null) { - $this->_priceBlock = $this->_productAlertData->createBlock(\Magento\ProductAlert\Block\Email\Price::class); + $this->_priceBlock = $this->_productAlertData->createBlock(Price::class); } return $this->_priceBlock; } @@ -272,12 +309,13 @@ protected function _getPriceBlock() /** * Retrieve stock block * - * @return \Magento\ProductAlert\Block\Email\Stock + * @return Stock + * @throws LocalizedException */ protected function _getStockBlock() { if ($this->_stockBlock === null) { - $this->_stockBlock = $this->_productAlertData->createBlock(\Magento\ProductAlert\Block\Email\Stock::class); + $this->_stockBlock = $this->_productAlertData->createBlock(Stock::class); } return $this->_stockBlock; } @@ -286,110 +324,133 @@ protected function _getStockBlock() * Send customer email * * @return bool - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @throws MailException + * @throws NoSuchEntityException + * @throws LocalizedException */ public function send() { if ($this->_website === null || $this->_customer === null) { return false; } - if ($this->_type == 'price' && count( - $this->_priceProducts - ) == 0 || $this->_type == 'stock' && count( - $this->_stockProducts - ) == 0 - ) { - return false; - } + if (!$this->_website->getDefaultGroup() || !$this->_website->getDefaultGroup()->getDefaultStore()) { return false; } - if ($this->_customer->getStoreId() > 0) { - $store = $this->_storeManager->getStore($this->_customer->getStoreId()); - } else { - $store = $this->_website->getDefaultStore(); + if (!in_array($this->_type, ['price', 'stock'])) { + return false; } - $storeId = $store->getId(); - if ($this->_type == 'price' && !$this->_scopeConfig->getValue( - self::XML_PATH_EMAIL_PRICE_TEMPLATE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, - $storeId - ) - ) { - return false; - } elseif ($this->_type == 'stock' && !$this->_scopeConfig->getValue( - self::XML_PATH_EMAIL_STOCK_TEMPLATE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, - $storeId - ) - ) { + $products = $this->getProducts(); + if (count($products) === 0) { return false; } - if ($this->_type != 'price' && $this->_type != 'stock') { + $templateConfigPath = $this->getTemplateConfigPath(); + if (!$templateConfigPath) { return false; } + $store = $this->getStore((int) $this->_customer->getStoreId()); + $storeId = $store->getId(); + $this->_appEmulation->startEnvironmentEmulation($storeId); - if ($this->_type == 'price') { - $this->_getPriceBlock()->setStore($store)->reset(); - foreach ($this->_priceProducts as $product) { - $product->setCustomerGroupId($this->_customer->getGroupId()); - $this->_getPriceBlock()->addProduct($product); - } - $block = $this->_getPriceBlock(); - $templateId = $this->_scopeConfig->getValue( - self::XML_PATH_EMAIL_PRICE_TEMPLATE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, - $storeId - ); - } else { - $this->_getStockBlock()->setStore($store)->reset(); - foreach ($this->_stockProducts as $product) { - $product->setCustomerGroupId($this->_customer->getGroupId()); - $this->_getStockBlock()->addProduct($product); - } - $block = $this->_getStockBlock(); - $templateId = $this->_scopeConfig->getValue( - self::XML_PATH_EMAIL_STOCK_TEMPLATE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, - $storeId - ); + $block = $this->getBlock(); + $block->setStore($store)->reset(); + + // Add products to the block + foreach ($products as $product) { + $product->setCustomerGroupId($this->_customer->getGroupId()); + $block->addProduct($product); } + $templateId = $this->_scopeConfig->getValue( + $templateConfigPath, + ScopeInterface::SCOPE_STORE, + $storeId + ); + $alertGrid = $this->_appState->emulateAreaCode( - \Magento\Framework\App\Area::AREA_FRONTEND, + Area::AREA_FRONTEND, [$block, 'toHtml'] ); $this->_appEmulation->stopEnvironmentEmulation(); - $transport = $this->_transportBuilder->setTemplateIdentifier( + $customerName = $this->_customerHelper->getCustomerName($this->_customer); + $this->_transportBuilder->setTemplateIdentifier( $templateId )->setTemplateOptions( - ['area' => \Magento\Framework\App\Area::AREA_FRONTEND, 'store' => $storeId] + ['area' => Area::AREA_FRONTEND, 'store' => $storeId] )->setTemplateVars( [ - 'customerName' => $this->_customerHelper->getCustomerName($this->_customer), + 'customerName' => $customerName, 'alertGrid' => $alertGrid, ] )->setFrom( $this->_scopeConfig->getValue( self::XML_PATH_EMAIL_IDENTITY, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORE, $storeId ) )->addTo( $this->_customer->getEmail(), - $this->_customerHelper->getCustomerName($this->_customer) - )->getTransport(); - - $transport->sendMessage(); + $customerName + )->getTransport()->sendMessage(); return true; } + + /** + * Retrieve the store for the email + * + * @param int|null $customerStoreId + * + * @return StoreInterface + * @throws NoSuchEntityException + */ + private function getStore(?int $customerStoreId): StoreInterface + { + return $customerStoreId > 0 + ? $this->_storeManager->getStore($customerStoreId) + : $this->_website->getDefaultStore(); + } + + /** + * Retrieve the block for the email based on type + * + * @return Price|Stock + * @throws LocalizedException + */ + private function getBlock(): AbstractEmail + { + return $this->_type === 'price' + ? $this->_getPriceBlock() + : $this->_getStockBlock(); + } + + /** + * Retrieve the products for the email based on type + * + * @return array + */ + private function getProducts(): array + { + return $this->_type === 'price' + ? $this->_priceProducts + : $this->_stockProducts; + } + + /** + * Retrieve template config path based on type + * + * @return string + */ + private function getTemplateConfigPath(): string + { + return $this->_type === 'price' + ? self::XML_PATH_EMAIL_PRICE_TEMPLATE + : self::XML_PATH_EMAIL_STOCK_TEMPLATE; + } } diff --git a/app/code/Magento/ProductAlert/Test/Unit/Model/ObserverTest.php b/app/code/Magento/ProductAlert/Test/Unit/Model/ObserverTest.php index 9cd8546a0180b..e3a2056a89ec0 100644 --- a/app/code/Magento/ProductAlert/Test/Unit/Model/ObserverTest.php +++ b/app/code/Magento/ProductAlert/Test/Unit/Model/ObserverTest.php @@ -5,6 +5,7 @@ */ namespace Magento\ProductAlert\Test\Unit\Model; +use Magento\Customer\Api\Data\CustomerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\ProductAlert\Model\ProductSalability; @@ -115,6 +116,9 @@ class ObserverTest extends \PHPUnit\Framework\TestCase */ private $productSalabilityMock; + /** + * @return void + */ protected function setUp() { $this->objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) @@ -296,8 +300,8 @@ public function testProcessPriceEmailThrowsException() ->method('setCustomerOrder') ->willReturn(new \ArrayIterator($items)); - $customer = new \Magento\Framework\DataObject(['group_id' => $id]); - $this->customerRepositoryMock->expects($this->once())->method('getById')->willReturn($customer); + $customerMock = $this->getMockForAbstractClass(CustomerInterface::class); + $this->customerRepositoryMock->expects($this->once())->method('getById')->willReturn($customerMock); $this->productMock->expects($this->once())->method('setCustomerGroupId')->willReturnSelf(); $this->productMock->expects($this->once())->method('getFinalPrice')->willReturn('655.99'); @@ -368,7 +372,6 @@ public function testProcessStockCustomerRepositoryThrowsException() */ public function testProcessStockEmailThrowsException() { - $id = 1; $this->scopeConfigMock->expects($this->any())->method('isSetFlag')->willReturn(false); $this->emailFactoryMock->expects($this->once())->method('create')->willReturn($this->emailMock); @@ -395,8 +398,8 @@ public function testProcessStockEmailThrowsException() ->method('setCustomerOrder') ->willReturn(new \ArrayIterator($items)); - $customer = new \Magento\Framework\DataObject(['group_id' => $id]); - $this->customerRepositoryMock->expects($this->once())->method('getById')->willReturn($customer); + $customerMock = $this->getMockForAbstractClass(CustomerInterface::class); + $this->customerRepositoryMock->expects($this->once())->method('getById')->willReturn($customerMock); $this->productMock->expects($this->once())->method('setCustomerGroupId')->willReturnSelf(); $this->productSalabilityMock->expects($this->once())->method('isSalable')->willReturn(false);