diff --git a/app/code/Magento/Backend/Block/Widget/Form/Container.php b/app/code/Magento/Backend/Block/Widget/Form/Container.php index 52c5525db17eb..282b3e69532a7 100644 --- a/app/code/Magento/Backend/Block/Widget/Form/Container.php +++ b/app/code/Magento/Backend/Block/Widget/Form/Container.php @@ -37,6 +37,16 @@ class Container extends \Magento\Backend\Block\Widget\Container * @var string */ protected $_blockGroup = 'Magento_Backend'; + + /** + * @var string + */ + const PARAM_BLOCK_GROUP = 'block_group'; + + /** + * @var string + */ + const PARAM_MODE = 'mode'; /** * @var string @@ -49,6 +59,12 @@ class Container extends \Magento\Backend\Block\Widget\Container protected function _construct() { parent::_construct(); + if ($this->hasData(self::PARAM_BLOCK_GROUP)) { + $this->_blockGroup = $this->_getData(self::PARAM_BLOCK_GROUP); + } + if ($this->hasData(self::PARAM_MODE)) { + $this->_mode = $this->_getData(self::PARAM_MODE); + } $this->addButton( 'back', diff --git a/app/code/Magento/Deploy/Console/Command/SetModeCommand.php b/app/code/Magento/Deploy/Console/Command/SetModeCommand.php index f8c5cde9b942a..51509bdc85d82 100644 --- a/app/code/Magento/Deploy/Console/Command/SetModeCommand.php +++ b/app/code/Magento/Deploy/Console/Command/SetModeCommand.php @@ -104,6 +104,8 @@ protected function execute(InputInterface $input, OutputInterface $output) throw new LocalizedException(__('Cannot switch into given mode "%1"', $toMode)); } $output->writeln('Enabled ' . $toMode . ' mode.'); + + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } catch (\Exception $e) { $output->writeln('' . $e->getMessage() . ''); if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { diff --git a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php index e31bd1b356431..a01df75bca596 100644 --- a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php +++ b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/AbstractContainerTest.php @@ -103,7 +103,14 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->escaperMock = $this->getMock(\Magento\Framework\Escaper::class, ['escapeHtml'], [], '', false); + $this->escaperMock = $this->getMock( + \Magento\Framework\Escaper::class, + ['escapeHtml', 'escapeHtmlAttr'], + [], + '', + false + ); + $this->escaperMock->expects($this->any())->method('escapeHtmlAttr')->willReturnArgument(0); $this->contextMock = $this->getMockBuilder(\Magento\Backend\Block\Context::class) ->setMethods(['getEventManager', 'getScopeConfig', 'getEscaper']) diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Form/ContainerTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Form/ContainerTest.php index 466a1314907fe..329e627903ccb 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Form/ContainerTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Form/ContainerTest.php @@ -33,4 +33,23 @@ public function testGetFormHtml() $form->setText($expectedHtml); $this->assertEquals($expectedHtml, $block->getFormHtml()); } + + public function testPseudoConstruct() + { + /** @var $block \Magento\Backend\Block\Widget\Form\Container */ + $block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\View\LayoutInterface::class + )->createBlock( + \Magento\Backend\Block\Widget\Form\Container::class, + '', + [ + 'data' => [ + \Magento\Backend\Block\Widget\Container::PARAM_CONTROLLER => 'user', + \Magento\Backend\Block\Widget\Form\Container::PARAM_MODE => 'edit', + \Magento\Backend\Block\Widget\Form\Container::PARAM_BLOCK_GROUP => 'Magento_User' + ] + ] + ); + $this->assertInstanceOf(\Magento\User\Block\User\Edit\Form::class, $block->getChildBlock('form')); + } } diff --git a/lib/internal/Magento/Framework/View/Element/Html/Link.php b/lib/internal/Magento/Framework/View/Element/Html/Link.php index c4e5460c7de0b..e6f22f14784e0 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Link.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Link.php @@ -22,6 +22,7 @@ class Link extends \Magento\Framework\View\Element\Template 'title', 'charset', 'name', + 'target', 'hreflang', 'rel', 'rev', diff --git a/lib/internal/Magento/Framework/View/Element/Html/Select.php b/lib/internal/Magento/Framework/View/Element/Html/Select.php index e388e665dfdba..7e0c07ff75e45 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Select.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Select.php @@ -140,7 +140,7 @@ protected function _toHtml() '" class="' . $this->getClass() . '" title="' . - $this->getTitle() . + $this->escapeHtml($this->getTitle()) . '" ' . $this->getExtraParams() . '>'; @@ -166,7 +166,8 @@ protected function _toHtml() } if (is_array($value)) { - $html .= ''; + $html .= ''; foreach ($value as $keyGroup => $optionGroup) { if (!is_array($optionGroup)) { $optionGroup = ['value' => $keyGroup, 'label' => $optionGroup]; @@ -204,10 +205,10 @@ protected function _optionToHtml($option, $selected = false) foreach ($option['params'] as $key => $value) { if (is_array($value)) { foreach ($value as $keyMulti => $valueMulti) { - $params .= sprintf(' %s="%s" ', $keyMulti, $valueMulti); + $params .= sprintf(' %s="%s" ', $keyMulti, $this->escapeHtml($valueMulti)); } } else { - $params .= sprintf(' %s="%s" ', $key, $value); + $params .= sprintf(' %s="%s" ', $key, $this->escapeHtml($value)); } } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php index 6e10998105654..4986aa3e5873b 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/SelectTest.php @@ -6,6 +6,7 @@ namespace Magento\Framework\View\Test\Unit\Element\Html; use \Magento\Framework\View\Element\Html\Select; +use Magento\Framework\Escaper; class SelectTest extends \PHPUnit_Framework_TestCase { @@ -14,25 +15,27 @@ class SelectTest extends \PHPUnit_Framework_TestCase */ protected $select; + /** + * @var Escaper|\PHPUnit_Framework_MockObject_MockObject + */ + protected $escaper; + protected function setUp() { $eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class); $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); - $escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) + $this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) ->disableOriginalConstructor() ->getMock(); - $escaper->expects($this->any()) - ->method('escapeHtml') - ->will($this->returnArgument(0)); $context = $this->getMockBuilder(\Magento\Framework\View\Element\Context::class) ->disableOriginalConstructor() ->getMock(); $context->expects($this->once()) ->method('getEscaper') - ->will($this->returnValue($escaper)); + ->will($this->returnValue($this->escaper)); $context->expects($this->once()) ->method('getEventManager') ->will($this->returnValue($eventManager)); @@ -92,8 +95,52 @@ public function testGetSetTitle() $this->assertEquals($selectTitle, $this->select->getTitle()); } + public function testGetHtmlJs() + { + $this->escaper->expects($this->any()) + ->method('escapeHtml') + ->will($this->returnArgument(0)); + $this->escaper->expects($this->any()) + ->method('escapeHtmlAttr') + ->will($this->returnArgument(0)); + + $selectId = 'testId'; + $selectClass = 'testClass'; + $selectTitle = 'testTitle'; + $selectName = 'testName'; + + $options = [ + 'testValue' => 'testLabel', + 'selectedValue' => 'selectedLabel', + ]; + $selectedValue = 'selectedValue'; + + $this->select->setId($selectId); + $this->select->setClass($selectClass); + $this->select->setTitle($selectTitle); + $this->select->setName($selectName); + $this->select->setOptions($options); + $this->select->setValue($selectedValue); + + $result = ''; + + $this->select->setIsRenderToJsTemplate(true); + $this->assertEquals($result, $this->select->getHtml()); + } + public function testGetHtml() { + $this->escaper->expects($this->any()) + ->method('escapeHtml') + ->will($this->returnArgument(0)); + $this->escaper->expects($this->any()) + ->method('escapeHtmlAttr') + ->will($this->returnArgument(0)); + $selectId = 'testId'; $selectClass = 'testClass'; $selectTitle = 'testTitle'; @@ -137,33 +184,112 @@ public function testGetHtml() $this->assertEquals($result, $this->select->getHtml()); } - public function testGetHtmlJs() + public function testGetHtmlEscapes() { - $selectId = 'testId'; - $selectClass = 'testClass'; - $selectTitle = 'testTitle'; - $selectName = 'testName'; + $this->escaper->expects($this->any()) + ->method('escapeHtml') + ->will($this->returnValue('ESCAPED')); + $this->escaper->expects($this->any()) + ->method('escapeHtmlAttr') + ->will($this->returnValue('ESCAPED_ATTR')); - $options = [ - 'testValue' => 'testLabel', - 'selectedValue' => 'selectedLabel', + $optionsSets = [ + $this->getOptionsWithSingleQuotes(), + $this->getOptionsWithDoubleQuotes() ]; - $selectedValue = 'selectedValue'; - - $this->select->setId($selectId); - $this->select->setClass($selectClass); - $this->select->setTitle($selectTitle); - $this->select->setName($selectName); - $this->select->setOptions($options); - $this->select->setValue($selectedValue); - $result = '' + . '' + . '' + . '' + . '' + . '' + . '' . ''; - $this->select->setIsRenderToJsTemplate(true); - $this->assertEquals($result, $this->select->getHtml()); + foreach ($optionsSets as $inOptions) { + $this->select->setId($inOptions['id']); + $this->select->setClass($inOptions['class']); + $this->select->setTitle($inOptions['title']); + $this->select->setName($inOptions['name']); + + foreach ($inOptions['options'] as $option) { + $this->select->addOption($option['value'], $option['label'], $option['params']); + } + $this->select->setValue($inOptions['values']); + + $this->assertEquals($expectedResult, $this->select->getHtml()); + + // reset + $this->select->setOptions([]); + } + } + + /** + * @return array + */ + private function getOptionsWithSingleQuotes() + { + return [ + 'id' => "testId", + 'name' => "test[name]", + 'class' => "test class", + 'title' => "test'Title", + 'options' => [ + 'regular' => [ + 'value' => 'testValue', + 'label' => "test'Label", + 'params' => ['paramKey' => "param'Value"] + ], + 'selected' => [ + 'value' => 'selectedValue', + 'label' => "selected'Label", + 'params' => [] + ], + 'optgroup' => [ + 'value' => [ + 'groupElementValue' => "GroupElement'Label", + 'selectedGroupElementValue' => "SelectedGroupElement'Label" + ], + 'label' => "group'Label", + 'params' => [] + ] + ], + 'values' => ['selectedValue', 'selectedGroupElementValue'] + ]; + } + + /** + * @return array + */ + private function getOptionsWithDoubleQuotes() + { + return [ + 'id' => 'testId', + 'name' => 'test[name]', + 'class' => 'test class', + 'title' => 'test"Title', + 'options' => [ + 'regular' => [ + 'value' => 'testValue', + 'label' => 'test"Label', + 'params' => ['paramKey' => 'param"Value'] + ], + 'selected' => [ + 'value' => 'selectedValue', + 'label' => 'selected"Label', + 'params' => [] + ], + 'optgroup' => [ + 'value' => [ + 'groupElementValue' => 'GroupElement"Label', + 'selectedGroupElementValue' => 'SelectedGroupElement"Label' + ], + 'label' => 'group"Label', + 'params' => [] + ] + ], + 'values' => ['selectedValue', 'selectedGroupElementValue'] + ]; } }