Skip to content

Commit

Permalink
Merge pull request #385 from magento-frontend/bugs-pr
Browse files Browse the repository at this point in the history
Bugs
MAGETWO-57656 Base url should be processed while sending email
  • Loading branch information
VladimirZaets committed Sep 14, 2016
2 parents fecf38c + 43a9594 commit 1ade3b7
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 25 deletions.
67 changes: 67 additions & 0 deletions app/code/Magento/Email/Model/Template/Css/Processor.php
@@ -0,0 +1,67 @@
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Email\Model\Template\Css;

use Magento\Framework\View\Asset\NotationResolver\Variable;
use Magento\Framework\View\Asset\Repository;

class Processor
{
/**
* @var Repository
*/
private $assetRepository;

/**
* @param Repository $assetRepository
*/
public function __construct(Repository $assetRepository)
{
$this->assetRepository = $assetRepository;
}

/**
* Process css placeholders
*
* @param string $css
* @return string
*/
public function process($css)
{
$matches = [];
if (preg_match_all(Variable::VAR_REGEX, $css, $matches, PREG_SET_ORDER)) {
$replacements = [];
foreach ($matches as $match) {
if (!isset($replacements[$match[0]])) {
$replacements[$match[0]] = $this->getPlaceholderValue($match[1]);
}
}
$css = str_replace(array_keys($replacements), $replacements, $css);
}
return $css;
}

/**
* Retrieve placeholder value
*
* @param string $placeholder
* @return string
*/
private function getPlaceholderValue($placeholder)
{
/** @var \Magento\Framework\View\Asset\File\FallbackContext $context */
$context = $this->assetRepository->getStaticViewFileContext();

switch ($placeholder) {
case 'base_url_path':
return $context->getBaseUrl();
case 'locale':
return $context->getLocale();
default:
return '';
}
}
}
51 changes: 49 additions & 2 deletions app/code/Magento/Email/Model/Template/Filter.php
Expand Up @@ -5,6 +5,9 @@
*/
namespace Magento\Email\Model\Template;

use Magento\Framework\App\ObjectManager;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\ReadInterface;
use Magento\Framework\View\Asset\ContentProcessorException;
use Magento\Framework\View\Asset\ContentProcessorInterface;

Expand Down Expand Up @@ -153,6 +156,16 @@ class Filter extends \Magento\Framework\Filter\Template
*/
protected $configVariables;

/**
* @var \Magento\Email\Model\Template\Css\Processor
*/
private $cssProcessor;

/**
* @var ReadInterface
*/
private $pubDirectory;

/**
* @param \Magento\Framework\Stdlib\StringUtils $string
* @param \Psr\Log\LoggerInterface $logger
Expand Down Expand Up @@ -203,6 +216,31 @@ public function __construct(
parent::__construct($string, $variables);
}

/**
* @deprecated
* @return Css\Processor
*/
private function getCssProcessor()
{
if (!$this->cssProcessor) {
$this->cssProcessor = ObjectManager::getInstance()->get(Css\Processor::class);
}
return $this->cssProcessor;
}

/**
* @deprecated
* @param string $dirType
* @return ReadInterface
*/
private function getPubDirectory($dirType)
{
if (!$this->pubDirectory) {
$this->pubDirectory = ObjectManager::getInstance()->get(Filesystem::class)->getDirectoryRead($dirType);
}
return $this->pubDirectory;
}

/**
* Set use absolute links flag
*
Expand Down Expand Up @@ -788,7 +826,9 @@ public function cssDirective($construction)
return '/* ' . __('"file" parameter must be specified') . ' */';
}

$css = $this->getCssFilesContent([$params['file']]);
$css = $this->getCssProcessor()->process(
$this->getCssFilesContent([$params['file']])
);

