destroyApplication();
}
public function testToArray()
{
$dataArrayable = $this->getMockBuilder('yii\\base\\Arrayable')->getMock();
$dataArrayable->method('toArray')->willReturn([]);
$this->assertEquals([], ArrayHelper::toArray($dataArrayable));
$this->assertEquals(['foo'], ArrayHelper::toArray('foo'));
$object = new Post1();
$this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object));
$object = new Post2();
$this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object));
$object1 = new Post1();
$object2 = new Post2();
$this->assertEquals([
get_object_vars($object1),
get_object_vars($object2),
], ArrayHelper::toArray([
$object1,
$object2,
]));
$object = new Post2();
$this->assertEquals([
'id' => 123,
'secret' => 's',
'_content' => 'test',
'length' => 4,
], ArrayHelper::toArray($object, [
$object::className() => [
'id', 'secret',
'_content' => 'content',
'length' => function ($post) {
return strlen($post->content);
},
],
]));
$object = new Post3();
$this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object, [], false));
$this->assertEquals([
'id' => 33,
'subObject' => [
'id' => 123,
'content' => 'test',
],
], ArrayHelper::toArray($object));
//recursive with attributes of object and sub-object
$subObject = $object->subObject;
$this->assertEquals([
'id' => 33,
'id_plus_1' => 34,
'subObject' => [
'id' => 123,
'id_plus_1' => 124,
],
], ArrayHelper::toArray($object, [
$object::className() => [
'id', 'subObject',
'id_plus_1' => function ($post) {
return $post->id + 1;
},
],
$subObject::className() => [
'id',
'id_plus_1' => function ($post) {
return $post->id + 1;
},
],
]));
//recursive with attributes of subobject only
$this->assertEquals([
'id' => 33,
'subObject' => [
'id' => 123,
'id_plus_1' => 124,
],
], ArrayHelper::toArray($object, [
$subObject::className() => [
'id',
'id_plus_1' => function ($post) {
return $post->id + 1;
},
],
]));
// DateTime test
$this->assertEquals([
'date' => '2021-09-13 15:16:17.000000',
'timezone_type' => 3,
'timezone' => 'UTC',
], ArrayHelper::toArray(new \DateTime('2021-09-13 15:16:17', new \DateTimeZone('UTC'))));
}
public function testRemove()
{
$array = ['name' => 'b', 'age' => 3];
$name = ArrayHelper::remove($array, 'name');
$this->assertEquals($name, 'b');
$this->assertEquals($array, ['age' => 3]);
$default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue');
$this->assertEquals('defaultValue', $default);
}
public function testRemoveValueMultiple()
{
$array = [
'Bob' => 'Dylan',
'Michael' => 'Jackson',
'Mick' => 'Jagger',
'Janet' => 'Jackson',
];
$removed = ArrayHelper::removeValue($array, 'Jackson');
$this->assertEquals([
'Bob' => 'Dylan',
'Mick' => 'Jagger',
], $array);
$this->assertEquals([
'Michael' => 'Jackson',
'Janet' => 'Jackson',
], $removed);
}
public function testRemoveValueNotExisting()
{
$array = [
'Bob' => 'Dylan',
'Michael' => 'Jackson',
'Mick' => 'Jagger',
'Janet' => 'Jackson',
];
$removed = ArrayHelper::removeValue($array, 'Marley');
$this->assertEquals([
'Bob' => 'Dylan',
'Michael' => 'Jackson',
'Mick' => 'Jagger',
'Janet' => 'Jackson',
], $array);
$this->assertEquals([], $removed);
}
public function testMultisort()
{
// empty key
$dataEmpty = [];
ArrayHelper::multisort($dataEmpty, '');
$this->assertEquals([], $dataEmpty);
// single key
$array = [
['name' => 'b', 'age' => 3],
['name' => 'a', 'age' => 1],
['name' => 'c', 'age' => 2],
];
ArrayHelper::multisort($array, 'name');
$this->assertEquals(['name' => 'a', 'age' => 1], $array[0]);
$this->assertEquals(['name' => 'b', 'age' => 3], $array[1]);
$this->assertEquals(['name' => 'c', 'age' => 2], $array[2]);
// multiple keys
$array = [
['name' => 'b', 'age' => 3],
['name' => 'a', 'age' => 2],
['name' => 'a', 'age' => 1],
];
ArrayHelper::multisort($array, ['name', 'age']);
$this->assertEquals(['name' => 'a', 'age' => 1], $array[0]);
$this->assertEquals(['name' => 'a', 'age' => 2], $array[1]);
$this->assertEquals(['name' => 'b', 'age' => 3], $array[2]);
// case-insensitive
$array = [
['name' => 'a', 'age' => 3],
['name' => 'b', 'age' => 2],
['name' => 'B', 'age' => 4],
['name' => 'A', 'age' => 1],
];
ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING, SORT_REGULAR]);
$this->assertEquals(['name' => 'A', 'age' => 1], $array[0]);
$this->assertEquals(['name' => 'B', 'age' => 4], $array[1]);
$this->assertEquals(['name' => 'a', 'age' => 3], $array[2]);
$this->assertEquals(['name' => 'b', 'age' => 2], $array[3]);
ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING | SORT_FLAG_CASE, SORT_REGULAR]);
$this->assertEquals(['name' => 'A', 'age' => 1], $array[0]);
$this->assertEquals(['name' => 'a', 'age' => 3], $array[1]);
$this->assertEquals(['name' => 'b', 'age' => 2], $array[2]);
$this->assertEquals(['name' => 'B', 'age' => 4], $array[3]);
}
public function testMultisortNestedObjects()
{
$obj1 = new \stdClass();
$obj1->type = 'def';
$obj1->owner = $obj1;
$obj2 = new \stdClass();
$obj2->type = 'abc';
$obj2->owner = $obj2;
$obj3 = new \stdClass();
$obj3->type = 'abc';
$obj3->owner = $obj3;
$models = [
$obj1,
$obj2,
$obj3,
];
$this->assertEquals($obj2, $obj3);
ArrayHelper::multisort($models, 'type', SORT_ASC);
$this->assertEquals($obj2, $models[0]);
$this->assertEquals($obj3, $models[1]);
$this->assertEquals($obj1, $models[2]);
ArrayHelper::multisort($models, 'type', SORT_DESC);
$this->assertEquals($obj1, $models[0]);
$this->assertEquals($obj2, $models[1]);
$this->assertEquals($obj3, $models[2]);
}
public function testMultisortUseSort()
{
// single key
$sort = new Sort([
'attributes' => ['name', 'age'],
'defaultOrder' => ['name' => SORT_ASC],
'params' => [],
]);
$orders = $sort->getOrders();
$array = [
['name' => 'b', 'age' => 3],
['name' => 'a', 'age' => 1],
['name' => 'c', 'age' => 2],
];
ArrayHelper::multisort($array, array_keys($orders), array_values($orders));
$this->assertEquals(['name' => 'a', 'age' => 1], $array[0]);
$this->assertEquals(['name' => 'b', 'age' => 3], $array[1]);
$this->assertEquals(['name' => 'c', 'age' => 2], $array[2]);
// multiple keys
$sort = new Sort([
'attributes' => ['name', 'age'],
'defaultOrder' => ['name' => SORT_ASC, 'age' => SORT_DESC],
'params' => [],
]);
$orders = $sort->getOrders();
$array = [
['name' => 'b', 'age' => 3],
['name' => 'a', 'age' => 2],
['name' => 'a', 'age' => 1],
];
ArrayHelper::multisort($array, array_keys($orders), array_values($orders));
$this->assertEquals(['name' => 'a', 'age' => 2], $array[0]);
$this->assertEquals(['name' => 'a', 'age' => 1], $array[1]);
$this->assertEquals(['name' => 'b', 'age' => 3], $array[2]);
}
public function testMultisortClosure()
{
$changelog = [
'- Enh #123: test1',
'- Bug #125: test2',
'- Bug #123: test2',
'- Enh: test3',
'- Bug: test4',
];
$i = 0;
ArrayHelper::multisort($changelog, function ($line) use (&$i) {
if (preg_match('/^- (Enh|Bug)( #\d+)?: .+$/', $line, $m)) {
$o = ['Bug' => 'C', 'Enh' => 'D'];
return $o[$m[1]] . ' ' . (!empty($m[2]) ? $m[2] : 'AAAA' . $i++);
}
return 'B' . $i++;
}, SORT_ASC, SORT_NATURAL);
$this->assertEquals([
'- Bug #123: test2',
'- Bug #125: test2',
'- Bug: test4',
'- Enh #123: test1',
'- Enh: test3',
], $changelog);
}
public function testMultisortInvalidParamExceptionDirection()
{
$this->expectException('yii\base\InvalidParamException');
$data = ['foo' => 'bar'];
ArrayHelper::multisort($data, ['foo'], []);
}
public function testMultisortInvalidParamExceptionSortFlag()
{
$this->expectException('yii\base\InvalidParamException');
$data = ['foo' => 'bar'];
ArrayHelper::multisort($data, ['foo'], ['foo'], []);
}
public function testMerge()
{
$a = [
'name' => 'Yii',
'version' => '1.0',
'options' => [
'namespace' => false,
'unittest' => false,
],
'features' => [
'mvc',
],
];
$b = [
'version' => '1.1',
'options' => [
'unittest' => true,
],
'features' => [
'gii',
],
];
$c = [
'version' => '2.0',
'options' => [
'namespace' => true,
],
'features' => [
'debug',
],
'foo',
];
$result = ArrayHelper::merge($a, $b, $c);
$expected = [
'name' => 'Yii',
'version' => '2.0',
'options' => [
'namespace' => true,
'unittest' => true,
],
'features' => [
'mvc',
'gii',
'debug',
],
'foo',
];
$this->assertEquals($expected, $result);
}
public function testMergeWithNumericKeys()
{
$a = [10 => [1]];
$b = [10 => [2]];
$result = ArrayHelper::merge($a, $b);
$expected = [10 => [1], 11 => [2]];
$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);
}
public function testMergeWithNullValues()
{
$a = [
'firstValue',
null,
];
$b = [
'secondValue',
'thirdValue',
];
$result = ArrayHelper::merge($a, $b);
$expected = [
'firstValue',
null,
'secondValue',
'thirdValue',
];
$this->assertEquals($expected, $result);
}
public function testMergeEmpty()
{
$this->assertEquals([], ArrayHelper::merge([], []));
$this->assertEquals([], ArrayHelper::merge([], [], []));
}
/**
* @see https://github.com/yiisoft/yii2/pull/11549
*/
public function test()
{
$array = [];
$array[1.0] = 'some value';
$result = ArrayHelper::getValue($array, 1.0);
$this->assertEquals('some value', $result);
}
public function testIndex()
{
$array = [
['id' => '123', 'data' => 'abc'],
['id' => '345', 'data' => 'def'],
['id' => '345', 'data' => 'ghi'],
];
$result = ArrayHelper::index($array, 'id');
$this->assertEquals([
'123' => ['id' => '123', 'data' => 'abc'],
'345' => ['id' => '345', 'data' => 'ghi'],
], $result);
$result = ArrayHelper::index($array, function ($element) {
return $element['data'];
});
$this->assertEquals([
'abc' => ['id' => '123', 'data' => 'abc'],
'def' => ['id' => '345', 'data' => 'def'],
'ghi' => ['id' => '345', 'data' => 'ghi'],
], $result);
$result = ArrayHelper::index($array, null);
$this->assertEquals([], $result);
$result = ArrayHelper::index($array, function ($element) {
return null;
});
$this->assertEquals([], $result);
$result = ArrayHelper::index($array, function ($element) {
return $element['id'] == '345' ? null : $element['id'];
});
$this->assertEquals([
'123' => ['id' => '123', 'data' => 'abc'],
], $result);
}
public function testIndexGroupBy()
{
$array = [
['id' => '123', 'data' => 'abc'],
['id' => '345', 'data' => 'def'],
['id' => '345', 'data' => 'ghi'],
];
$expected = [
'123' => [
['id' => '123', 'data' => 'abc'],
],
'345' => [
['id' => '345', 'data' => 'def'],
['id' => '345', 'data' => 'ghi'],
],
];
$result = ArrayHelper::index($array, null, ['id']);
$this->assertEquals($expected, $result);
$result = ArrayHelper::index($array, null, 'id');
$this->assertEquals($expected, $result);
$result = ArrayHelper::index($array, null, ['id', 'data']);
$this->assertEquals([
'123' => [
'abc' => [
['id' => '123', 'data' => 'abc'],
],
],
'345' => [
'def' => [
['id' => '345', 'data' => 'def'],
],
'ghi' => [
['id' => '345', 'data' => 'ghi'],
],
],
], $result);
$expected = [
'123' => [
'abc' => ['id' => '123', 'data' => 'abc'],
],
'345' => [
'def' => ['id' => '345', 'data' => 'def'],
'ghi' => ['id' => '345', 'data' => 'ghi'],
],
];
$result = ArrayHelper::index($array, 'data', ['id']);
$this->assertEquals($expected, $result);
$result = ArrayHelper::index($array, 'data', 'id');
$this->assertEquals($expected, $result);
$result = ArrayHelper::index($array, function ($element) {
return $element['data'];
}, 'id');
$this->assertEquals($expected, $result);
$expected = [
'123' => [
'abc' => [
'abc' => ['id' => '123', 'data' => 'abc'],
],
],
'345' => [
'def' => [
'def' => ['id' => '345', 'data' => 'def'],
],
'ghi' => [
'ghi' => ['id' => '345', 'data' => 'ghi'],
],
],
];
$result = ArrayHelper::index($array, 'data', ['id', 'data']);
$this->assertEquals($expected, $result);
$result = ArrayHelper::index($array, function ($element) {
return $element['data'];
}, ['id', 'data']);
$this->assertEquals($expected, $result);
}
/**
* @see https://github.com/yiisoft/yii2/issues/11739
*/
public function testIndexFloat()
{
$array = [
['id' => 1e6],
['id' => 1e32],
['id' => 1e64],
['id' => 1465540807.522109],
];
$expected = [
'1000000' => ['id' => 1e6],
'1.0E+32' => ['id' => 1e32],
'1.0E+64' => ['id' => 1e64],
'1465540807.5221' => ['id' => 1465540807.522109],
];
$result = ArrayHelper::index($array, 'id');
$this->assertEquals($expected, $result);
}
public function testGetColumn()
{
$array = [
'a' => ['id' => '123', 'data' => 'abc'],
'b' => ['id' => '345', 'data' => 'def'],
];
$result = ArrayHelper::getColumn($array, 'id');
$this->assertEquals(['a' => '123', 'b' => '345'], $result);
$result = ArrayHelper::getColumn($array, 'id', false);
$this->assertEquals(['123', '345'], $result);
$result = ArrayHelper::getColumn($array, function ($element) {
return $element['data'];
});
$this->assertEquals(['a' => 'abc', 'b' => 'def'], $result);
$result = ArrayHelper::getColumn($array, function ($element) {
return $element['data'];
}, false);
$this->assertEquals(['abc', 'def'], $result);
}
public function testMap()
{
$array = [
['id' => '123', 'name' => 'aaa', 'class' => 'x'],
['id' => '124', 'name' => 'bbb', 'class' => 'x'],
['id' => '345', 'name' => 'ccc', 'class' => 'y'],
];
$result = ArrayHelper::map($array, 'id', 'name');
$this->assertEquals([
'123' => 'aaa',
'124' => 'bbb',
'345' => 'ccc',
], $result);
$result = ArrayHelper::map($array, 'id', 'name', 'class');
$this->assertEquals([
'x' => [
'123' => 'aaa',
'124' => 'bbb',
],
'y' => [
'345' => 'ccc',
],
], $result);
}
public function testKeyExists()
{
$array = [
'a' => 1,
'B' => 2,
];
$this->assertTrue(ArrayHelper::keyExists('a', $array));
$this->assertFalse(ArrayHelper::keyExists('b', $array));
$this->assertTrue(ArrayHelper::keyExists('B', $array));
$this->assertFalse(ArrayHelper::keyExists('c', $array));
$this->assertTrue(ArrayHelper::keyExists('a', $array, false));
$this->assertTrue(ArrayHelper::keyExists('b', $array, false));
$this->assertTrue(ArrayHelper::keyExists('B', $array, false));
$this->assertFalse(ArrayHelper::keyExists('c', $array, false));
}
public function testKeyExistsArrayAccess()
{
$array = new TraversableArrayAccessibleObject([
'a' => 1,
'B' => 2,
]);
$this->assertTrue(ArrayHelper::keyExists('a', $array));
$this->assertFalse(ArrayHelper::keyExists('b', $array));
$this->assertTrue(ArrayHelper::keyExists('B', $array));
$this->assertFalse(ArrayHelper::keyExists('c', $array));
}
public function testKeyExistsArrayAccessCaseInsensitiveThrowsError()
{
$this->expectException('yii\base\InvalidArgumentException');
$this->expectExceptionMessage('Second parameter($array) cannot be ArrayAccess in case insensitive mode');
$array = new TraversableArrayAccessibleObject([
'a' => 1,
'B' => 2,
]);
ArrayHelper::keyExists('a', $array, false);
}
public function valueProvider()
{
return [
['name', 'test'],
['noname', null],
['noname', 'test', 'test'],
['post.id', 5],
['post.id', 5, 'test'],
['nopost.id', null],
['nopost.id', 'test', 'test'],
['post.author.name', 'cebe'],
['post.author.noname', null],
['post.author.noname', 'test', 'test'],
['post.author.profile.title', '1337'],
['admin.firstname', 'Qiang'],
['admin.firstname', 'Qiang', 'test'],
['admin.lastname', 'Xue'],
[
function ($array, $defaultValue) {
return $array['date'] . $defaultValue;
},
'31-12-2113test',
'test',
],
[['version', '1.0', 'status'], 'released'],
[['version', '1.0', 'date'], 'defaultValue', 'defaultValue'],
];
}
/**
* @dataProvider valueProvider
*
* @param $key
* @param $expected
* @param null $default
*/
public function testGetValue($key, $expected, $default = null)
{
$array = [
'name' => 'test',
'date' => '31-12-2113',
'post' => [
'id' => 5,
'author' => [
'name' => 'cebe',
'profile' => [
'title' => '1337',
],
],
],
'admin.firstname' => 'Qiang',
'admin.lastname' => 'Xue',
'admin' => [
'lastname' => 'cebe',
],
'version' => [
'1.0' => [
'status' => 'released',
],
],
];
$this->assertEquals($expected, ArrayHelper::getValue($array, $key, $default));
}
public function testGetValueObjects()
{
$arrayObject = new \ArrayObject(['id' => 23], \ArrayObject::ARRAY_AS_PROPS);
$this->assertEquals(23, ArrayHelper::getValue($arrayObject, 'id'));
$object = new Post1();
$this->assertEquals(23, ArrayHelper::getValue($object, 'id'));
}
public function testGetValueNonexistingProperties1()
{
if (PHP_VERSION_ID < 80000) {
$this->expectException('PHPUnit_Framework_Error_Notice');
} else {
$this->expectException('PHPUnit_Framework_Error_Warning');
}
$object = new Post1();
ArrayHelper::getValue($object, 'nonExisting');
}
public function testGetValueNonexistingPropertiesForArrayObject()
{
$arrayObject = new \ArrayObject(['id' => 23], \ArrayObject::ARRAY_AS_PROPS);
$this->assertNull(ArrayHelper::getValue($arrayObject, 'nonExisting'));
}
public function testGetValueFromArrayAccess()
{
$arrayAccessibleObject = new ArrayAccessibleObject([
'one' => 1,
'two' => 2,
'three' => 3,
'key.with.dot' => 'dot',
'null' => null,
]);
$this->assertEquals(1, ArrayHelper::getValue($arrayAccessibleObject, 'one'));
}
public function testGetValueWithDotsFromArrayAccess()
{
$arrayAccessibleObject = new ArrayAccessibleObject([
'one' => 1,
'two' => 2,
'three' => 3,
'key.with.dot' => 'dot',
'null' => null,
]);
$this->assertEquals('dot', ArrayHelper::getValue($arrayAccessibleObject, 'key.with.dot'));
}
public function testGetValueNonexistingArrayAccess()
{
$arrayAccessibleObject = new ArrayAccessibleObject([
'one' => 1,
'two' => 2,
'three' => 3,
'key.with.dot' => 'dot',
'null' => null,
]);
$this->assertEquals(null, ArrayHelper::getValue($arrayAccessibleObject, 'four'));
}
/**
* Data provider for [[testSetValue()]].
* @return array test data
*/
public function dataProviderSetValue()
{
return [
[
[
'key1' => 'val1',
'key2' => 'val2',
],
'key', 'val',
[
'key1' => 'val1',
'key2' => 'val2',
'key' => 'val',
],
],
[
[
'key1' => 'val1',
'key2' => 'val2',
],
'key2', 'val',
[
'key1' => 'val1',
'key2' => 'val',
],
],
[
[
'key1' => 'val1',
],
'key.in', 'val',
[
'key1' => 'val1',
'key' => ['in' => 'val'],
],
],
[
[
'key' => 'val1',
],
'key.in', 'val',
[
'key' => [
'val1',
'in' => 'val',
],
],
],
[
[
'key' => 'val1',
],
'key', ['in' => 'val'],
[
'key' => ['in' => 'val'],
],
],
[
[
'key1' => 'val1',
],
'key.in.0', 'val',
[
'key1' => 'val1',
'key' => [
'in' => ['val'],
],
],
],
[
[
'key1' => 'val1',
],
'key.in.arr', 'val',
[
'key1' => 'val1',
'key' => [
'in' => [
'arr' => 'val',
],
],
],
],
[
[
'key1' => 'val1',
],
'key.in.arr', ['val'],
[
'key1' => 'val1',
'key' => [
'in' => [
'arr' => ['val'],
],
],
],
],
[
[
'key' => [
'in' => ['val1'],
],
],
'key.in.arr', 'val',
[
'key' => [
'in' => [
'val1',
'arr' => 'val',
],
],
],
],
[
[
'key' => ['in' => 'val1'],
],
'key.in.arr', ['val'],
[
'key' => [
'in' => [
'val1',
'arr' => ['val'],
],
],
],
],
[
[
'key' => [
'in' => [
'val1',
'key' => 'val',
],
],
],
'key.in.0', ['arr' => 'val'],
[
'key' => [
'in' => [
['arr' => 'val'],
'key' => 'val',
],
],
],
],
[
[
'key' => [
'in' => [
'val1',
'key' => 'val',
],
],
],
'key.in', ['arr' => 'val'],
[
'key' => [
'in' => ['arr' => 'val'],
],
],
],
[
[
'key' => [
'in' => [
'key' => 'val',
'data' => [
'attr1',
'attr2',
'attr3',
],
],
],
],
'key.in.schema', 'array',
[
'key' => [
'in' => [
'key' => 'val',
'schema' => 'array',
'data' => [
'attr1',
'attr2',
'attr3',
],
],
],
],
],
[
[
'key' => [
'in.array' => [
'key' => 'val',
],
],
],
['key', 'in.array', 'ok.schema'], 'array',
[
'key' => [
'in.array' => [
'key' => 'val',
'ok.schema' => 'array',
],
],
],
],
[
[
'key' => ['val'],
],
null, 'data',
'data',
],
];
}
/**
* @dataProvider dataProviderSetValue
*
* @param array $array_input
* @param string|array|null $key
* @param mixed $value
* @param mixed $expected
*/
public function testSetValue($array_input, $key, $value, $expected)
{
ArrayHelper::setValue($array_input, $key, $value);
$this->assertEquals($expected, $array_input);
}
public function testIsAssociative()
{
$this->assertFalse(ArrayHelper::isAssociative('test'));
$this->assertFalse(ArrayHelper::isAssociative([]));
$this->assertFalse(ArrayHelper::isAssociative([1, 2, 3]));
$this->assertFalse(ArrayHelper::isAssociative([1], false));
$this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test']));
$this->assertFalse(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3]));
$this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3], false));
}
public function testIsIndexed()
{
$this->assertFalse(ArrayHelper::isIndexed('test'));
$this->assertTrue(ArrayHelper::isIndexed([]));
$this->assertTrue(ArrayHelper::isIndexed([1, 2, 3]));
$this->assertTrue(ArrayHelper::isIndexed([2 => 'a', 3 => 'b']));
$this->assertFalse(ArrayHelper::isIndexed([2 => 'a', 3 => 'b'], true));
$this->assertFalse(ArrayHelper::isIndexed(['a' => 'b'], false));
}
public function testHtmlEncode()
{
$array = [
'abc' => '123',
'<' => '>',
'cde' => false,
3 => 'blank',
[
'<>' => 'a<>b',
'23' => true,
],
'invalid' => "a\x80b",
];
$this->assertEquals([
'abc' => '123',
'<' => '>',
'cde' => false,
3 => 'blank',
[
'<>' => 'a<>b',
'23' => true,
],
'invalid' => 'a�b',
], ArrayHelper::htmlEncode($array));
$this->assertEquals([
'abc' => '123',
'<' => '>',
'cde' => false,
3 => 'blank',
[
'<>' => 'a<>b',
'23' => true,
],
'invalid' => 'a�b',
], ArrayHelper::htmlEncode($array, false));
}
public function testHtmlDecode()
{
$array = [
'abc' => '123',
'<' => '>',
'cde' => false,
3 => 'blank',
[
'<>' => 'a<>b',
'<a>' => '<a href="index.php?a=1&b=2">link</a>',
'23' => true,
],
];
$expected = [
'abc' => '123',
'<' => '>',
'cde' => false,
3 => 'blank',
[
'<>' => 'a<>b',
'<a>' => 'link',
'23' => true,
],
];
$this->assertEquals($expected, ArrayHelper::htmlDecode($array));
$expected = [
'abc' => '123',
'<' => '>',
'cde' => false,
3 => 'blank',
[
'<>' => 'a<>b',
'' => 'link',
'23' => true,
],
];
$this->assertEquals($expected, ArrayHelper::htmlDecode($array, false));
}
public function testIsIn()
{
$this->assertTrue(ArrayHelper::isIn('a', new \ArrayObject(['a', 'b'])));
$this->assertTrue(ArrayHelper::isIn('a', ['a', 'b']));
$this->assertTrue(ArrayHelper::isIn('1', new \ArrayObject([1, 'b'])));
$this->assertTrue(ArrayHelper::isIn('1', [1, 'b']));
$this->assertFalse(ArrayHelper::isIn('1', new \ArrayObject([1, 'b']), true));
$this->assertFalse(ArrayHelper::isIn('1', [1, 'b'], true));
$this->assertTrue(ArrayHelper::isIn(['a'], new \ArrayObject([['a'], 'b'])));
$this->assertFalse(ArrayHelper::isIn('a', new \ArrayObject([['a'], 'b'])));
$this->assertFalse(ArrayHelper::isIn('a', [['a'], 'b']));
}
public function testIsInStrict()
{
// strict comparison
$this->assertTrue(ArrayHelper::isIn(1, new \ArrayObject([1, 'a']), true));
$this->assertTrue(ArrayHelper::isIn(1, [1, 'a'], true));
$this->assertFalse(ArrayHelper::isIn('1', new \ArrayObject([1, 'a']), true));
$this->assertFalse(ArrayHelper::isIn('1', [1, 'a'], true));
}
public function testInException()
{
$this->expectException('yii\base\InvalidParamException');
$this->expectExceptionMessage('Argument $haystack must be an array or implement Traversable');
ArrayHelper::isIn('value', null);
}
public function testIsSubset()
{
$this->assertTrue(ArrayHelper::isSubset(['a'], new \ArrayObject(['a', 'b'])));
$this->assertTrue(ArrayHelper::isSubset(new \ArrayObject(['a']), ['a', 'b']));
$this->assertTrue(ArrayHelper::isSubset([1], new \ArrayObject(['1', 'b'])));
$this->assertTrue(ArrayHelper::isSubset(new \ArrayObject([1]), ['1', 'b']));
$this->assertFalse(ArrayHelper::isSubset([1], new \ArrayObject(['1', 'b']), true));
$this->assertFalse(ArrayHelper::isSubset(new \ArrayObject([1]), ['1', 'b'], true));
}
public function testIsSubsetException()
{
$this->expectException('yii\base\InvalidParamException');
$this->expectExceptionMessage('Argument $needles must be an array or implement Traversable');
ArrayHelper::isSubset('a', new \ArrayObject(['a', 'b']));
}
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(ArrayHelper::isTraversable(false));
$this->assertFalse(ArrayHelper::isTraversable(null));
}
public function testFilter()
{
$array = [
'A' => [
'B' => 1,
'C' => 2,
'D' => [
'E' => 1,
'F' => 2,
],
],
'G' => 1,
];
//Include tests
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
'D' => [
'E' => 1,
'F' => 2,
],
],
], ArrayHelper::filter($array, ['A']));
$this->assertEquals([
'A' => [
'B' => 1,
],
], ArrayHelper::filter($array, ['A.B']));
$this->assertEquals([
'A' => [
'D' => [
'E' => 1,
'F' => 2,
],
],
], ArrayHelper::filter($array, ['A.D']));
$this->assertEquals([
'A' => [
'D' => [
'E' => 1,
],
],
], ArrayHelper::filter($array, ['A.D.E']));
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
'D' => [
'E' => 1,
'F' => 2,
],
],
'G' => 1,
], ArrayHelper::filter($array, ['A', 'G']));
$this->assertEquals([
'A' => [
'D' => [
'E' => 1,
],
],
'G' => 1,
], ArrayHelper::filter($array, ['A.D.E', 'G']));
//Exclude (combined with include) tests
$this->assertEquals([
'A' => [
'C' => 2,
'D' => [
'E' => 1,
'F' => 2,
],
],
], ArrayHelper::filter($array, ['A', '!A.B']));
$this->assertEquals([
'A' => [
'C' => 2,
'D' => [
'E' => 1,
'F' => 2,
],
],
], ArrayHelper::filter($array, ['!A.B', 'A']));
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
'D' => [
'F' => 2,
],
],
], ArrayHelper::filter($array, ['A', '!A.D.E']));
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
],
], ArrayHelper::filter($array, ['A', '!A.D']));
$this->assertEquals([
'G' => 1
], ArrayHelper::filter($array, ['G', '!Z', '!X.A']));
//Non existing keys tests
$this->assertEquals([], ArrayHelper::filter($array, ['X']));
$this->assertEquals([], ArrayHelper::filter($array, ['X.Y']));
$this->assertEquals([], ArrayHelper::filter($array, ['X.Y.Z']));
$this->assertEquals([], ArrayHelper::filter($array, ['A.X']));
//Values that evaluate to `true` with `empty()` tests
$tmp = [
'a' => 0,
'b' => '',
'c' => false,
'd' => null,
'e' => true,
];
$this->assertEquals($tmp, ArrayHelper::filter($tmp, array_keys($tmp)));
}
/**
* @see https://github.com/yiisoft/yii2/issues/18395
*/
public function testFilterForIntegerKeys()
{
$array = ['a', 'b', ['c', 'd']];
// to make sure order is changed test it encoded
$this->assertEquals('{"1":"b","0":"a"}', json_encode(ArrayHelper::filter($array, [1, 0])));
$this->assertEquals([2 => ['c']], ArrayHelper::filter($array, ['2.0']));
$this->assertEquals([2 => [1 => 'd']], ArrayHelper::filter($array, [2, '!2.0']));
}
public function testFilterWithInvalidValues()
{
$array = ['a' => 'b'];
$this->assertEquals([], ArrayHelper::filter($array, [new \stdClass()]));
$this->assertEquals([], ArrayHelper::filter($array, [['a']]));
}
/**
* @see https://github.com/yiisoft/yii2/issues/18086
*/
public function testArrayAccessWithPublicProperty()
{
$data = new ArrayAccessibleObject(['value' => 123]);
$this->assertEquals(123, ArrayHelper::getValue($data, 'value'));
$this->assertEquals('bar1', ArrayHelper::getValue($data, 'name'));
}
/**
* https://github.com/yiisoft/yii2/commit/35fb9c624893855317e5fe52e6a21f6518a9a31c changed the way
* ArrayHelper works with existing object properties in case of ArrayAccess.
*/
public function testArrayAccessWithMagicProperty()
{
$model = new MagicModel();
$this->assertEquals(42, ArrayHelper::getValue($model, 'magic'));
$this->assertEquals('ta-da', ArrayHelper::getValue($model, 'moreMagic'));
}
/**
* @dataProvider dataProviderRecursiveSort
*
* @return void
*/
public function testRecursiveSort($expected_result, $input_array)
{
$actual = ArrayHelper::recursiveSort($input_array);
$this->assertEquals($expected_result, $actual);
}
/**
* Data provider for [[testRecursiveSort()]].
* @return array test data
*/
public function dataProviderRecursiveSort()
{
return [
//Normal index array
[
[1, 2, 3, 4],
[4, 1, 3, 2]
],
//Normal associative array
[
['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
['b' => 2, 'a' => 1, 'd' => 4, 'c' => 3],
],
//Normal index array
[
[1, 2, 3, 4],
[4, 1, 3, 2]
],
//Multidimensional associative array
[
[
'a' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
'b' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
'c' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
'd' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
],
[
'b' => ['a' => 1, 'd' => 4, 'b' => 2, 'c' => 3],
'd' => ['b' => 2, 'c' => 3, 'a' => 1, 'd' => 4],
'c' => ['c' => 3, 'a' => 1, 'd' => 4, 'b' => 2],
'a' => ['d' => 4, 'b' => 2, 'c' => 3, 'a' => 1],
],
],
//Multidimensional associative array
[
[
'a' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]],
'b' => ['a' => 1, 'b' => 2, 'c' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], 'd' => 4],
'c' => ['a' => 1, 'b' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], 'c' => 3, 'd' => 4],
'd' => ['a' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], 'b' => 2, 'c' => 3, 'd' => 4],
],
[
'b' => ['a' => 1, 'd' => 4, 'b' => 2, 'c' => ['b' => 2, 'c' => 3, 'a' => 1, 'd' => 4]],
'd' => ['b' => 2, 'c' => 3, 'a' => ['a' => 1, 'd' => 4, 'b' => 2, 'c' => 3], 'd' => 4],
'c' => ['c' => 3, 'a' => 1, 'd' => 4, 'b' => ['c' => 3, 'a' => 1, 'd' => 4, 'b' => 2]],
'a' => ['d' => ['d' => 4, 'b' => 2, 'c' => 3, 'a' => 1], 'b' => 2, 'c' => 3, 'a' => 1],
]
],
];
}
}
class Post1
{
public $id = 23;
public $title = 'tt';
}
class Post2 extends BaseObject
{
public $id = 123;
public $content = 'test';
private $secret = 's';
public function getSecret()
{
return $this->secret;
}
}
class Post3 extends BaseObject
{
public $id = 33;
/** @var BaseObject */
public $subObject;
public function init()
{
$this->subObject = new Post2();
}
}
class ArrayAccessibleObject implements ArrayAccess
{
public $name = 'bar1';
protected $container = [];
public function __construct($container)
{
$this->container = $container;
}
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return array_key_exists($offset, $this->container);
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->container[$offset] : null;
}
}
class TraversableArrayAccessibleObject extends ArrayAccessibleObject implements Iterator
{
private $position = 0;
public function __construct($container)
{
$this->position = 0;
parent::__construct($container);
}
protected function getContainerKey($keyIndex)
{
$keys = array_keys($this->container);
return array_key_exists($keyIndex, $keys) ? $keys[$keyIndex] : false;
}
#[\ReturnTypeWillChange]
public function rewind()
{
$this->position = 0;
}
#[\ReturnTypeWillChange]
public function current()
{
return $this->offsetGet($this->getContainerKey($this->position));
}
#[\ReturnTypeWillChange]
public function key()
{
return $this->getContainerKey($this->position);
}
#[\ReturnTypeWillChange]
public function next()
{
++$this->position;
}
#[\ReturnTypeWillChange]
public function valid()
{
$key = $this->getContainerKey($this->position);
return !(!$key || !$this->offsetExists($key));
}
}
class MagicModel extends Model
{
protected $magic;
public function getMagic()
{
return 42;
}
private $moreMagic;
public function getMoreMagic()
{
return 'ta-da';
}
}