Skip to content

Commit 8b7c710

Browse files
author
Karpenko, Oleksandr
committed
MAGETWO-57656: Base url should be processed while sending email
1 parent 3bcc1c9 commit 8b7c710

File tree

6 files changed

+223
-25
lines changed

6 files changed

+223
-25
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Email\Model\Template\Css;
7+
8+
use Magento\Framework\View\Asset\NotationResolver\Variable;
9+
use Magento\Framework\View\Asset\Repository;
10+
11+
class Processor
12+
{
13+
/**
14+
* List of css placeholders
15+
*
16+
* @var array
17+
*/
18+
private $placeholders = [
19+
'base_url_path',
20+
'locale'
21+
];
22+
23+
/**
24+
* @var Repository
25+
*/
26+
private $assetRepository;
27+
28+
/**
29+
* @param Repository $assetRepository
30+
*/
31+
public function __construct(
32+
Repository $assetRepository
33+
) {
34+
$this->assetRepository = $assetRepository;
35+
}
36+
37+
/**
38+
* Process css placeholders
39+
*
40+
* @param string $css
41+
* @return string
42+
*/
43+
public function process($css)
44+
{
45+
$matches = [];
46+
if (preg_match_all(Variable::VAR_REGEX, $css, $matches, PREG_SET_ORDER)) {
47+
$replacements = [];
48+
foreach ($matches as $match) {
49+
if (!isset($replacements[$match[0]])) {
50+
$replacements[$match[0]] = $this->getPlaceholderValue($match[1]);
51+
}
52+
}
53+
$css = str_replace(array_keys($replacements), $replacements, $css);
54+
}
55+
return $css;
56+
}
57+
58+
/**
59+
* Retrieve placeholder value
60+
*
61+
* @param string $placeholder
62+
* @return string
63+
*/
64+
private function getPlaceholderValue($placeholder)
65+
{
66+
/** @var \Magento\Framework\View\Asset\File\FallbackContext $context */
67+
$context = $this->assetRepository->getStaticViewFileContext();
68+
69+
switch ($placeholder) {
70+
case 'base_url_path':
71+
return $context->getBaseUrl();
72+
case 'locale':
73+
return $context->getLocale();
74+
default:
75+
return '';
76+
}
77+
}
78+
}

app/code/Magento/Email/Model/Template/Filter.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\Email\Model\Template;
77

8+
use Magento\Framework\App\ObjectManager;
89
use Magento\Framework\View\Asset\ContentProcessorException;
910
use Magento\Framework\View\Asset\ContentProcessorInterface;
1011

@@ -153,6 +154,11 @@ class Filter extends \Magento\Framework\Filter\Template
153154
*/
154155
protected $configVariables;
155156

157+
/**
158+
* @var \Magento\Email\Model\Template\Css\Processor
159+
*/
160+
private $cssProcessor;
161+
156162
/**
157163
* @param \Magento\Framework\Stdlib\StringUtils $string
158164
* @param \Psr\Log\LoggerInterface $logger
@@ -203,6 +209,18 @@ public function __construct(
203209
parent::__construct($string, $variables);
204210
}
205211

212+
/**
213+
* @deprecated
214+
* @return Css\Processor
215+
*/
216+
private function getCssProcessor()
217+
{
218+
if (!$this->cssProcessor) {
219+
$this->cssProcessor = ObjectManager::getInstance()->get(Css\Processor::class);
220+
}
221+
return $this->cssProcessor;
222+
}
223+
206224
/**
207225
* Set use absolute links flag
208226
*
@@ -788,7 +806,9 @@ public function cssDirective($construction)
788806
return '/* ' . __('"file" parameter must be specified') . ' */';
789807
}
790808

791-
$css = $this->getCssFilesContent([$params['file']]);
809+
$css = $this->getCssProcessor()->process(
810+
$this->getCssFilesContent([$params['file']])
811+
);
792812

