Skip to content

Commit

Permalink
Merge pull request #153 from andrey-helldar/4.x
Browse files Browse the repository at this point in the history
[4.x] Added the ability to get the value of an array by dot
  • Loading branch information
Andrey Helldar committed Jul 27, 2021
2 parents 938ee5c + 1fdded3 commit 089f55a
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 2 deletions.
30 changes: 28 additions & 2 deletions src/Helpers/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,14 @@ public function exists($array, $key): bool
return $array->offsetExists($key);
}

return isset($array[$key]);
return array_key_exists($key, $array);
}

/**
* Get an item from an array.
*
* @see https://github.com/illuminate/collections/blob/master/Arr.php
*
* @param array|ArrayAccess $array
* @param mixed $key
* @param mixed|null $default
Expand All @@ -306,7 +308,31 @@ public function exists($array, $key): bool
*/
public function get($array, $key, $default = null)
{
return $array[$key] ?? $default;
if (! $this->isArrayable($array)) {
return $default;
}

if (is_null($key)) {
return $array;
}

if ($this->exists($array, $key)) {
return $array[$key];
}

if (strpos($key, '.') === false) {
return $array[$key] ?? $default;
}

foreach (explode('.', $key) as $segment) {
if ($this->isArrayable($array) && $this->exists($array, $segment)) {
$array = $array[$segment];
} else {
return $default;
}
}

return $array;
}

