diff --git a/app/code/Magento/Email/Model/Template/Filter.php b/app/code/Magento/Email/Model/Template/Filter.php index 648e4ab8fc380..87add921f9de8 100644 --- a/app/code/Magento/Email/Model/Template/Filter.php +++ b/app/code/Magento/Email/Model/Template/Filter.php @@ -3,15 +3,39 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Email\Model\Template; -use Magento\Framework\App\ObjectManager; +use Exception; +use Magento\Cms\Block\Block; +use Magento\Framework\App\Area; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\State; +use Magento\Framework\Css\PreProcessor\Adapter\CssInliner; +use Magento\Framework\Escaper; use Magento\Framework\Exception\MailException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\Read; +use Magento\Framework\Filter\Template; +use Magento\Framework\Filter\Template\Tokenizer\Parameter; use Magento\Framework\Filter\VariableResolverInterface; +use Magento\Framework\Stdlib\StringUtils; +use Magento\Framework\UrlInterface; use Magento\Framework\View\Asset\ContentProcessorException; use Magento\Framework\View\Asset\ContentProcessorInterface; +use Magento\Framework\View\Asset\File\NotFoundException; +use Magento\Framework\View\Asset\Repository; +use Magento\Framework\View\Element\AbstractBlock; +use Magento\Framework\View\LayoutFactory; +use Magento\Framework\View\LayoutInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Variable\Model\Source\Variables; +use Magento\Variable\Model\Variable; +use Magento\Variable\Model\VariableFactory; +use Psr\Log\LoggerInterface; /** * Core Email Template Filter Model @@ -22,7 +46,7 @@ * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @since 100.0.2 */ -class Filter extends \Magento\Framework\Filter\Template +class Filter extends Template { /** * The name used in the {{trans}} directive @@ -89,17 +113,17 @@ class Filter extends \Magento\Framework\Filter\Template private $plainTemplateMode = false; /** - * @var \Magento\Framework\View\Asset\Repository + * @var Repository */ protected $_assetRepo; /** - * @var \Psr\Log\LoggerInterface + * @var LoggerInterface */ protected $_logger; /** - * @var \Magento\Framework\Escaper + * @var Escaper */ protected $_escaper; @@ -107,29 +131,29 @@ class Filter extends \Magento\Framework\Filter\Template * Core store config * Variable factory * - * @var \Magento\Variable\Model\VariableFactory + * @var VariableFactory */ protected $_variableFactory; /** - * @var \Magento\Store\Model\StoreManagerInterface + * @var StoreManagerInterface */ protected $_storeManager; /** - * @var \Magento\Framework\View\LayoutInterface + * @var LayoutInterface */ protected $_layout; /** - * @var \Magento\Framework\View\LayoutFactory + * @var LayoutFactory */ protected $_layoutFactory; /** * Setup callbacks for filters * - * @var \Magento\Framework\App\Config\ScopeConfigInterface + * @var ScopeConfigInterface */ protected $_scopeConfig; @@ -143,28 +167,22 @@ class Filter extends \Magento\Framework\Filter\Template /** * App state * - * @var \Magento\Framework\App\State + * @var State */ protected $_appState; /** - * @var \Magento\Framework\UrlInterface + * @var UrlInterface */ protected $urlModel; /** - * @var \Pelago\Emogrifier - * @deprecated 100.2.0 - */ - protected $emogrifier; - - /** - * @var \Magento\Framework\Css\PreProcessor\Adapter\CssInliner + * @var CssInliner */ private $cssInliner; /** - * @var \Magento\Variable\Model\Source\Variables + * @var Variables */ protected $configVariables; @@ -179,52 +197,52 @@ class Filter extends \Magento\Framework\Filter\Template private $pubDirectory; /** - * @var \Magento\Framework\Filesystem\Directory\Read + * @var Read */ private $pubDirectoryRead; + /** - * @param \Magento\Framework\Stdlib\StringUtils $string - * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Framework\Escaper $escaper - * @param \Magento\Framework\View\Asset\Repository $assetRepo - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - * @param \Magento\Variable\Model\VariableFactory $coreVariableFactory - * @param \Magento\Store\Model\StoreManagerInterface $storeManager - * @param \Magento\Framework\View\LayoutInterface $layout - * @param \Magento\Framework\View\LayoutFactory $layoutFactory - * @param \Magento\Framework\App\State $appState - * @param \Magento\Framework\UrlInterface $urlModel - * @param \Pelago\Emogrifier $emogrifier - * @param \Magento\Variable\Model\Source\Variables $configVariables + * Filter constructor. + * @param StringUtils $string + * @param LoggerInterface $logger + * @param Escaper $escaper + * @param Repository $assetRepo + * @param ScopeConfigInterface $scopeConfig + * @param VariableFactory $coreVariableFactory + * @param StoreManagerInterface $storeManager + * @param LayoutInterface $layout + * @param LayoutFactory $layoutFactory + * @param State $appState + * @param UrlInterface $urlModel + * @param Variables $configVariables + * @param VariableResolverInterface $variableResolver + * @param Css\Processor $cssProcessor + * @param Filesystem $pubDirectory + * @param CssInliner $cssInliner * @param array $variables - * @param \Magento\Framework\Css\PreProcessor\Adapter\CssInliner|null $cssInliner * @param array $directiveProcessors - * @param VariableResolverInterface|null $variableResolver - * @param Css\Processor|null $cssProcessor - * @param Filesystem|null $pubDirectory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Framework\Stdlib\StringUtils $string, - \Psr\Log\LoggerInterface $logger, - \Magento\Framework\Escaper $escaper, - \Magento\Framework\View\Asset\Repository $assetRepo, - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Magento\Variable\Model\VariableFactory $coreVariableFactory, - \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Framework\View\LayoutInterface $layout, - \Magento\Framework\View\LayoutFactory $layoutFactory, - \Magento\Framework\App\State $appState, - \Magento\Framework\UrlInterface $urlModel, - \Pelago\Emogrifier $emogrifier, - \Magento\Variable\Model\Source\Variables $configVariables, + StringUtils $string, + LoggerInterface $logger, + Escaper $escaper, + Repository $assetRepo, + ScopeConfigInterface $scopeConfig, + VariableFactory $coreVariableFactory, + StoreManagerInterface $storeManager, + LayoutInterface $layout, + LayoutFactory $layoutFactory, + State $appState, + UrlInterface $urlModel, + Variables $configVariables, + VariableResolverInterface $variableResolver, + Css\Processor $cssProcessor, + Filesystem $pubDirectory, + CssInliner $cssInliner, $variables = [], - \Magento\Framework\Css\PreProcessor\Adapter\CssInliner $cssInliner = null, - array $directiveProcessors = [], - VariableResolverInterface $variableResolver = null, - Css\Processor $cssProcessor = null, - Filesystem $pubDirectory = null + array $directiveProcessors = [] ) { $this->_escaper = $escaper; $this->_assetRepo = $assetRepo; @@ -237,13 +255,9 @@ public function __construct( $this->_layoutFactory = $layoutFactory; $this->_appState = $appState; $this->urlModel = $urlModel; - $this->emogrifier = $emogrifier; - $this->cssInliner = $cssInliner ?: \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\Css\PreProcessor\Adapter\CssInliner::class); - $this->cssProcessor = $cssProcessor ?: ObjectManager::getInstance() - ->get(Css\Processor::class); - $this->pubDirectory = $pubDirectory ?: ObjectManager::getInstance() - ->get(Filesystem::class); + $this->cssInliner = $cssInliner; + $this->cssProcessor = $cssProcessor; + $this->pubDirectory = $pubDirectory; $this->configVariables = $configVariables; parent::__construct($string, $variables, $directiveProcessors, $variableResolver); } @@ -395,7 +409,7 @@ public function blockDirective($construction) if (isset($blockParameters['class'])) { $block = $this->_layout->createBlock($blockParameters['class'], null, ['data' => $blockParameters]); } elseif (isset($blockParameters['id'])) { - $block = $this->_layout->createBlock(\Magento\Cms\Block\Block::class); + $block = $this->_layout->createBlock(Block::class); if ($block) { $block->setBlockId($blockParameters['id']); } @@ -436,7 +450,7 @@ public function layoutDirective($construction) { $this->_directiveParams = $this->getParameters($construction[2]); if (!isset($this->_directiveParams['area'])) { - $this->_directiveParams['area'] = \Magento\Framework\App\Area::AREA_FRONTEND; + $this->_directiveParams['area'] = Area::AREA_FRONTEND; } if ($this->_directiveParams['area'] != $this->_appState->getAreaCode()) { return $this->_appState->emulateAreaCode( @@ -457,7 +471,7 @@ public function emulateAreaCallback() { $skipParams = ['handle', 'area']; - /** @var $layout \Magento\Framework\View\LayoutInterface */ + /** @var $layout LayoutInterface */ $layout = $this->_layoutFactory->create(['cacheable' => false]); $layout->getUpdate()->addHandle($this->_directiveParams['handle'])->load(); @@ -466,7 +480,7 @@ public function emulateAreaCallback() $rootBlock = false; foreach ($layout->getAllBlocks() as $block) { - /* @var $block \Magento\Framework\View\Element\AbstractBlock */ + /* @var $block AbstractBlock */ if (!$block->getParentBlock() && !$rootBlock) { $rootBlock = $block; } @@ -499,7 +513,7 @@ public function emulateAreaCallback() */ protected function _getBlockParameters($value) { - $tokenizer = new \Magento\Framework\Filter\Template\Tokenizer\Parameter(); + $tokenizer = new Parameter(); $tokenizer->setString($value); return $tokenizer->tokenize(); @@ -529,7 +543,7 @@ public function mediaDirective($construction) // phpcs:disable Magento2.Functions.DiscouragedFunction $params = $this->getParameters(html_entity_decode($construction[2], ENT_QUOTES)); return $this->_storeManager->getStore() - ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) . $params['url']; + ->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . $params['url']; } /** @@ -573,10 +587,10 @@ public function storeDirective($construction) /** * Set current URL model, which will be used for URLs generation. * - * @param \Magento\Framework\UrlInterface $urlModel + * @param UrlInterface $urlModel * @return $this */ - public function setUrlModel(\Magento\Framework\UrlInterface $urlModel) + public function setUrlModel(UrlInterface $urlModel) { $this->urlModel = $urlModel; return $this; @@ -752,7 +766,7 @@ public function protocolDirective($construction) if (isset($params['store'])) { try { $store = $this->_storeManager->getStore($params['store']); - } catch (\Exception $e) { + } catch (Exception $e) { throw new MailException( __('Requested invalid store "%1"', $params['store']) ); @@ -820,7 +834,7 @@ public function configDirective($construction) if (isset($params['path']) && $this->isAvailableConfigVariable($params['path'])) { $configValue = $this->_scopeConfig->getValue( $params['path'], - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORE, $storeId ); } @@ -858,8 +872,8 @@ public function customvarDirective($construction) $params['code'] ); $mode = $this->isPlainTemplateMode() - ? \Magento\Variable\Model\Variable::TYPE_TEXT - : \Magento\Variable\Model\Variable::TYPE_HTML; + ? Variable::TYPE_TEXT + : Variable::TYPE_HTML; $value = $variable->getValue($mode); if ($value) { $customVarValue = $value; @@ -892,19 +906,17 @@ public function cssDirective($construction) return '/* ' . __('"file" parameter must be specified') . ' */'; } - $css = $this->cssProcessor->process( - $this->getCssFilesContent([$params['file']]) - ); + try { + $css = $this->cssProcessor->process($this->getCssFilesContent([$params['file']])); + } catch (ContentProcessorException $exception) { + return '/*' . PHP_EOL . $exception->getMessage() . PHP_EOL . '*/'; + } - if (strpos($css, ContentProcessorInterface::ERROR_MESSAGE_PREFIX) !== false) { - // Return compilation error wrapped in CSS comment - return '/*' . PHP_EOL . $css . PHP_EOL . '*/'; - } elseif (!empty($css)) { - return $css; - } else { - // Return CSS comment for debugging purposes + if (empty($css)){ return '/* ' . __('Contents of the specified CSS file could not be loaded or is empty') . ' */'; } + + return $css; } /** @@ -922,7 +934,7 @@ public function cssDirective($construction) * * @param string[] $construction * @return string - * @throws \Magento\Framework\Exception\MailException + * @throws MailException */ public function inlinecssDirective($construction) { @@ -939,7 +951,7 @@ public function inlinecssDirective($construction) $params = $this->getParameters($construction[2]); if (!isset($params['file']) || !$params['file']) { - throw new \Magento\Framework\Exception\MailException( + throw new MailException( __('"file" parameter must be specified and must not be empty') ); } @@ -978,7 +990,8 @@ protected function getInlineCssFiles() * * @param [] $files * @return string - * @throws \Magento\Framework\Exception\MailException + * @throws MailException + * @throws ContentProcessorException */ public function getCssFilesContent(array $files) { @@ -987,7 +1000,7 @@ public function getCssFilesContent(array $files) $designParams = $this->getDesignParams(); if (!count($designParams)) { - throw new \Magento\Framework\Exception\MailException( + throw new MailException( __('Design params must be set before calling this method') ); } @@ -1002,9 +1015,7 @@ public function getCssFilesContent(array $files) $css .= $asset->getContent(); } } - } catch (ContentProcessorException $exception) { - $css = $exception->getMessage(); - } catch (\Magento\Framework\View\Asset\File\NotFoundException $exception) { + } catch (NotFoundException $exception) { $css = ''; } @@ -1019,50 +1030,55 @@ public function getCssFilesContent(array $files) * * @param string $html * @return string - * @throws \Magento\Framework\Exception\MailException + * @throws MailException */ public function applyInlineCss($html) { - // Check to see if the {{inlinecss file=""}} directive set CSS file(s) to inline and then load those files - $cssToInline = $this->getCssFilesContent( - $this->getInlineCssFiles() - ); + try { + // Check to see if the {{inlinecss file=""}} directive set CSS file(s) to inline and then load those files + $cssToInline = $this->getCssFilesContent($this->getInlineCssFiles()); + } catch (ContentProcessorException $exception) { + return $this->getExceptionHtml($html, $exception); + } + $cssToInline = $this->cssProcessor->process($cssToInline); // Only run Emogrify if HTML and CSS contain content - if ($html && $cssToInline) { - try { - // Don't try to compile CSS that has compilation errors - if (strpos($cssToInline, ContentProcessorInterface::ERROR_MESSAGE_PREFIX) - !== false - ) { - throw new \Magento\Framework\Exception\MailException( - __('
 %1 
', PHP_EOL . $cssToInline . PHP_EOL) - ); - } - - $this->cssInliner->setHtml($html); - - $this->cssInliner->setCss($cssToInline); - - // Don't parse inline