Fixes #11275: Added possibility of unset or force replace former value in ArrayHelper::merge()

This commit is contained in:
Robert Korulczyk
2016-08-03 21:49:49 +02:00
committed by Alexander Makarov
parent 0ac161b69d
commit 993f2aef28
6 changed files with 268 additions and 15 deletions

View File

@ -303,21 +303,68 @@ Encoding will use application charset and could be changed via third argument.
## Merging Arrays <span id="merging-arrays"></span> ## Merging Arrays <span id="merging-arrays"></span>
You can use [[yii\helpers\ArrayHelper::merge()|ArrayHelper::merge()]] to merge two or more arrays into one recursively.
If each array has an element with the same string key value, the latter will overwrite the former
(different from [array_merge_recursive()](http://php.net/manual/en/function.array-merge-recursive.php)).
Recursive merging will be conducted if both arrays have an element of array type and are having the same key.
For integer-keyed elements, the elements from the latter array will be appended to the former array.
You can use [[yii\helpers\UnsetArrayValue]] object to unset value from previous array or
[[yii\helpers\ReplaceArrayValue]] to force replace former value instead of recursive merging.
For example:
```php ```php
/** $array1 = [
* Merges two or more arrays into one recursively. 'name' => 'Yii',
* If each array has an element with the same string key value, the latter 'version' => '1.1',
* will overwrite the former (different from array_merge_recursive). 'ids' => [
* Recursive merging will be conducted if both arrays have an element of array 1,
* type and are having the same key. ],
* For integer-keyed elements, the elements from the latter array will 'validDomains' => [
* be appended to the former array. 'example.com',
* @param array $a array to be merged to 'www.example.com',
* @param array $b array to be merged from. You can specify additional ],
* arrays via third argument, fourth argument etc. 'emails' => [
* @return array the merged array (the original arrays are not changed.) 'admin' => 'admin@example.com',
*/ 'dev' => 'dev@example.com',
public static function merge($a, $b) ],
];
$array2 = [
'version' => '2.0',
'ids' => [
2,
],
'validDomains' => new \yii\helpers\ReplaceArrayValue([
'yiiframework.com',
'www.yiiframework.com',
]),
'emails' => [
'dev' => new \yii\helpers\UnsetArrayValue(),
],
];
$result = ArrayHelper::merge($array1, $array2);
```
The result will be:
```php
[
'name' => 'Yii',
'version' => '2.0',
'ids' => [
1,
2,
],
'validDomains' => [
'yiiframework.com',
'www.yiiframework.com',
],
'emails' => [
'admin' => 'admin@example.com',
],
]
``` ```

View File

@ -9,6 +9,7 @@ Yii Framework 2 Change Log
- Bug #11912: Fixed PostgreSQL Schema to support negative default values for integer/float/decimal columns (nsknewbie) - Bug #11912: Fixed PostgreSQL Schema to support negative default values for integer/float/decimal columns (nsknewbie)
- Bug #11947: Fixed `gridData` initialization in `yii.gridView.js` (pavlm) - Bug #11947: Fixed `gridData` initialization in `yii.gridView.js` (pavlm)
- Bug #11949: Fixed `ActiveField::end` generates close tag when it's `option['tag']` is null (egorio) - Bug #11949: Fixed `ActiveField::end` generates close tag when it's `option['tag']` is null (egorio)
- Enh #11275: Added possibility of unset or force replace former value in `ArrayHelper::merge()` (mdmunir, rob006)
- Enh #11950: Improve BaseArrayHelper::keyExists speed (egorio) - Enh #11950: Improve BaseArrayHelper::keyExists speed (egorio)
- Bug #11726: `DbSession` was echoing database errors in production mode (samdark, pastuhov, deadkrolik) - Bug #11726: `DbSession` was echoing database errors in production mode (samdark, pastuhov, deadkrolik)
- Bug #12030: Fixed `yii\base\Model::offsetExists()` throws an exception on un-existing field (klimov-paul) - Bug #12030: Fixed `yii\base\Model::offsetExists()` throws an exception on un-existing field (klimov-paul)

View File

