Skip to content

Commit a235b0f

Browse files
author
Oleksii Korshenko
authored
MAGETWO-70660: Fix getImage method when sending product alert email #10208
2 parents 2df12c4 + 5b0e6d1 commit a235b0f

File tree

4 files changed

+218
-40
lines changed

4 files changed

+218
-40
lines changed

app/code/Magento/ProductAlert/Block/Email/AbstractEmail.php

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,21 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6-
7-
// @codingStandardsIgnoreFile
8-
96
namespace Magento\ProductAlert\Block\Email;
107

118
use Magento\Framework\Pricing\PriceCurrencyInterface;
9+
use Magento\Framework\App\ObjectManager;
10+
use Magento\ProductAlert\Block\Product\ImageProvider;
1211

1312
/**
1413
* Product Alert Abstract Email Block
15-
*
16-
* @author Magento Core Team <core@magentocommerce.com>
1714
*/
1815
abstract class AbstractEmail extends \Magento\Framework\View\Element\Template
1916
{
2017
/**
2118
* Product collection array
2219
*
23-
* @var array
20+
* @var \Magento\Catalog\Model\Product[]
2421
*/
2522
protected $_products = [];
2623

@@ -42,36 +39,45 @@ abstract class AbstractEmail extends \Magento\Framework\View\Element\Template
4239
protected $priceCurrency;
4340

4441
/**
45-
* @var \Magento\Catalog\Helper\Image
42+
* @var \Magento\Catalog\Block\Product\ImageBuilder
4643
*/
4744
protected $imageBuilder;
4845

46+
/**
47+
* @var ImageProvider
48+
*/
49+
private $imageProvider;
50+
4951
/**
5052
* @param \Magento\Framework\View\Element\Template\Context $context
5153
* @param \Magento\Framework\Filter\Input\MaliciousCode $maliciousCode
5254
* @param PriceCurrencyInterface $priceCurrency
5355
* @param \Magento\Catalog\Block\Product\ImageBuilder $imageBuilder
5456
* @param array $data
57+
* @param ImageProvider $imageProvider
5558
*/
5659
public function __construct(
5760
\Magento\Framework\View\Element\Template\Context $context,
5861
\Magento\Framework\Filter\Input\MaliciousCode $maliciousCode,
5962
PriceCurrencyInterface $priceCurrency,
6063
\Magento\Catalog\Block\Product\ImageBuilder $imageBuilder,
61-
array $data = []
64+
array $data = [],
65+
ImageProvider $imageProvider = null
6266
) {
6367
$this->imageBuilder = $imageBuilder;
6468
$this->priceCurrency = $priceCurrency;
6569
$this->_maliciousCode = $maliciousCode;
70+
$this->imageProvider = $imageProvider ?: ObjectManager::getInstance()->get(ImageProvider::class);
71+
6672
parent::__construct($context, $data);
6773
}
6874

6975
/**
70-
* Filter malicious code before insert content to email
71-
*
72-
* @param string|array $content
73-
* @return string|array
74-
*/
76+
* Filter malicious code before insert content to email
77+
*
78+
* @param string|array $content
79+
* @return string|array
80+
*/
7581
public function getFilteredContent($content)
7682
{
7783
return $this->_maliciousCode->filter($content);
@@ -104,7 +110,7 @@ public function setStore($store)
104110
*/
105111
public function getStore()
106112
{
107-
if (is_null($this->_store)) {
113+
if ($this->_store === null) {
108114
$this->_store = $this->_storeManager->getStore();
109115
}
110116
return $this->_store;
@@ -114,9 +120,9 @@ public function getStore()
114120
* Convert price from default currency to current currency
115121
*
116122
* @param float $price
117-
* @param boolean $format Format price to currency format
118-
* @param boolean $includeContainer Enclose into <span class="price"><span>
119-
* @return float
123+
* @param bool $format Format price to currency format
124+
* @param bool $includeContainer Enclose into <span class="price"><span>
125+
* @return float|string
120126
*/
121127
public function formatPrice($price, $format = true, $includeContainer = true)
122128
{
@@ -149,7 +155,7 @@ public function addProduct(\Magento\Catalog\Model\Product $product)
149155
/**
150156
* Retrieve product collection array
151157
*
152-
* @return array
158+
* @return \Magento\Catalog\Model\Product[]
153159
*/
154160
public function getProducts()
155161
{
@@ -212,7 +218,7 @@ public function getProductPriceHtml(
212218
}
213219

214220
/**
215-
* Retrieve product image
221+
* Retrieve product image.
216222
*
217223
* @param \Magento\Catalog\Model\Product $product
218224
* @param string $imageId
@@ -221,9 +227,6 @@ public function getProductPriceHtml(
221227
*/
222228
public function getImage($product, $imageId, $attributes = [])
223229
{
224-
return $this->imageBuilder->setProduct($product)
225-
->setImageId($imageId)
226-
->setAttributes($attributes)
227-
->create();
230+
return $this->imageProvider->getImage($product, $imageId, $attributes);
228231
}
229232
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\ProductAlert\Block\Product;
7+
8+
use Magento\Store\Model\App\Emulation;
9+
use Magento\Catalog\Block\Product\ImageBuilder;
10+
use Magento\Catalog\Model\Product;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
use Magento\Framework\App\Area;
13+
use Magento\Catalog\Block\Product\Image;
14+
15+
/**
16+
* Provides product image to be used in the Product Alert Email.
17+
*/
18+
class ImageProvider
19+
{
20+
/**
21+
* @var ImageBuilder
22+
*/
23+
private $imageBuilder;
24+
25+
/**
26+
* @var StoreManagerInterface
27+
*/
28+
private $storeManager;
29+
30+
/**
31+
* @var Emulation
32+
*/
33+
private $appEmulation;
34+
35+
/**
36+
* @param ImageBuilder $imageBuilder
37+
* @param StoreManagerInterface $storeManager
38+
* @param Emulation $appEmulation
39+
*/
40+
public function __construct(
41+
ImageBuilder $imageBuilder,
42+
StoreManagerInterface $storeManager,
43+
Emulation $appEmulation
44+
) {
45+
$this->imageBuilder = $imageBuilder;
46+
$this->storeManager = $storeManager;
47+
$this->appEmulation = $appEmulation;
48+
}
49+
50+
/**
51+
* @param Product $product
52+
* @param string $imageId
53+
* @param array $attributes
54+
* @return Image
55+
* @throws \Exception
56+
*/
57+
public function getImage(Product $product, $imageId, $attributes = [])
58+
{
59+
$storeId = $this->storeManager->getStore()->getId();
60+
$this->appEmulation->startEnvironmentEmulation($storeId, Area::AREA_FRONTEND, true);
61+
62+
try {
63+
$image = $this->imageBuilder->setProduct($product)
64+
->setImageId($imageId)
65+
->setAttributes($attributes)
66+
->create();
67+
} catch (\Exception $exception) {
68+
$this->appEmulation->stopEnvironmentEmulation();
69+
throw $exception;
70+
}
71+
72+
$this->appEmulation->stopEnvironmentEmulation();
73+
return $image;
74+
}
75+
}

app/code/Magento/ProductAlert/Test/Unit/Block/Email/StockTest.php

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ class StockTest extends \PHPUnit_Framework_TestCase
2525
*/
2626
protected $imageBuilder;
2727

28+
/**
29+
* @var \Magento\ProductAlert\Block\Product\ImageProvider|\PHPUnit_Framework_MockObject_MockObject
30+
*/
31+
private $imageProviderMock;
32+
2833
protected function setUp()
2934
{
3035
$objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -40,11 +45,16 @@ protected function setUp()
4045
->disableOriginalConstructor()
4146
->getMock();
4247

48+
$this->imageProviderMock = $this->getMockBuilder(\Magento\ProductAlert\Block\Product\ImageProvider::class)
49+
->disableOriginalConstructor()
50+
->getMock();
51+
4352
$this->_block = $objectManager->getObject(
4453
\Magento\ProductAlert\Block\Email\Stock::class,
4554
[
4655
'maliciousCode' => $this->_filter,
4756
'imageBuilder' => $this->imageBuilder,
57+
'imageProvider' => $this->imageProviderMock
4858
]
4959
);
5060
}
@@ -77,26 +87,11 @@ public function testGetImage()
7787
$productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
7888
->disableOriginalConstructor()
7989
->getMock();
80-
81-
$imageMock = $this->getMockBuilder(\Magento\Catalog\Block\Product\Image::class)
90+
$productImageMock = $this->getMockBuilder(\Magento\Catalog\Block\Product\Image::class)
8291
->disableOriginalConstructor()
8392
->getMock();
8493

85-
$this->imageBuilder->expects($this->once())
86-
->method('setProduct')
87-
->with($productMock)
88-
->willReturnSelf();
89-
$this->imageBuilder->expects($this->once())
90-
->method('setImageId')
91-
->with($imageId)
92-
->willReturnSelf();
93-
$this->imageBuilder->expects($this->once())
94-
->method('setAttributes')
95-
->with($attributes)
96-
->willReturnSelf();
97-
$this->imageBuilder->expects($this->once())
98-
->method('create')
99-
->willReturn($imageMock);
94+
$this->imageProviderMock->expects($this->atLeastOnce())->method('getImage')->willReturn($productImageMock);
10095

10196
$this->assertInstanceOf(
10297
\Magento\Catalog\Block\Product\Image::class,
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\ProductAlert\Test\Unit\Block\Product;
7+
8+
class ImageProviderTest extends \PHPUnit_Framework_TestCase
9+
{
10+
/**
11+
* @var \Magento\Catalog\Block\Product\ImageBuilder|\PHPUnit_Framework_MockObject_MockObject
12+
*/
13+
private $imageBuilderMock;
14+
15+
/**
16+
* @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
17+
*/
18+
private $storeManagerMock;
19+
20+
/**
21+
* @var \Magento\Store\Model\App\Emulation|\PHPUnit_Framework_MockObject_MockObject
22+
*/
23+
private $emulationMock;
24+
25+
/**
26+
* @var \Magento\ProductAlert\Block\Product\ImageProvider
27+
*/
28+
private $model;
29+
30+
protected function setUp()
31+
{
32+
$this->imageBuilderMock = $this->getMockBuilder(\Magento\Catalog\Block\Product\ImageBuilder::class)
33+
->disableOriginalConstructor()
34+
->getMock();
35+
$this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
36+
->disableOriginalConstructor()
37+
->getMock();
38+
$this->emulationMock = $this->getMockBuilder(\Magento\Store\Model\App\Emulation::class)
39+
->disableOriginalConstructor()
40+
->getMock();
41+
42+
$this->model = new \Magento\ProductAlert\Block\Product\ImageProvider(
43+
$this->imageBuilderMock,
44+
$this->storeManagerMock,
45+
$this->emulationMock
46+
);
47+
}
48+
49+
/**
50+
* Test that image is created successfully with app emulation enabled.
51+
*/
52+
public function testGetImage()
53+
{
54+
$imageId = 'test_image_id';
55+
$attributes = [];
56+
57+
$productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
58+
->disableOriginalConstructor()
59+
->getMock();
60+
$imageMock = $this->getMockBuilder(\Magento\Catalog\Block\Product\Image::class)
61+
->disableOriginalConstructor()
62+
->getMock();
63+
$storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
64+
->disableOriginalConstructor()
65+
->getMock();
66+
67+
$this->storeManagerMock->expects($this->atLeastOnce())->method('getStore')->willReturn($storeMock);
68+
$storeMock->expects($this->atLeastOnce())->method('getId')->willReturn(42);
69+
$this->emulationMock->expects($this->once())->method('startEnvironmentEmulation');
70+
$this->imageBuilderMock->expects($this->once())->method('setProduct')->with($productMock)->willReturnSelf();
71+
$this->imageBuilderMock->expects($this->once())->method('setImageId')->with($imageId)->willReturnSelf();
72+
$this->imageBuilderMock->expects($this->once())->method('setAttributes')->with($attributes)->willReturnSelf();
73+
$this->imageBuilderMock->expects($this->once())->method('create')->willReturn($imageMock);
74+
$this->emulationMock->expects($this->once())->method('stopEnvironmentEmulation');
75+
76+
$this->assertEquals($imageMock, $this->model->getImage($productMock, $imageId, $attributes));
77+
}
78+
79+
/**
80+
* Test that app emulation stops when exception occurs.
81+
*
82+
* @expectedException \Exception
83+
* @expectedExceptionMessage Image Builder Exception
84+
*/
85+
public function testGetImageThrowsAnException()
86+
{
87+
$productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
88+
->disableOriginalConstructor()
89+
->getMock();
90+
$storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
91+
->disableOriginalConstructor()
92+
->getMock();
93+
94+
$this->emulationMock->expects($this->once())->method('startEnvironmentEmulation');
95+
$this->storeManagerMock->expects($this->atLeastOnce())->method('getStore')->willReturn($storeMock);
96+
$storeMock->expects($this->atLeastOnce())->method('getId')->willReturn(42);
97+
98+
$this->imageBuilderMock->expects($this->once())
99+
->method('setProduct')
100+
->willThrowException(new \Exception("Image Builder Exception"));
101+
102+
$this->emulationMock->expects($this->once())->method('stopEnvironmentEmulation');
103+
$this->model->getImage($productMock, 1);
104+
}
105+
}

0 commit comments

Comments
 (0)