From e49a52f3a18dd7ae20a710dc8208baaab8a93fa8 Mon Sep 17 00:00:00 2001 From: Alex <1797626+alex-code@users.noreply.github.com> Date: Wed, 5 Aug 2020 13:12:42 +0100 Subject: [PATCH] Fix #18210: Allow strict comparison for multi-select inputs --- framework/CHANGELOG.md | 1 + framework/helpers/BaseHtml.php | 19 +++++++++++++++---- tests/framework/helpers/HtmlTest.php | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 03af91e..de6d3fd 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -9,6 +9,7 @@ Yii Framework 2 Change Log - Bug #18170: Fix 2.0.36 regression in passing extra console command arguments to the action (darkdef) - Bug #18182: `yii\db\Expression` was not supported as condition in `ActiveRecord::findOne()` and `ActiveRecord::findAll()` (rhertogh) - Bug #18189: Fix "Invalid parameter number" in `yii\rbac\DbManager::removeItem()` (samdark) +- Enh #18210: Allow strict comparison for multi-select inputs (alex-code) - Bug #18204: Fix 2.0.36 regression in inline validator and JS validation (samdark) - Enh #18205: Add `.phpstorm.meta.php` file for better auto-completion in PhpStorm (vjik) - Bug #18198: Fix saving tables with trigger by outputting inserted data from insert query with usage of temporary table (darkdef) diff --git a/framework/helpers/BaseHtml.php b/framework/helpers/BaseHtml.php index 74376aa..902d464 100644 --- a/framework/helpers/BaseHtml.php +++ b/framework/helpers/BaseHtml.php @@ -819,6 +819,8 @@ class BaseHtml * Defaults to false. * - encode: bool, whether to encode option prompt and option value characters. * Defaults to `true`. This option is available since 2.0.3. + * - strict: boolean, if `$selection` is an array and this value is true a strict comparison will be performed on `$items` keys. Defaults to false. + * This option is available since 2.0.37. * * The rest of the options will be rendered as the attributes of the resulting tag. The values will * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. @@ -877,6 +879,8 @@ class BaseHtml * Defaults to false. * - encode: bool, whether to encode option prompt and option value characters. * Defaults to `true`. This option is available since 2.0.3. + * - strict: boolean, if `$selection` is an array and this value is true a strict comparison will be performed on `$items` keys. Defaults to false. + * This option is available since 2.0.37. * * The rest of the options will be rendered as the attributes of the resulting tag. The values will * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. @@ -931,6 +935,8 @@ class BaseHtml * This option is available since version 2.0.16. * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. * This option is ignored if `item` option is set. + * - strict: boolean, if `$selection` is an array and this value is true a strict comparison will be performed on `$items` keys. Defaults to false. + * This option is available since 2.0.37. * - separator: string, the HTML code that separates items. * - itemOptions: array, the options for generating the checkbox tag using [[checkbox()]]. * - item: callable, a callback that can be used to customize the generation of the HTML code @@ -962,13 +968,14 @@ class BaseHtml $encode = ArrayHelper::remove($options, 'encode', true); $separator = ArrayHelper::remove($options, 'separator', "\n"); $tag = ArrayHelper::remove($options, 'tag', 'div'); + $strict = ArrayHelper::remove($options, 'strict', false); $lines = []; $index = 0; foreach ($items as $value => $label) { $checked = $selection !== null && (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) - || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection)); + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection, $strict)); if ($formatter !== null) { $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); } else { @@ -1021,6 +1028,8 @@ class BaseHtml * This option is available since version 2.0.16. * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. * This option is ignored if `item` option is set. + * - strict: boolean, if `$selection` is an array and this value is true a strict comparison will be performed on `$items` keys. Defaults to false. + * This option is available since 2.0.37. * - separator: string, the HTML code that separates items. * - itemOptions: array, the options for generating the radio button tag using [[radio()]]. * - item: callable, a callback that can be used to customize the generation of the HTML code @@ -1049,6 +1058,7 @@ class BaseHtml $encode = ArrayHelper::remove($options, 'encode', true); $separator = ArrayHelper::remove($options, 'separator', "\n"); $tag = ArrayHelper::remove($options, 'tag', 'div'); + $strict = ArrayHelper::remove($options, 'strict', false); $hidden = ''; if (isset($options['unselect'])) { @@ -1067,7 +1077,7 @@ class BaseHtml foreach ($items as $value => $label) { $checked = $selection !== null && (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) - || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection)); + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$value, $selection, $strict)); if ($formatter !== null) { $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); } else { @@ -1860,6 +1870,7 @@ class BaseHtml $lines = []; $encodeSpaces = ArrayHelper::remove($tagOptions, 'encodeSpaces', false); $encode = ArrayHelper::remove($tagOptions, 'encode', true); + $strict = ArrayHelper::remove($tagOptions, 'strict', false); if (isset($tagOptions['prompt'])) { $promptOptions = ['value' => '']; if (is_string($tagOptions['prompt'])) { @@ -1887,7 +1898,7 @@ class BaseHtml if (!isset($groupAttrs['label'])) { $groupAttrs['label'] = $key; } - $attrs = ['options' => $options, 'groups' => $groups, 'encodeSpaces' => $encodeSpaces, 'encode' => $encode]; + $attrs = ['options' => $options, 'groups' => $groups, 'encodeSpaces' => $encodeSpaces, 'encode' => $encode, 'strict' => $strict]; $content = static::renderSelectOptions($selection, $value, $attrs); $lines[] = static::tag('optgroup', "\n" . $content . "\n", $groupAttrs); } else { @@ -1896,7 +1907,7 @@ class BaseHtml if (!array_key_exists('selected', $attrs)) { $attrs['selected'] = $selection !== null && (!ArrayHelper::isTraversable($selection) && !strcmp($key, $selection) - || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$key, $selection)); + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn((string)$key, $selection, $strict)); } $text = $encode ? static::encode($value) : $value; if ($encodeSpaces) { diff --git a/tests/framework/helpers/HtmlTest.php b/tests/framework/helpers/HtmlTest.php index 4e2e3a9..15c41b0 100644 --- a/tests/framework/helpers/HtmlTest.php +++ b/tests/framework/helpers/HtmlTest.php @@ -768,6 +768,13 @@ EOD; 'label' => 'Test Label' ] ])); + + $expected = <<<'EOD' +
+ +
+EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['1.1'], ['1' => '1', '1.1' => '1.1', '1.10' => '1.10'], ['strict' => true])); } public function testRadioListWithArrayExpression() @@ -909,6 +916,13 @@ EOD; 'label' => 'Test Label' ] ])); + + $expected = <<<'EOD' +
+ +
+EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['1.1'], ['1' => '1', '1.1' => '1.1', '1.10' => '1.10'], ['strict' => true])); } public function testUl() @@ -1046,6 +1060,26 @@ EOD; ], ]; $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['value1'], $data, $attributes)); + + $expected = <<<'EOD' + + + +EOD; + $data = ['1' => '1', '1.1' => '1.1', '1.10' => '1.10']; + $attributes = ['strict' => true]; + $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['1.1'], $data, $attributes)); + + $expected = <<<'EOD' + + + + + +EOD; + $data = ['1' => '1', '1.1' => '1.1', 'group' => ['1.10' => '1.10']]; + $attributes = ['strict' => true]; + $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['1.10'], $data, $attributes)); } public function testRenderAttributes()