if (strpos($css, ContentProcessorInterface::ERROR_MESSAGE_PREFIX) !== false) {
// Return compilation error wrapped in CSS comment
Expand Down Expand Up @@ -889,7 +929,12 @@ public function getCssFilesContent(array $files)
try {
foreach ($files as $file) {
$asset = $this->_assetRepo->createAsset($file, $designParams);
$css .= $asset->getContent();
$pubDirectory = $this->getPubDirectory($asset->getContext()->getBaseDirType());
if ($pubDirectory->isExist($asset->getPath())) {
$css .= $pubDirectory->readFile($asset->getPath());
} else {
$css .= $asset->getContent();
}
}
} catch (ContentProcessorException $exception) {
$css = $exception->getMessage();
Expand All @@ -914,6 +959,8 @@ public function applyInlineCss($html)
$cssToInline = $this->getCssFilesContent(
$this->getInlineCssFiles()
);
$cssToInline = $this->getCssProcessor()->process($cssToInline);

// Only run Emogrify if HTML and CSS contain content
if ($html && $cssToInline) {
try {
Expand Down
@@ -0,0 +1,59 @@
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Email\Test\Unit\Model\Template\Css;

use Magento\Email\Model\Template\Css\Processor;
use Magento\Framework\View\Asset\File\FallbackContext;
use Magento\Framework\View\Asset\Repository;

class ProcessorTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Processor
*/
protected $processor;

/**
* @var Repository|\PHPUnit_Framework_MockObject_MockObject
*/
protected $assetRepository;

/**
* @var FallbackContext|\PHPUnit_Framework_MockObject_MockObject
*/
protected $fallbackContext;

public function setUp()
{
$this->assetRepository = $this->getMockBuilder(Repository::class)
->disableOriginalConstructor()
->getMock();
$this->fallbackContext = $this->getMockBuilder(FallbackContext::class)
->disableOriginalConstructor()
->getMock();

$this->processor = new Processor($this->assetRepository);
}

public function testProcess()
{
$url = 'http://magento.local/pub/static/';
$locale = 'en_US';
$css = '@import url("{{base_url_path}}frontend/_view/{{locale}}/css/email.css");';
$expectedCss = '@import url("' . $url . 'frontend/_view/' . $locale . '/css/email.css");';

$this->assetRepository->expects($this->exactly(2))
->method('getStaticViewFileContext')
->willReturn($this->fallbackContext);
$this->fallbackContext->expects($this->once())
->method('getBaseUrl')
->willReturn($url);
$this->fallbackContext->expects($this->once())
->method('getLocale')
->willReturn($locale);
$this->assertEquals($expectedCss, $this->processor->process($css));
}
}
99 changes: 93 additions & 6 deletions app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php
Expand Up @@ -5,6 +5,13 @@
*/
namespace Magento\Email\Test\Unit\Model\Template;

use Magento\Email\Model\Template\Css\Processor;
use Magento\Email\Model\Template\Filter;
use Magento\Framework\App\Area;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem\Directory\ReadInterface;
use Magento\Framework\View\Asset\File\FallbackContext;

/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
Expand Down Expand Up @@ -94,7 +101,6 @@ protected function setUp()

$this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class)
->disableOriginalConstructor()
->enableProxyingToOriginalMethods()
->getMock();

$this->assetRepo = $this->getMockBuilder(\Magento\Framework\View\Asset\Repository::class)
Expand Down Expand Up @@ -138,7 +144,7 @@ protected function setUp()

/**
* @param array|null $mockedMethods Methods to mock
* @return \Magento\Email\Model\Template\Filter|\PHPUnit_Framework_MockObject_MockObject
* @return Filter|\PHPUnit_Framework_MockObject_MockObject
*/
protected function getModel($mockedMethods = null)
{
Expand Down Expand Up @@ -252,13 +258,23 @@ public function transDirectiveDataProvider()
public function testApplyInlineCss($html, $css, $expectedResults)
{
$filter = $this->getModel(['getCssFilesContent']);
$cssProcessor = $this->getMockBuilder(Processor::class)
->disableOriginalConstructor()
->getMock();
$reflectionClass = new \ReflectionClass(Filter::class);
$reflectionProperty = $reflectionClass->getProperty('cssProcessor');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($filter, $cssProcessor);
$cssProcessor->expects($this->any())
->method('process')
->willReturnArgument(0);

$filter->expects($this->exactly(count($expectedResults)))
->method('getCssFilesContent')
->will($this->returnValue($css));

$designParams = [
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
'area' => Area::AREA_FRONTEND,
'theme' => 'themeId',
'locale' => 'localeId',
];
Expand All @@ -269,6 +285,60 @@ public function testApplyInlineCss($html, $css, $expectedResults)
}
}

public function testGetCssFilesContent()
{
$file = 'css/email.css';
$path = Area::AREA_FRONTEND . '/themeId/localeId';
$css = 'p{color:black}';
$designParams = [
'area' => Area::AREA_FRONTEND,
'theme' => 'themeId',
'locale' => 'localeId',
];
$filter = $this->getModel();

$asset = $this->getMockBuilder(\Magento\Framework\View\Asset\File::class)
->disableOriginalConstructor()
->getMock();

$fallbackContext = $this->getMockBuilder(FallbackContext::class)
->disableOriginalConstructor()
->getMock();
$fallbackContext->expects($this->once())
->method('getBaseDirType')
->willReturn(DirectoryList::STATIC_VIEW);
$asset->expects($this->atLeastOnce())
->method('getContext')
->willReturn($fallbackContext);

$asset->expects($this->atLeastOnce())
->method('getPath')
->willReturn($path . DIRECTORY_SEPARATOR . $file);
$this->assetRepo->expects($this->once())
->method('createAsset')
->with($file, $designParams)
->willReturn($asset);

$pubDirectory = $this->getMockBuilder(ReadInterface::class)
->getMockForAbstractClass();
$reflectionClass = new \ReflectionClass(Filter::class);
$reflectionProperty = $reflectionClass->getProperty('pubDirectory');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($filter, $pubDirectory);
$pubDirectory->expects($this->once())
->method('isExist')
->with($path . DIRECTORY_SEPARATOR . $file)
->willReturn(true);
$pubDirectory->expects($this->once())
->method('readFile')
->with($path . DIRECTORY_SEPARATOR . $file)
->willReturn($css);

$filter->setDesignParams($designParams);

$this->assertEquals($css, $filter->getCssFilesContent([$file]));
}

/**
* @return array
*/
Expand Down Expand Up @@ -301,7 +371,19 @@ public function applyInlineCssDataProvider()
*/
public function testApplyInlineCssThrowsExceptionWhenDesignParamsNotSet()
{
$this->getModel()->applyInlineCss('test');
$filter = $this->getModel();
$cssProcessor = $this->getMockBuilder(Processor::class)
->disableOriginalConstructor()
->getMock();
$reflectionClass = new \ReflectionClass(Filter::class);
$reflectionProperty = $reflectionClass->getProperty('cssProcessor');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($filter, $cssProcessor);
$cssProcessor->expects($this->any())
->method('process')
->willReturnArgument(0);

$filter->applyInlineCss('test');
}

/**
Expand Down Expand Up @@ -348,7 +430,10 @@ public function testConfigDirectiveAvailable()
$construction = ["{{config path={$path}}}", 'config', " path={$path}"];
$scopeConfigValue = 'value';

$storeMock = $this->getMock(\Magento\Store\Api\Data\StoreInterface::class, [], [], '', false);
$storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
->disableOriginalConstructor()
->getMock();

$this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
$storeMock->expects($this->once())->method('getId')->willReturn(1);

Expand All @@ -369,7 +454,9 @@ public function testConfigDirectiveUnavailable()
$construction = ["{{config path={$path}}}", 'config', " path={$path}"];
$scopeConfigValue = '';

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

Expand Down

0 comments on commit 1ade3b7

Please sign in to comment.