793813
if (strpos($css, ContentProcessorInterface::ERROR_MESSAGE_PREFIX) !== false) {
794814
// Return compilation error wrapped in CSS comment
@@ -914,6 +934,8 @@ public function applyInlineCss($html)
914934
$cssToInline = $this->getCssFilesContent(
915935
$this->getInlineCssFiles()
916936
);
937+
$cssToInline = $this->getCssProcessor()->process($cssToInline);
938+
917939
// Only run Emogrify if HTML and CSS contain content
918940
if ($html && $cssToInline) {
919941
try {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Emai\Test\Unit\Model\Template\Css;
7+
8+
use Magento\Email\Model\Template\Css\Processor;
9+
use Magento\Framework\View\Asset\File\FallbackContext;
10+
use Magento\Framework\View\Asset\Repository;
11+
12+
class ProcessorTest extends \PHPUnit_Framework_TestCase
13+
{
14+
/**
15+
* @var Processor
16+
*/
17+
protected $processor;
18+
19+
/**
20+
* @var Repository|\PHPUnit_Framework_MockObject_MockObject
21+
*/
22+
protected $assetRepository;
23+
24+
/**
25+
* @var FallbackContext|\PHPUnit_Framework_MockObject_MockObject
26+
*/
27+
protected $fallbackContext;
28+
29+
public function setUp()
30+
{
31+
$this->assetRepository = $this->getMockBuilder(Repository::class)
32+
->disableOriginalConstructor()
33+
->getMock();
34+
$this->fallbackContext = $this->getMockBuilder(FallbackContext::class)
35+
->disableOriginalConstructor()
36+
->getMock();
37+
38+
$this->processor = new Processor($this->assetRepository);
39+
}
40+
41+
public function testProcess()
42+
{
43+
$url = 'http://magento.local/pub/static/';
44+
$locale = 'en_US';
45+
$css = '@import url("{{base_url_path}}frontend/_view/{{locale}}/css/email.css");';
46+
$expectedCss = '@import url("' . $url . 'frontend/_view/' . $locale . '/css/email.css");';
47+
48+
$this->assetRepository->expects($this->exactly(2))
49+
->method('getStaticViewFileContext')
50+
->willReturn($this->fallbackContext);
51+
$this->fallbackContext->expects($this->once())
52+
->method('getBaseUrl')
53+
->willReturn($url);
54+
$this->fallbackContext->expects($this->once())
55+
->method('getLocale')
56+
->willReturn($locale);
57+
$this->assertEquals($expectedCss, $this->processor->process($css));
58+
}
59+
}

app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* See COPYING.txt for license details.
55
*/
66
namespace Magento\Email\Test\Unit\Model\Template;
7+
use Magento\Email\Model\Template\Css\Processor;
8+
use Magento\Email\Model\Template\Filter;
79

810
/**
911
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -94,7 +96,6 @@ protected function setUp()
9496

9597
$this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class)
9698
->disableOriginalConstructor()
97-
->enableProxyingToOriginalMethods()
9899
->getMock();
99100

100101
$this->assetRepo = $this->getMockBuilder(\Magento\Framework\View\Asset\Repository::class)
@@ -138,7 +139,7 @@ protected function setUp()
138139

139140
/**
140141
* @param array|null $mockedMethods Methods to mock
141-
* @return \Magento\Email\Model\Template\Filter|\PHPUnit_Framework_MockObject_MockObject
142+
* @return Filter|\PHPUnit_Framework_MockObject_MockObject
142143
*/
143144
protected function getModel($mockedMethods = null)
144145
{
@@ -252,6 +253,16 @@ public function transDirectiveDataProvider()
252253
public function testApplyInlineCss($html, $css, $expectedResults)
253254
{
254255
$filter = $this->getModel(['getCssFilesContent']);
256+
$cssProcessor = $this->getMockBuilder(Processor::class)
257+
->disableOriginalConstructor()
258+
->getMock();
259+
$reflectionClass = new \ReflectionClass(Filter::class);
260+
$reflectionProperty = $reflectionClass->getProperty('cssProcessor');
261+
$reflectionProperty->setAccessible(true);
262+
$reflectionProperty->setValue($filter, $cssProcessor);
263+
$cssProcessor->expects($this->any())
264+
->method('process')
265+
->willReturnArgument(0);
255266

256267
$filter->expects($this->exactly(count($expectedResults)))
257268
->method('getCssFilesContent')
@@ -301,7 +312,19 @@ public function applyInlineCssDataProvider()
301312
*/
302313
public function testApplyInlineCssThrowsExceptionWhenDesignParamsNotSet()
303314
{
304-
$this->getModel()->applyInlineCss('test');
315+
$filter = $this->getModel();
316+
$cssProcessor = $this->getMockBuilder(Processor::class)
317+
->disableOriginalConstructor()
318+
->getMock();
319+
$reflectionClass = new \ReflectionClass(Filter::class);
320+
$reflectionProperty = $reflectionClass->getProperty('cssProcessor');
321+
$reflectionProperty->setAccessible(true);
322+
$reflectionProperty->setValue($filter, $cssProcessor);
323+
$cssProcessor->expects($this->any())
324+
->method('process')
325+
->willReturnArgument(0);
326+
327+
$filter->applyInlineCss('test');
305328
}
306329

307330
/**
@@ -348,7 +371,10 @@ public function testConfigDirectiveAvailable()
348371
$construction = ["{{config path={$path}}}", 'config', " path={$path}"];
349372
$scopeConfigValue = 'value';
350373

351-
$storeMock = $this->getMock(\Magento\Store\Api\Data\StoreInterface::class, [], [], '', false);
374+
$storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
375+
->disableOriginalConstructor()
376+
->getMock();
377+
352378
$this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
353379
$storeMock->expects($this->once())->method('getId')->willReturn(1);
354380

@@ -369,7 +395,9 @@ public function testConfigDirectiveUnavailable()
369395
$construction = ["{{config path={$path}}}", 'config', " path={$path}"];
370396
$scopeConfigValue = '';
371397

372-
$storeMock = $this->getMock(\Magento\Store\Api\Data\StoreInterface::class, [], [], '', false);
398+
$storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
399+
->disableOriginalConstructor()
400+
->getMock();
373401
$this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
374402
$storeMock->expects($this->once())->method('getId')->willReturn(1);
375403

lib/internal/Magento/Framework/View/Asset/NotationResolver/Variable.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function convertVariableNotation($path)
4949
$replacements = [];
5050
foreach ($matches as $match) {
5151
if (!isset($replacements[$match[0]])) {
52-
$replacements[$match[0]] = $this->getPlaceholderValue($match[1]);
52+
$replacements[$match[0]] = $this->preProcessPlaceholder($match[1]);
5353
}
5454
}
5555
$path = str_replace(array_keys($replacements), $replacements, $path);
@@ -58,18 +58,21 @@ public function convertVariableNotation($path)
5858
}
5959

6060
/**
61-
* Retrieves the value of a given placeholder
61+
* Process placeholder
6262
*
6363
* @param string $placeholder
6464
* @return string
6565
*/
66-
public function getPlaceholderValue($placeholder)
66+
public function preProcessPlaceholder($placeholder)
6767
{
68+
/** @var \Magento\Framework\View\Asset\File\FallbackContext $context */
6869
$context = $this->assetRepo->getStaticViewFileContext();
6970

7071
switch ($placeholder) {
7172
case self::VAR_BASE_URL_PATH:
72-
return $context->getBaseUrl() . $context->getPath();
73+
return '{{' . self::VAR_BASE_URL_PATH . '}}/' . $context->getAreaCode() .
74+
($context->getThemePath() ? '/' . $context->getThemePath() . '/' : '') .
75+
'{{locale}}';
7376
default:
7477
return '';
7578
}

lib/internal/Magento/Framework/View/Test/Unit/Asset/NotationResolver/VariableTest.php

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,51 @@
66

77
namespace Magento\Framework\View\Test\Unit\Asset\NotationResolver;
88

9-
use Magento\Framework\App\Filesystem\DirectoryList;
10-
use Magento\Framework\View\Asset\NotationResolver;
9+
use Magento\Framework\UrlInterface;
10+
use Magento\Framework\View\Asset\File\FallbackContext;
11+
use Magento\Framework\View\Asset\NotationResolver\Variable;
12+
use Magento\Framework\View\Asset\Repository;
1113

1214
class VariableTest extends \PHPUnit_Framework_TestCase
1315
{
1416
/**
15-
* @var \Magento\Framework\View\Asset\File\Context|\PHPUnit_Framework_MockObject_MockObject
17+
* @var FallbackContext|\PHPUnit_Framework_MockObject_MockObject
1618
*/
1719
private $context;
1820

1921
/**
20-
* @var \Magento\Framework\View\Asset\Repository|\PHPUnit_Framework_MockObject_MockObject
22+
* @var Repository|\PHPUnit_Framework_MockObject_MockObject
2123
*/
2224
private $assetRepo;
2325

2426
/**
25-
* @var \Magento\Framework\View\Asset\NotationResolver\Variable
27+
* @var Variable
2628
*/
2729
private $object;
2830

2931
protected function setUp()
3032
{
31-
$baseUrl = 'http://example.com/pub/static/';
32-
$path = 'frontend/Magento/blank/en_US';
33+
$area = 'frontend';
34+
$themePath = 'Magento/blank';
3335

34-
$this->context = $this->getMock(
35-
\Magento\Framework\View\Asset\File\Context::class,
36-
null,
37-
[$baseUrl, DirectoryList::STATIC_VIEW, $path]
38-
);
36+
$this->context = $this->getMockBuilder(FallbackContext::class)
37+
->disableOriginalConstructor()
38+
->getMock();
39+
$this->context->expects($this->once())
40+
->method('getAreaCode')
41+
->willReturn($area);
42+
$this->context->expects($this->exactly(2))
43+
->method('getThemePath')
44+
->willReturn($themePath);
3945

40-
$this->assetRepo = $this->getMock(\Magento\Framework\View\Asset\Repository::class, [], [], '', false);
46+
$this->assetRepo = $this->getMockBuilder(Repository::class)
47+
->disableOriginalConstructor()
48+
->getMock();
4149
$this->assetRepo->expects($this->any())
4250
->method('getStaticViewFileContext')
4351
->will($this->returnValue($this->context));
4452

45-
$this->object = new \Magento\Framework\View\Asset\NotationResolver\Variable($this->assetRepo);
53+
$this->object = new Variable($this->assetRepo);
4654
}
4755

4856
/**
@@ -61,7 +69,7 @@ public function testConvertVariableNotation($path, $expectedResult)
6169
public function convertVariableNotationDataProvider()
6270
{
6371
return [
64-
['{{base_url_path}}/file.ext', 'http://example.com/pub/static/frontend/Magento/blank/en_US/file.ext'],
72+
['{{base_url_path}}/file.ext', '{{base_url_path}}/frontend/Magento/blank/{{locale}}/file.ext'],
6573
];
6674
}
6775
}

0 commit comments

Comments
 (0)