@ -107,6 +107,8 @@ class BaseArrayHelper
* type and are having the same key. * type and are having the same key.
* For integer-keyed elements, the elements from the latter array will * For integer-keyed elements, the elements from the latter array will
* be appended to the former array. * be appended to the former array.
* You can use [[UnsetArrayValue]] object to unset value from previous array or
* [[ReplaceArrayValue]] to force replace former value instead of recursive merging.
* @param array $a array to be merged to * @param array $a array to be merged to
* @param array $b array to be merged from. You can specify additional * @param array $b array to be merged from. You can specify additional
* arrays via third argument, fourth argument etc. * arrays via third argument, fourth argument etc.
@ -119,7 +121,11 @@ class BaseArrayHelper
while (!empty($args)) { while (!empty($args)) {
$next = array_shift($args); $next = array_shift($args);
foreach ($next as $k => $v) { foreach ($next as $k => $v) {
if (is_int($k)) { if ($v instanceof UnsetArrayValue) {
unset($res[$k]);
} elseif ($v instanceof ReplaceArrayValue) {
$res[$k] = $v->value;
} elseif (is_int($k)) {
if (isset($res[$k])) { if (isset($res[$k])) {
$res[] = $v; $res[] = $v;
} else { } else {

View File

@ -0,0 +1,73 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\helpers;
/**
* Object that represents the replacement of array value while performing [[ArrayHelper::merge()]].
*
* Usage example:
*
* ```php
* $array1 = [
* 'ids' => [
* 1,
* ],
* 'validDomains' => [
* 'example.com',
* 'www.example.com',
* ],
* ];
*
* $array2 = [
* 'ids' => [
* 2,
* ],
* 'validDomains' => new \yii\helpers\ReplaceArrayValue([
* 'yiiframework.com',
* 'www.yiiframework.com',
* ]),
* ];
*
* $result = \yii\helpers\ArrayHelper::merge($array1, $array2);
* ```
*
* The result will be
*
* ```php
* [
* 'ids' => [
* 1,
* 2,
* ],
* 'validDomains' => [
* 'yiiframework.com',
* 'www.yiiframework.com',
* ],
* ]
* ```
*
* @author Robert Korulczyk <robert@korulczyk.pl>
* @since 2.0.10
*/
class ReplaceArrayValue
{
/**
* @var mixed value used as replacement.
*/
public $value;
/**
* Constructor.
* @param mixed $value value used as replacement.
*/
public function __construct($value)
{
$this->value = $value;
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\helpers;
/**
* Object that represents the removal of array value while performing [[ArrayHelper::merge()]].
*
* Usage example:
*
* ```php
* $array1 = [
* 'ids' => [
* 1,
* ],
* 'validDomains' => [
* 'example.com',
* 'www.example.com',
* ],
* ];
*
* $array2 = [
* 'ids' => [
* 2,
* ],
* 'validDomains' => new \yii\helpers\UnsetArrayValue(),
* ];
*
* $result = \yii\helpers\ArrayHelper::merge($array1, $array2);
* ```
*
* The result will be
*
* ```php
* [
* 'ids' => [
* 1,
* 2,
* ],
* ]
* ```
*
* @author Robert Korulczyk <robert@korulczyk.pl>
* @since 2.0.10
*/
class UnsetArrayValue
{
}

View File

@ -307,6 +307,79 @@ class ArrayHelperTest extends TestCase
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result);
} }
public function testMergeWithUnset()
{
$a = [
'name' => 'Yii',
'version' => '1.0',
'options' => [
'namespace' => false,
'unittest' => false,
],
'features' => [
'mvc',
],
];
$b = [
'version' => '1.1',
'options' => new \yii\helpers\UnsetArrayValue(),
'features' => [
'gii',
],
];
$result = ArrayHelper::merge($a, $b);
$expected = [
'name' => 'Yii',
'version' => '1.1',
'features' => [
'mvc',
'gii',
],
];
$this->assertEquals($expected, $result);
}
public function testMergeWithReplace()
{
$a = [
'name' => 'Yii',
'version' => '1.0',
'options' => [
'namespace' => false,
'unittest' => false,
],
'features' => [
'mvc',
],
];
$b = [
'version' => '1.1',
'options' => [
'unittest' => true,
],
'features' => new \yii\helpers\ReplaceArrayValue([
'gii',
]),
];
$result = ArrayHelper::merge($a, $b);
$expected = [
'name' => 'Yii',
'version' => '1.1',
'options' => [
'namespace' => false,
'unittest' => true,
],
'features' => [
'gii',
],
];
$this->assertEquals($expected, $result);
}
/** /**
* @see https://github.com/yiisoft/yii2/pull/11549 * @see https://github.com/yiisoft/yii2/pull/11549
*/ */