diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php b/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php index 44c43055df8b9..32bae10c801c8 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php @@ -136,7 +136,6 @@ public function addFields() * @return \Magento\Framework\Data\Form\Element\AbstractElement * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function _addField($parameter) { @@ -159,10 +158,6 @@ protected function _addField($parameter) $data['value'] = $parameter->getValue(); } - if ($parameter->getType() == 'text' && $data['value'] != '') { - $data['value'] = $this->_widget->decodeReservedChars($data['value']); - } - //prepare unique id value if ($fieldName == 'unique_id' && $data['value'] == '') { $data['value'] = hash('sha256', microtime(1)); diff --git a/app/code/Magento/Widget/Model/Widget.php b/app/code/Magento/Widget/Model/Widget.php index 3ca52cec43f40..6d9bb1878708a 100644 --- a/app/code/Magento/Widget/Model/Widget.php +++ b/app/code/Magento/Widget/Model/Widget.php @@ -5,6 +5,16 @@ */ namespace Magento\Widget\Model; +use Magento\Framework\App\Cache\Type\Config; +use Magento\Framework\DataObject; +use Magento\Framework\Escaper; +use Magento\Framework\Math\Random; +use Magento\Framework\View\Asset\Repository; +use Magento\Framework\View\Asset\Source; +use Magento\Framework\View\FileSystem; +use Magento\Widget\Helper\Conditions; +use Magento\Widget\Model\Config\Data; + /** * Widget model for different purposes * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -15,32 +25,32 @@ class Widget { /** - * @var \Magento\Widget\Model\Config\Data + * @var Data */ protected $dataStorage; /** - * @var \Magento\Framework\App\Cache\Type\Config + * @var Config */ protected $configCacheType; /** - * @var \Magento\Framework\View\Asset\Repository + * @var Repository */ protected $assetRepo; /** - * @var \Magento\Framework\View\Asset\Source + * @var Source */ protected $assetSource; /** - * @var \Magento\Framework\View\FileSystem + * @var FileSystem */ protected $viewFileSystem; /** - * @var \Magento\Framework\Escaper + * @var Escaper */ protected $escaper; @@ -50,30 +60,35 @@ class Widget protected $widgetsArray = []; /** - * @var \Magento\Widget\Helper\Conditions + * @var Conditions */ protected $conditionsHelper; /** - * @var \Magento\Framework\Math\Random + * @var Random */ private $mathRandom; /** - * @param \Magento\Framework\Escaper $escaper - * @param \Magento\Widget\Model\Config\Data $dataStorage - * @param \Magento\Framework\View\Asset\Repository $assetRepo - * @param \Magento\Framework\View\Asset\Source $assetSource - * @param \Magento\Framework\View\FileSystem $viewFileSystem - * @param \Magento\Widget\Helper\Conditions $conditionsHelper + * @var string[] + */ + private $reservedChars = ['}', '{']; + + /** + * @param Escaper $escaper + * @param Data $dataStorage + * @param Repository $assetRepo + * @param Source $assetSource + * @param FileSystem $viewFileSystem + * @param Conditions $conditionsHelper */ public function __construct( - \Magento\Framework\Escaper $escaper, - \Magento\Widget\Model\Config\Data $dataStorage, - \Magento\Framework\View\Asset\Repository $assetRepo, - \Magento\Framework\View\Asset\Source $assetSource, - \Magento\Framework\View\FileSystem $viewFileSystem, - \Magento\Widget\Helper\Conditions $conditionsHelper + Escaper $escaper, + Data $dataStorage, + Repository $assetRepo, + Source $assetSource, + FileSystem $viewFileSystem, + Conditions $conditionsHelper ) { $this->escaper = $escaper; $this->dataStorage = $dataStorage; @@ -110,14 +125,11 @@ public function getWidgetByClassType($type) $widgets = $this->getWidgets(); /** @var array $widget */ foreach ($widgets as $widget) { - if (isset($widget['@'])) { - if (isset($widget['@']['type'])) { - if ($type === $widget['@']['type']) { - return $widget; - } - } + if (isset($widget['@']['type']) && $type === $widget['@']['type']) { + return $widget; } } + return null; } @@ -131,8 +143,7 @@ public function getWidgetByClassType($type) */ public function getConfigAsXml($type) { - // phpstan:ignore - return $this->getXmlElementByType($type); + return $this->getWidgetByClassType($type); } /** @@ -294,48 +305,71 @@ public function getWidgetsArray($filters = []) * @param array $params Pre-configured Widget Params * @param bool $asIs Return result as widget directive(true) or as placeholder image(false) * @return string Widget directive ready to parse - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function getWidgetDeclaration($type, $params = [], $asIs = true) { - $directive = '{{widget type="' . $type . '"'; $widget = $this->getConfigAsObject($type); + $directiveParams = ''; foreach ($params as $name => $value) { // Retrieve default option value if pre-configured - if ($name == 'conditions') { - $name = 'conditions_encoded'; - $value = $this->conditionsHelper->encode($value); - } elseif ($this->isTextType($widget, $name)) { - $value = $this->encodeReservedChars($value); - } elseif (is_array($value)) { - $value = implode(',', $value); - } elseif (trim($value) == '') { - $parameters = $widget->getParameters(); - if (isset($parameters[$name]) && is_object($parameters[$name])) { - $value = $parameters[$name]->getValue(); - } - } - if (isset($value)) { - $directive .= sprintf(' %s="%s"', $name, $this->escaper->escapeHtmlAttr($value, false)); - } + $directiveParams .= $this->getDirectiveParam($widget, $name, $value); } - $directive .= $this->getWidgetPageVarName($params); - - $directive .= '}}'; + $directive = sprintf('{{widget type="%s"%s%s}}', $type, $directiveParams, $this->getWidgetPageVarName($params)); if ($asIs) { return $directive; } - $html = sprintf( + return sprintf( '', $this->idEncode($directive), $this->getPlaceholderImageUrl($type), $this->escaper->escapeUrl($directive) ); - return $html; + } + + /** + * Returns directive param with prepared value + * + * @param DataObject $widget + * @param string $name + * @param string|array $value + * @return string + */ + private function getDirectiveParam(DataObject $widget, string $name, $value): string + { + if ($name === 'conditions') { + $name = 'conditions_encoded'; + $value = $this->conditionsHelper->encode($value); + } elseif (is_array($value)) { + $value = implode(',', $value); + } elseif (trim($value) === '') { + $parameters = $widget->getParameters(); + if (isset($parameters[$name]) && is_object($parameters[$name])) { + $value = $parameters[$name]->getValue(); + } + } else { + $value = $this->getPreparedValue($value); + } + + return $value !== null + ? sprintf(' %s="%s"', $name, $this->escaper->escapeHtmlAttr($value, false)) + : ''; + } + + /** + * Returns encoded value if it contains reserved chars + * + * @param string $value + * @return string + */ + private function getPreparedValue(string $value): string + { + $pattern = sprintf('/%s/', implode('|', $this->reservedChars)); + + return preg_match($pattern, $value) ? rawurlencode($value) : $value; } /** @@ -460,65 +494,4 @@ protected function sortParameters($firstElement, $secondElement) $bOrder = (int)$secondElement->getData('sort_order'); return $aOrder < $bOrder ? -1 : ($aOrder > $bOrder ? 1 : 0); } - - /** - * Encode reserved chars - * - * @param string $string - * @return string|string[] - */ - private function encodeReservedChars($string) - { - $map = [ - '{' => urlencode('{'), - '}' => urlencode('}') - ]; - - return str_replace( - array_keys($map), - array_values($map), - $string - ); - } - - /** - * Decode reserved chars - * - * @param string $string - * @return array - */ - public function decodeReservedChars($string) - { - $map = [ - '{' => urlencode('{'), - '}' => urlencode('}') - ]; - - return str_replace( - array_values($map), - array_keys($map), - $string - ); - } - - /** - * Is text type Widget parameter - * - * @param \Magento\Framework\DataObject $widget - * @param string $name - * @return bool - */ - private function isTextType($widget, $name) - { - $parameters = $widget->getParameters(); - - if (isset($parameters[$name]) && is_object($parameters[$name])) { - $type = $parameters[$name]->getType(); - if ($type == 'text') { - return true; - } - } - - return false; - } }