From d39d3ed0a65d5e442908f38f105fc6d3e3e01c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Sousa?= Date: Thu, 15 Feb 2018 12:23:12 -0300 Subject: [PATCH] Fixes #15644: Avoid wrong default selection on a dropdown, checkbox list, and radio list, when a option has a key equals to zero --- framework/CHANGELOG.md | 1 + framework/helpers/BaseHtml.php | 17 ++++-- tests/framework/helpers/HtmlTest.php | 81 ++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 3a31ccef3a6..cf778104533 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.14 under development ------------------------ +- Bug #15644: Avoid wrong default selection on a dropdown, checkbox list, and radio list, when a option has a key equals to zero (berosoboy) - Enh #14538: Added `yii\behaviors\AttributeTypecastBehavior::typecastAfterFind` property (littlefuntik, silverfire) - Enh #14254: add an option to specify whether validator is forced to always use master DB for `yii\validators\UniqueValidator` and `yii\validators\ExistValidator` (rossoneri, samdark) - Enh #15272: Removed type attribute from script tag (aleksbelic) diff --git a/framework/helpers/BaseHtml.php b/framework/helpers/BaseHtml.php index 70e571a586b..9b28a82dcfb 100644 --- a/framework/helpers/BaseHtml.php +++ b/framework/helpers/BaseHtml.php @@ -939,6 +939,9 @@ public static function checkboxList($name, $selection = null, $items = [], $opti if (substr($name, -2) !== '[]') { $name .= '[]'; } + if (ArrayHelper::isTraversable($selection)) { + $selection = array_map('strval', (array)$selection); + } $formatter = ArrayHelper::remove($options, 'item'); $itemOptions = ArrayHelper::remove($options, 'itemOptions', []); @@ -951,7 +954,7 @@ public static function checkboxList($name, $selection = null, $items = [], $opti foreach ($items as $value => $label) { $checked = $selection !== null && (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) - || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($value, $selection)); + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection)); if ($formatter !== null) { $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); } else { @@ -1016,6 +1019,10 @@ public static function checkboxList($name, $selection = null, $items = [], $opti */ public static function radioList($name, $selection = null, $items = [], $options = []) { + if (ArrayHelper::isTraversable($selection)) { + $selection = array_map('strval', (array)$selection); + } + $formatter = ArrayHelper::remove($options, 'item'); $itemOptions = ArrayHelper::remove($options, 'itemOptions', []); $encode = ArrayHelper::remove($options, 'encode', true); @@ -1030,7 +1037,7 @@ public static function radioList($name, $selection = null, $items = [], $options foreach ($items as $value => $label) { $checked = $selection !== null && (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) - || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($value, $selection)); + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection)); if ($formatter !== null) { $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); } else { @@ -1807,6 +1814,10 @@ protected static function activeListInput($type, $model, $attribute, $items, $op */ public static function renderSelectOptions($selection, $items, &$tagOptions = []) { + if (ArrayHelper::isTraversable($selection)) { + $selection = array_map('strval', (array)$selection); + } + $lines = []; $encodeSpaces = ArrayHelper::remove($tagOptions, 'encodeSpaces', false); $encode = ArrayHelper::remove($tagOptions, 'encode', true); @@ -1846,7 +1857,7 @@ public static function renderSelectOptions($selection, $items, &$tagOptions = [] if (!array_key_exists('selected', $attrs)) { $attrs['selected'] = $selection !== null && (!ArrayHelper::isTraversable($selection) && !strcmp($key, $selection) - || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($key, $selection)); + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$key, $selection)); } $text = $encode ? static::encode($value) : $value; if ($encodeSpaces) { diff --git a/tests/framework/helpers/HtmlTest.php b/tests/framework/helpers/HtmlTest.php index 8db1e761ed3..0e6c664e640 100644 --- a/tests/framework/helpers/HtmlTest.php +++ b/tests/framework/helpers/HtmlTest.php @@ -520,6 +520,26 @@ public function testDropDownList() EOD; $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', null, [], ['multiple' => 'true'])); + + $expected = <<<'EOD' + +EOD; + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', [0], $this->getDataItems3(), ['multiple' => 'true'])); + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', new \ArrayObject([0]), $this->getDataItems3(), ['multiple' => 'true'])); + + $expected = <<<'EOD' + +EOD; + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', ['1', 'value3'], $this->getDataItems3(), ['multiple' => 'true'])); + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', new \ArrayObject(['1', 'value3']), $this->getDataItems3(), ['multiple' => 'true'])); } public function testListBox() @@ -602,6 +622,26 @@ public function testListBox() EOD; $this->assertEqualsWithoutLE($expected, Html::listBox('test', new \ArrayObject(['value1', 'value2']), $this->getDataItems())); + + $expected = <<<'EOD' + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', [0], $this->getDataItems3())); + $this->assertEqualsWithoutLE($expected, Html::listBox('test', new \ArrayObject([0]), $this->getDataItems3())); + + $expected = <<<'EOD' + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', ['1', 'value3'], $this->getDataItems3())); + $this->assertEqualsWithoutLE($expected, Html::listBox('test', new \ArrayObject(['1', 'value3']), $this->getDataItems3())); } public function testCheckboxList() @@ -658,6 +698,22 @@ public function testCheckboxList() }, 'tag' => false, ])); + + $expected = <<<'EOD' +
+ +
+EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', [0], $this->getDataItems3())); + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', new \ArrayObject([0]), $this->getDataItems3())); + + $expected = <<<'EOD' +
+ +
+EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['1', 'value3'], $this->getDataItems3())); + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', new \ArrayObject(['1', 'value3']), $this->getDataItems3())); } public function testRadioList() @@ -712,6 +768,22 @@ public function testRadioList() }, 'tag' => false, ])); + + $expected = <<<'EOD' +
+ +
+EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', [0], $this->getDataItems3())); + $this->assertEqualsWithoutLE($expected, Html::radioList('test', new \ArrayObject([0]), $this->getDataItems3())); + + $expected = <<<'EOD' +
+ +
+EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value3'], $this->getDataItems3())); + $this->assertEqualsWithoutLE($expected, Html::radioList('test', new \ArrayObject(['value3']), $this->getDataItems3())); } public function testUl() @@ -1049,6 +1121,15 @@ protected function getDataItems2() ]; } + protected function getDataItems3() + { + return [ + 'zero', + 'one', + 'value3' => 'text3', + ]; + } + /** * Data provider for [[testActiveTextInput()]]. * @return array test data