From 16a6af5fa81a281e81a1a8ec1e539131057dd6db Mon Sep 17 00:00:00 2001 From: Sam Mousa Date: Wed, 24 Feb 2016 11:59:01 +0000 Subject: [PATCH 1/2] Add helper function for checking if an object is an array-like object. Added support for traversable objects in `BaseHtml` and `ArrayHelper` --- framework/CHANGELOG.md | 3 ++- framework/helpers/BaseArrayHelper.php | 17 ++++++++++++++- framework/helpers/BaseHtml.php | 12 +++++------ tests/framework/helpers/ArrayHelperTest.php | 10 +++++++++ tests/framework/helpers/HtmlTest.php | 24 +++++++++++++++++++++ 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 24c48675b5..32a83259e3 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -7,10 +7,11 @@ Yii Framework 2 Change Log - Bug #9851: Fixed partial commit / rollback in nested transactions (sammousa) - Bug #10946: Fixed parameters binding to the SQL query in `yii\db\mysqlSchema::findConstraints()` (silverfire) - Enh #5469: Add mimetype validation by mask in FileValidator (kirsenn, samdark, silverfire) +- Enh #10487: `yii\helpers\BaseArrayHelper::index()` got a third parameter `$groupBy` to group the input array by the key in one or more dimensions (quantum13, silverfire, samdark) - Enh #10451: Check of existence of `$_SERVER` in `\yii\web\Request` before using it (quantum13) - Enh #10610: Added `BaseUrl::$urlManager` to be able to set URL manager used for creating URLs (samdark) - Enh #10764: `yii\helpers\Html::tag()` and `::beginTag()` return content without any HTML when the `$tag` attribute is `false` or `null` (pana1990) -- Enh #10487: `yii\helpers\BaseArrayHelper::index()` got a third parameter `$groupBy` to group the input array by the key in one or more dimensions (quantum13, silverfire, samdark) +- Enh #10941: Added `yii\helpers\ArrayHelper::isTraversable`, added support for traversable selections for dropdownList, radioList and checkboxList in `yii\helpers\Html`. - Chg: HTMLPurifier dependency updated to `~4.6` (samdark) 2.0.7 February 14, 2016 diff --git a/framework/helpers/BaseArrayHelper.php b/framework/helpers/BaseArrayHelper.php index 7bb97b58b8..429eae978a 100644 --- a/framework/helpers/BaseArrayHelper.php +++ b/framework/helpers/BaseArrayHelper.php @@ -680,7 +680,7 @@ class BaseArrayHelper * Check whether an array or [[\Traversable]] contains an element. * * This method does the same as the PHP function [in_array()](http://php.net/manual/en/function.in-array.php) - * but it does not only work for arrays but also objects that implement the [[\Traversable]] interface. + * but additionally works for objects that implement the [[\Traversable]] interface. * @param mixed $needle The value to look for. * @param array|\Traversable $haystack The set of values to search. * @param boolean $strict Whether to enable strict (`===`) comparison. @@ -706,6 +706,21 @@ class BaseArrayHelper return false; } + /** + * Checks whether a variable is an array or [[\Traversable]]. + * + * This method does the same as the PHP function [is_array()](http://php.net/manual/en/function.is-array.php) + * but additionally works objects that implement the [[\Traversable]] interface. + * @param mixed $var The variable being evaluated. + * @return boolean whether $var is array-like + * @see http://php.net/manual/en/function.is_array.php + * @since 2.0.8 + */ + public static function isTraversable($var) + { + return is_array($var) || $var instanceof \Traversable; + } + /** * Checks whether an array or [[\Traversable]] is a subset of another array or [[\Traversable]]. * diff --git a/framework/helpers/BaseHtml.php b/framework/helpers/BaseHtml.php index 71b6f72b2e..e5c4e40af7 100644 --- a/framework/helpers/BaseHtml.php +++ b/framework/helpers/BaseHtml.php @@ -906,8 +906,8 @@ class BaseHtml $index = 0; foreach ($items as $value => $label) { $checked = $selection !== null && - (!is_array($selection) && !strcmp($value, $selection) - || is_array($selection) && in_array($value, $selection)); + (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($value, $selection)); if ($formatter !== null) { $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); } else { @@ -984,8 +984,8 @@ class BaseHtml $index = 0; foreach ($items as $value => $label) { $checked = $selection !== null && - (!is_array($selection) && !strcmp($value, $selection) - || is_array($selection) && in_array($value, $selection)); + (!ArrayHelper::isTraversable($selection) && !strcmp($value, $selection) + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($value, $selection)); if ($formatter !== null) { $lines[] = call_user_func($formatter, $index, $label, $name, $checked, $value); } else { @@ -1737,8 +1737,8 @@ class BaseHtml $attrs = isset($options[$key]) ? $options[$key] : []; $attrs['value'] = (string) $key; $attrs['selected'] = $selection !== null && - (!is_array($selection) && !strcmp($key, $selection) - || is_array($selection) && in_array($key, $selection)); + (!ArrayHelper::isTraversable($selection) && !strcmp($key, $selection) + || ArrayHelper::isTraversable($selection) && ArrayHelper::isIn($key, $selection)); $text = $encode ? static::encode($value) : $value; if ($encodeSpaces) { $text = str_replace(' ', ' ', $text); diff --git a/tests/framework/helpers/ArrayHelperTest.php b/tests/framework/helpers/ArrayHelperTest.php index 2ef4441f1e..1d92febe4c 100644 --- a/tests/framework/helpers/ArrayHelperTest.php +++ b/tests/framework/helpers/ArrayHelperTest.php @@ -664,5 +664,15 @@ class ArrayHelperTest extends TestCase } + public function testIsArray() + { + $this->assertTrue(ArrayHelper::isTraversable(['a'])); + $this->assertTrue(ArrayHelper::isTraversable(new \ArrayObject(['1']))); + $this->assertFalse(ArrayHelper::isTraversable(new \stdClass())); + $this->assertFalse(ArrayHelper::isTraversable("A,B,C")); + $this->assertFalse(ArrayHelper::isTraversable(12)); + $this->assertFalse(false); + } + } diff --git a/tests/framework/helpers/HtmlTest.php b/tests/framework/helpers/HtmlTest.php index ca505941db..33032956e5 100644 --- a/tests/framework/helpers/HtmlTest.php +++ b/tests/framework/helpers/HtmlTest.php @@ -354,6 +354,14 @@ EOD; EOD; $this->assertEqualsWithoutLE($expected, Html::listBox('test', '', [], ['unselect' => '0'])); + + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', new \ArrayObject(['value1', 'value2']), $this->getDataItems())); } public function testCheckboxList() @@ -402,6 +410,15 @@ EOD; }, 'tag' => false ])); + + + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', new \ArrayObject(['value2']), $this->getDataItems(), [ + 'item' => function ($index, $label, $name, $checked, $value) { + return $index . Html::label($label . ' ' . Html::checkbox($name, $checked, ['value' => $value])); + }, + 'tag' => false + ])); + } public function testRadioList() @@ -449,6 +466,13 @@ EOD; }, 'tag' => false ])); + + $this->assertEqualsWithoutLE($expected, Html::radioList('test', new \ArrayObject(['value2']), $this->getDataItems(), [ + 'item' => function ($index, $label, $name, $checked, $value) { + return $index . Html::label($label . ' ' . Html::radio($name, $checked, ['value' => $value])); + }, + 'tag' => false + ])); } public function testUl() From 438e5cfb5dddb5519c2e52539ad33c51151b0815 Mon Sep 17 00:00:00 2001 From: SilverFire - Dmitry Naumenko Date: Wed, 24 Feb 2016 23:51:19 +0200 Subject: [PATCH 2/2] BaseArrayHelper::isTraversable() PHPDoc update --- framework/helpers/BaseArrayHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/helpers/BaseArrayHelper.php b/framework/helpers/BaseArrayHelper.php index 429eae978a..b5d8cd5969 100644 --- a/framework/helpers/BaseArrayHelper.php +++ b/framework/helpers/BaseArrayHelper.php @@ -710,7 +710,7 @@ class BaseArrayHelper * Checks whether a variable is an array or [[\Traversable]]. * * This method does the same as the PHP function [is_array()](http://php.net/manual/en/function.is-array.php) - * but additionally works objects that implement the [[\Traversable]] interface. + * but additionally works on objects that implement the [[\Traversable]] interface. * @param mixed $var The variable being evaluated. * @return boolean whether $var is array-like * @see http://php.net/manual/en/function.is_array.php