/**
Expand Down
81 changes: 81 additions & 0 deletions tests/Facades/Helpers/ArrTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Tests\Facades\Helpers;

use ArrayObject;
use Helldar\Support\Facades\Helpers\Ables\Arrayable as ArrayableHelper;
use Helldar\Support\Facades\Helpers\Arr;
use Helldar\Support\Facades\Helpers\Str;
Expand Down Expand Up @@ -142,6 +143,86 @@ public function testGet()
$this->assertSame('Baz', Arr::get(new Arrayable(), 'baz'));

$this->assertNull(Arr::get(new Arrayable(), 'qwerty'));

$this->assertNull(Arr::get(new Arrayable(), 'qwerty'));

$array = ['products.desk' => ['price' => 100]];
$this->assertEquals(['price' => 100], Arr::get($array, 'products.desk'));

$array = ['products' => ['desk' => ['price' => 100]]];
$value = Arr::get($array, 'products.desk');
$this->assertEquals(['price' => 100], $value);

// Test null array values
$array = ['foo' => null, 'bar' => ['baz' => null]];
$this->assertNull(Arr::get($array, 'foo', 'default'));
$this->assertNull(Arr::get($array, 'bar.baz', 'default'));

// Test direct ArrayAccess object
$array = ['products' => ['desk' => ['price' => 100]]];
$arrayAccessObject = new ArrayObject($array);
$value = Arr::get($arrayAccessObject, 'products.desk');
$this->assertEquals(['price' => 100], $value);

// Test array containing ArrayAccess object
$arrayAccessChild = new ArrayObject(['products' => ['desk' => ['price' => 100]]]);
$array = ['child' => $arrayAccessChild];
$value = Arr::get($array, 'child.products.desk');
$this->assertEquals(['price' => 100], $value);

// Test array containing multiple nested ArrayAccess objects
$arrayAccessChild = new ArrayObject(['products' => ['desk' => ['price' => 100]]]);
$arrayAccessParent = new ArrayObject(['child' => $arrayAccessChild]);
$array = ['parent' => $arrayAccessParent];
$value = Arr::get($array, 'parent.child.products.desk');
$this->assertEquals(['price' => 100], $value);

// Test missing ArrayAccess object field
$arrayAccessChild = new ArrayObject(['products' => ['desk' => ['price' => 100]]]);
$arrayAccessParent = new ArrayObject(['child' => $arrayAccessChild]);
$array = ['parent' => $arrayAccessParent];
$value = Arr::get($array, 'parent.child.desk');
$this->assertNull($value);

// Test missing ArrayAccess object field
$arrayAccessObject = new ArrayObject(['products' => ['desk' => null]]);
$array = ['parent' => $arrayAccessObject];
$value = Arr::get($array, 'parent.products.desk.price');
$this->assertNull($value);

// Test null ArrayAccess object fields
$array = new ArrayObject(['foo' => null, 'bar' => new ArrayObject(['baz' => null])]);
$this->assertNull(Arr::get($array, 'foo', 'default'));
$this->assertNull(Arr::get($array, 'bar.baz', 'default'));

// Test null key returns the whole array
$array = ['foo', 'bar'];
$this->assertEquals($array, Arr::get($array, null));

// Test $array not an array
$this->assertSame('default', Arr::get(null, 'foo', 'default'));
$this->assertSame('default', Arr::get(false, 'foo', 'default'));

// Test $array not an array and key is null
$this->assertSame('default', Arr::get(null, null, 'default'));

// Test $array is empty and key is null
$this->assertEmpty(Arr::get([], null));
$this->assertEmpty(Arr::get([], null, 'default'));

// Test numeric keys
$array = [
'products' => [
['name' => 'desk'],
['name' => 'chair'],
],
];
$this->assertSame('desk', Arr::get($array, 'products.0.name'));
$this->assertSame('chair', Arr::get($array, 'products.1.name'));

// Test return default value for non-existing key.
$array = ['names' => ['developer' => 'taylor']];
$this->assertSame('dayle', Arr::get($array, 'names.otherDeveloper', 'dayle'));
}

public function testMerge()
Expand Down
79 changes: 79 additions & 0 deletions tests/Helpers/ArrTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Tests\Helpers;

use ArrayObject;
use Helldar\Support\Facades\Helpers\Ables\Arrayable as ArrayableHelper;
use Helldar\Support\Facades\Helpers\Str;
use Helldar\Support\Helpers\Ables\Arrayable as Helper;
Expand Down Expand Up @@ -158,6 +159,84 @@ public function testGet()
$this->assertSame('Baz', $this->arr()->get(new Arrayable(), 'baz'));

$this->assertNull($this->arr()->get(new Arrayable(), 'qwerty'));

$array = ['products.desk' => ['price' => 100]];
$this->assertEquals(['price' => 100], $this->arr()->get($array, 'products.desk'));

$array = ['products' => ['desk' => ['price' => 100]]];
$value = $this->arr()->get($array, 'products.desk');
$this->assertEquals(['price' => 100], $value);

// Test null array values
$array = ['foo' => null, 'bar' => ['baz' => null]];
$this->assertNull($this->arr()->get($array, 'foo', 'default'));
$this->assertNull($this->arr()->get($array, 'bar.baz', 'default'));

// Test direct ArrayAccess object
$array = ['products' => ['desk' => ['price' => 100]]];
$arrayAccessObject = new ArrayObject($array);
$value = $this->arr()->get($arrayAccessObject, 'products.desk');
$this->assertEquals(['price' => 100], $value);

// Test array containing ArrayAccess object
$arrayAccessChild = new ArrayObject(['products' => ['desk' => ['price' => 100]]]);
$array = ['child' => $arrayAccessChild];
$value = $this->arr()->get($array, 'child.products.desk');
$this->assertEquals(['price' => 100], $value);

// Test array containing multiple nested ArrayAccess objects
$arrayAccessChild = new ArrayObject(['products' => ['desk' => ['price' => 100]]]);
$arrayAccessParent = new ArrayObject(['child' => $arrayAccessChild]);
$array = ['parent' => $arrayAccessParent];
$value = $this->arr()->get($array, 'parent.child.products.desk');
$this->assertEquals(['price' => 100], $value);

// Test missing ArrayAccess object field
$arrayAccessChild = new ArrayObject(['products' => ['desk' => ['price' => 100]]]);
$arrayAccessParent = new ArrayObject(['child' => $arrayAccessChild]);
$array = ['parent' => $arrayAccessParent];
$value = $this->arr()->get($array, 'parent.child.desk');
$this->assertNull($value);

// Test missing ArrayAccess object field
$arrayAccessObject = new ArrayObject(['products' => ['desk' => null]]);
$array = ['parent' => $arrayAccessObject];
$value = $this->arr()->get($array, 'parent.products.desk.price');
$this->assertNull($value);

// Test null ArrayAccess object fields
$array = new ArrayObject(['foo' => null, 'bar' => new ArrayObject(['baz' => null])]);
$this->assertNull($this->arr()->get($array, 'foo', 'default'));
$this->assertNull($this->arr()->get($array, 'bar.baz', 'default'));

// Test null key returns the whole array
$array = ['foo', 'bar'];
$this->assertEquals($array, $this->arr()->get($array, null));

// Test $array not an array
$this->assertSame('default', $this->arr()->get(null, 'foo', 'default'));
$this->assertSame('default', $this->arr()->get(false, 'foo', 'default'));

// Test $array not an array and key is null
$this->assertSame('default', $this->arr()->get(null, null, 'default'));

// Test $array is empty and key is null
$this->assertEmpty($this->arr()->get([], null));
$this->assertEmpty($this->arr()->get([], null, 'default'));

// Test numeric keys
$array = [
'products' => [
['name' => 'desk'],
['name' => 'chair'],
],
];
$this->assertSame('desk', $this->arr()->get($array, 'products.0.name'));
$this->assertSame('chair', $this->arr()->get($array, 'products.1.name'));

// Test return default value for non-existing key.
$array = ['names' => ['developer' => 'taylor']];
$this->assertSame('dayle', $this->arr()->get($array, 'names.otherDeveloper', 'dayle'));
}

public function testMerge()
Expand Down

0 comments on commit 089f55a

Please sign in to comment.