Skip to content

Commit

Permalink
Fixes #15644: Avoid wrong default selection on a dropdown, checkbox l…
Browse files Browse the repository at this point in the history
…ist, and radio list, when a option has a key equals to zero
  • Loading branch information
beroso authored and samdark committed Feb 15, 2018
1 parent d64c139 commit d39d3ed
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 3 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 14 additions & 3 deletions framework/helpers/BaseHtml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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', []);
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
81 changes: 81 additions & 0 deletions tests/framework/helpers/HtmlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,26 @@ public function testDropDownList()
</select>
EOD;
$this->assertEqualsWithoutLE($expected, Html::dropDownList('test', null, [], ['multiple' => 'true']));

$expected = <<<'EOD'
<select name="test[]" multiple="true" size="4">
<option value="0" selected>zero</option>
<option value="1">one</option>
<option value="value3">text3</option>
</select>
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'
<select name="test[]" multiple="true" size="4">
<option value="0">zero</option>
<option value="1" selected>one</option>
<option value="value3" selected>text3</option>
</select>
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()
Expand Down Expand Up @@ -602,6 +622,26 @@ public function testListBox()
</select>
EOD;
$this->assertEqualsWithoutLE($expected, Html::listBox('test', new \ArrayObject(['value1', 'value2']), $this->getDataItems()));

$expected = <<<'EOD'
<select name="test" size="4">
<option value="0" selected>zero</option>
<option value="1">one</option>
<option value="value3">text3</option>
</select>
EOD;
$this->assertEqualsWithoutLE($expected, Html::listBox('test', [0], $this->getDataItems3()));
$this->assertEqualsWithoutLE($expected, Html::listBox('test', new \ArrayObject([0]), $this->getDataItems3()));

$expected = <<<'EOD'
<select name="test" size="4">
<option value="0">zero</option>
<option value="1" selected>one</option>
<option value="value3" selected>text3</option>
</select>
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()
Expand Down Expand Up @@ -658,6 +698,22 @@ public function testCheckboxList()
},
'tag' => false,
]));

$expected = <<<'EOD'
<div><label><input type="checkbox" name="test[]" value="0" checked> zero</label>
<label><input type="checkbox" name="test[]" value="1"> one</label>
<label><input type="checkbox" name="test[]" value="value3"> text3</label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', [0], $this->getDataItems3()));
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', new \ArrayObject([0]), $this->getDataItems3()));

$expected = <<<'EOD'
<div><label><input type="checkbox" name="test[]" value="0"> zero</label>
<label><input type="checkbox" name="test[]" value="1" checked> one</label>
<label><input type="checkbox" name="test[]" value="value3" checked> text3</label></div>
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()
Expand Down Expand Up @@ -712,6 +768,22 @@ public function testRadioList()
},
'tag' => false,
]));

$expected = <<<'EOD'
<div><label><input type="radio" name="test" value="0" checked> zero</label>
<label><input type="radio" name="test" value="1"> one</label>
<label><input type="radio" name="test" value="value3"> text3</label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', [0], $this->getDataItems3()));
$this->assertEqualsWithoutLE($expected, Html::radioList('test', new \ArrayObject([0]), $this->getDataItems3()));

$expected = <<<'EOD'
<div><label><input type="radio" name="test" value="0"> zero</label>
<label><input type="radio" name="test" value="1"> one</label>
<label><input type="radio" name="test" value="value3" checked> text3</label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value3'], $this->getDataItems3()));
$this->assertEqualsWithoutLE($expected, Html::radioList('test', new \ArrayObject(['value3']), $this->getDataItems3()));
}

public function testUl()
Expand Down Expand Up @@ -1049,6 +1121,15 @@ protected function getDataItems2()
];
}

protected function getDataItems3()
{
return [
'zero',
'one',
'value3' => 'text3',
];
}

/**
* Data provider for [[testActiveTextInput()]].
* @return array test data
Expand Down

0 comments on commit d39d3ed

Please sign in to comment.