Adding replace and replaceRecursively methods
This commit is contained in:
@ -20,5 +20,8 @@
|
||||
"files": [
|
||||
"src/helper.php"
|
||||
]
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.3"
|
||||
}
|
||||
}
|
||||
|
25
readme.md
25
readme.md
@ -1,15 +1,22 @@
|
||||
Ary
|
||||
===
|
||||
|
||||
Are you tired from casting objects and arrays to each other or are bored using is `isset`? Don't do those anymore!
|
||||
Ary is a light class/function that makes accessing array items more convenient.
|
||||
Ary provides unified interface for ary/object. Really handy to store:
|
||||
|
||||
- arrays/objects those their items/properties varies conditionally.
|
||||
- storing registry, system configuration, env variables, etc.
|
||||
- when you perform a chain of action on an array/object
|
||||
|
||||
It's super cool and after a while you can not code in php without it.
|
||||
|
||||
Features
|
||||
---------
|
||||
1. You can access array items using `->` or `['']` syntax.
|
||||
2. You will get `null` if an index does not exists (instead of a nasty notification!)
|
||||
3. You can specify a default value for missing indexes.
|
||||
4. You can set/get a value within a deeply nested array using "dot" notation.
|
||||
5. A bunch of really handy methods: `merge`, `only`, `search`, `toObject`, ...
|
||||
6. (new) It extends `Illuminate\Support\Collection` class so all of its methods are available (https://laravel.com/docs/master/eloquent-collections)
|
||||
6. Now, `Ary` extends `Illuminate\Support\Collection` class so all of its methods are available (https://laravel.com/docs/master/eloquent-collections)
|
||||
|
||||
Examples
|
||||
--------
|
||||
@ -24,7 +31,7 @@ $ary = ary(2, 4, 6, 8); // or
|
||||
$ary = ary([2, 4, 6, 8]);
|
||||
$ary = ary(['x' => 'foo', 'y' => 'bar']);
|
||||
|
||||
//Assignment;
|
||||
//Assignment
|
||||
$ary->newItem=20; //or
|
||||
$ary['newItem']=20;
|
||||
|
||||
@ -34,7 +41,7 @@ $foo = $ary['x'];
|
||||
$missed = $ary->get('missed', 'Default value');
|
||||
$ary->all(); // returns the simple php array;
|
||||
|
||||
// behave similar to regular arrays
|
||||
// behaive as regular arrays
|
||||
count($ary); //returns 3
|
||||
unset($ary[0]);
|
||||
json_encode($ary);
|
||||
@ -48,14 +55,14 @@ $ary['production.table.weight']=200;
|
||||
|
||||
Installation
|
||||
============
|
||||
Simply, `include '__DIR__.'/src/helper.php';`
|
||||
Simply `include '__DIR__.'/src/helper.php';`
|
||||
|
||||
or using Composer:
|
||||
or use Composer:
|
||||
|
||||
composer require salarmehr/ary
|
||||
|
||||
* The class (`Ary()`) requires PHP 5.4 or newer.
|
||||
* The helper function (`ary()`) requires PHP 5.6 or newer.
|
||||
* The class (`Ary()`) requires PHP 5.4 or above.
|
||||
* The helper function (`ary()`) requires PHP 5.6 or above.
|
||||
|
||||
Licence
|
||||
=======
|
||||
|
255
src/Ary.php
255
src/Ary.php
@ -10,139 +10,160 @@
|
||||
|
||||
namespace Salarmehr;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use Illuminate\Support\Collection;
|
||||
use IteratorAggregate;
|
||||
use JsonSerializable;
|
||||
|
||||
class Ary extends Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
|
||||
class Ary extends Collection
|
||||
{
|
||||
/**
|
||||
* Create a new collection.
|
||||
*
|
||||
* @param mixed $items
|
||||
*/
|
||||
/**
|
||||
* Create a new ary.
|
||||
*
|
||||
* @param mixed $items
|
||||
*/
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$items = func_get_args();
|
||||
if (count($items) === 0) {
|
||||
$items = [];
|
||||
}
|
||||
elseif (count($items) === 1) {
|
||||
$items = is_array($items[0]) ? $items[0] : $this->getArrayableItems($items[0]);
|
||||
}
|
||||
$this->items = $items;
|
||||
public function __construct()
|
||||
{
|
||||
$items = func_get_args();
|
||||
if (count($items) === 0) {
|
||||
$items = [];
|
||||
}
|
||||
elseif (count($items) === 1) {
|
||||
$items = is_array($items[0]) ? $items[0] : $this->getArrayableItems($items[0]);
|
||||
}
|
||||
$this->items = $items;
|
||||
}
|
||||
|
||||
public function &__get($item)
|
||||
{
|
||||
return $this->get($item);
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->offsetSet($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from the ary by key.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function &get($key, $default = null)
|
||||
{
|
||||
if ($this->offsetExists($key)) {
|
||||
return $this->items[$key];
|
||||
}
|
||||
|
||||
public function &__get($item)
|
||||
{
|
||||
return $this->get($item);
|
||||
$array = $this->items;
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($array) || !array_key_exists($segment, $array)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$array = $array[$segment];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the item at a given offset.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
$this->items[] = $value;
|
||||
return;
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->offsetSet($name, $value);
|
||||
$keys = explode('.', $key);
|
||||
$array =& $this->items;
|
||||
while (count($keys) > 1) {
|
||||
$key = array_shift($keys);
|
||||
|
||||
// If the key doesn't exist at this depth, we will just create an empty array
|
||||
// to hold the next value, allowing us to create the arrays to hold final
|
||||
// values at the correct depth. Then we'll keep digging into the array.
|
||||
if (!isset($array[$key]) || !is_array($array[$key])) {
|
||||
$array[$key] = [];
|
||||
}
|
||||
|
||||
$array = &$array[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from the collection by key.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function &get($key, $default = null)
|
||||
{
|
||||
if ($this->offsetExists($key)) {
|
||||
return $this->items[$key];
|
||||
}
|
||||
$array[array_shift($keys)] = $value;
|
||||
return;
|
||||
}
|
||||
|
||||
$array = $this->items;
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($array) || !array_key_exists($segment, $array)) {
|
||||
return $default;
|
||||
}
|
||||
/**
|
||||
* Get an item at a given offset.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function &offsetGet($key)
|
||||
{
|
||||
return $this->get($key);
|
||||
}
|
||||
|
||||
$array = $array[$segment];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the item at a given offset.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
$this->items[] = $value;
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Get the ary of items as a plain object.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function toObject()
|
||||
{
|
||||
return (object)$this->all();
|
||||
}
|
||||
|
||||
// $this->items[$key] = $value;
|
||||
/**
|
||||
* Return a subset of current ary as a new ary
|
||||
* @param $item
|
||||
* @return Ary
|
||||
*/
|
||||
public function ary($item)
|
||||
{
|
||||
return new self($this->get($item));
|
||||
}
|
||||
|
||||
$keys = explode('.', $key);
|
||||
$array =& $this->items;
|
||||
while (count($keys) > 1) {
|
||||
$key = array_shift($keys);
|
||||
public function __unset($key)
|
||||
{
|
||||
$this->offsetUnset($key);
|
||||
}
|
||||
|
||||
// If the key doesn't exist at this depth, we will just create an empty array
|
||||
// to hold the next value, allowing us to create the arrays to hold final
|
||||
// values at the correct depth. Then we'll keep digging into the array.
|
||||
if (!isset($array[$key]) || !is_array($array[$key])) {
|
||||
$array[$key] = [];
|
||||
}
|
||||
#region extra helpers
|
||||
|
||||
$array = &$array[$key];
|
||||
}
|
||||
/**
|
||||
* Replaces elements from passed arrays into the collection
|
||||
*
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
* @see http://php.net/manual/en/function.array-replace-recursive.php
|
||||
*/
|
||||
public function replace($items)
|
||||
{
|
||||
return new static(array_replace($this->items, $this->getArrayableItems($items)));
|
||||
}
|
||||
|
||||
$array[array_shift($keys)] = $value;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item at a given offset.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function &offsetGet($key)
|
||||
{
|
||||
return $this->get($key);
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the collection of items as a plain object.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function toObject()
|
||||
{
|
||||
return (object)$this->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a subset of current ary as a new ary
|
||||
* @param $item
|
||||
* @return Ary
|
||||
*/
|
||||
public function ary($item)
|
||||
{
|
||||
return new ary($this->get($item));
|
||||
}
|
||||
|
||||
public function __unset($key)
|
||||
{
|
||||
$this->offsetUnset($key);
|
||||
}
|
||||
/**
|
||||
* Replaces elements from passed arrays into the collection recursively
|
||||
*
|
||||
* @param mixed $items
|
||||
* @return static
|
||||
* @see http://php.net/manual/en/function.array-replace-recursive.php
|
||||
*/
|
||||
public function replaceRecursively($items)
|
||||
{
|
||||
return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));
|
||||
}
|
||||
#endrtiong
|
||||
}
|
@ -13,7 +13,7 @@ if (!function_exists('ary') && phpversion()) {
|
||||
function parse_version($version)
|
||||
{
|
||||
$version = explode('.', $version);
|
||||
return $version[0] * 10000 + $version[1] * 100 + $version[2];
|
||||
return $version[0] * 10000 + $version[1] * 100 + (int) $version[2];
|
||||
}
|
||||
|
||||
if (!defined('ary') && parse_version(PHP_VERSION) > parse_version('5.6.0')) {
|
||||
|
239
test/Test.php
239
test/Test.php
@ -12,135 +12,152 @@ use \Salarmehr\Ary;
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
require __DIR__ . '/../src/Ary.php';
|
||||
|
||||
class Test extends PHPUnit_Framework_TestCase
|
||||
class Test extends PHPUnit\Framework\TestCase
|
||||
|
||||
{
|
||||
protected $item;
|
||||
protected $item;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$this->item = [];
|
||||
}
|
||||
public function setup()
|
||||
{
|
||||
$this->item = [];
|
||||
}
|
||||
|
||||
public function provider()
|
||||
{
|
||||
return array(
|
||||
array(''),
|
||||
array(['ali', 'reza', 'mohammad']),
|
||||
array([1, 2, 3, 4]),
|
||||
);
|
||||
}
|
||||
public function provider()
|
||||
{
|
||||
return array(
|
||||
array(''),
|
||||
array(['ali', 'reza', 'mohammad']),
|
||||
array([1, 2, 3, 4]),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $originalary array to get
|
||||
* @param array $expectedary What we expect to get
|
||||
*
|
||||
* @dataProvider various
|
||||
*/
|
||||
/**
|
||||
* @param array $originalary array to get
|
||||
* @param array $expectedary What we expect to get
|
||||
*
|
||||
* @dataProvider various
|
||||
*/
|
||||
|
||||
public function testAll($originalary, $expectedary)
|
||||
{
|
||||
$ary = new Ary();
|
||||
$ary->all($originalary);
|
||||
$this->assertEquals($expectedary, $originalary);
|
||||
}
|
||||
public function testAll($originalary, $expectedary)
|
||||
{
|
||||
$ary = new Ary();
|
||||
$ary->all();
|
||||
$this->assertEquals($expectedary, $originalary);
|
||||
}
|
||||
|
||||
public function various()
|
||||
{
|
||||
return array(
|
||||
array('', ''),
|
||||
array(null, null),
|
||||
array(['ali', 'reza', 'mohammad'], ['ali', 'reza', 'mohammad']),
|
||||
array(['name' => 'ali', 'lastname' => 'reza', 'age' => 30], ['name' => 'ali', 'lastname' => 'reza', 'age' => 30]),
|
||||
array((object)['name' => 'ali', 'lastname' => 'reza', 'age' => 30], (object)['name' => 'ali', 'lastname' => 'reza', 'age' => 30]),
|
||||
array(['ali', 'reza', 'mohammad'], ['ali', 'reza', 'mohammad']),
|
||||
array([1, 2, 3, 4], [1, 2, 3, 4]),
|
||||
);
|
||||
}
|
||||
public function various()
|
||||
{
|
||||
return array(
|
||||
array('', ''),
|
||||
array(null, null),
|
||||
array(['ali', 'reza', 'mohammad'], ['ali', 'reza', 'mohammad']),
|
||||
array(['name' => 'ali', 'lastname' => 'reza', 'age' => 30], ['name' => 'ali', 'lastname' => 'reza', 'age' => 30]),
|
||||
array((object)['name' => 'ali', 'lastname' => 'reza', 'age' => 30], (object)['name' => 'ali', 'lastname' => 'reza', 'age' => 30]),
|
||||
array(['ali', 'reza', 'mohammad'], ['ali', 'reza', 'mohammad']),
|
||||
array([1, 2, 3, 4], [1, 2, 3, 4]),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$ary = new Ary();
|
||||
$this->assertEquals($ary[0], null);
|
||||
public function testGet()
|
||||
{
|
||||
$ary = new Ary();
|
||||
$this->assertEquals($ary[0], null);
|
||||
|
||||
$ary = new Ary(['x' => ['xx' => ['m' => 'xxx']]]);
|
||||
$this->assertEquals($ary->get('x.xx.m'), 'xxx');
|
||||
}
|
||||
$ary = new Ary(['x' => ['xx' => ['m' => 'xxx']]]);
|
||||
$this->assertEquals($ary->get('x.xx.m'), 'xxx');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider Provider
|
||||
*/
|
||||
public function testCount($objects)
|
||||
{
|
||||
$ary = new Ary($objects);
|
||||
$result = count($objects);
|
||||
$num = count($ary);
|
||||
$this->assertEquals($result, $num);
|
||||
}
|
||||
/**
|
||||
* @dataProvider Provider
|
||||
*/
|
||||
public function testCount($objects)
|
||||
{
|
||||
$ary = new Ary($objects);
|
||||
$result = count($objects);
|
||||
$num = count($ary);
|
||||
$this->assertEquals($result, $num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider various
|
||||
*/
|
||||
public function testGetArrayableItems($original, $expected)
|
||||
{
|
||||
$ary = new Ary($original);
|
||||
$result = $this->invokeMethod($ary, 'getArrayableItems', array($original));
|
||||
$this->assertEquals($expected, $original);
|
||||
}
|
||||
/**
|
||||
* @dataProvider various
|
||||
*/
|
||||
public function testGetArrayableItems($original, $expected)
|
||||
{
|
||||
$ary = new Ary($original);
|
||||
$this->invokeMethod($ary, 'getArrayableItems', array($original));
|
||||
$this->assertEquals($expected, $original);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object &$ary Instantiated object that we will run method on.
|
||||
* @param string $getArrayableItems Method name to call
|
||||
* @param array $parameters Array of parameters to pass into method.
|
||||
*
|
||||
* @return mixed Method return.
|
||||
*/
|
||||
public function invokeMethod(&$ary, $getArrayableItems, array $parameters = array())
|
||||
{
|
||||
$reflection = new \ReflectionClass(get_class($ary));
|
||||
$method = $reflection->getMethod($getArrayableItems);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($ary, $parameters);
|
||||
}
|
||||
/**
|
||||
* @param object &$ary Instantiated object that we will run method on.
|
||||
* @param string $getArrayableItems Method name to call
|
||||
* @param array $parameters Array of parameters to pass into method.
|
||||
*
|
||||
* @return mixed Method return.
|
||||
*/
|
||||
public function invokeMethod(&$ary, $getArrayableItems, array $parameters = array())
|
||||
{
|
||||
$reflection = new \ReflectionClass(get_class($ary));
|
||||
$method = $reflection->getMethod($getArrayableItems);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($ary, $parameters);
|
||||
}
|
||||
|
||||
public function testAssignment()
|
||||
{
|
||||
$ary = new Ary();
|
||||
public function testAssignment()
|
||||
{
|
||||
$ary = new Ary();
|
||||
// var_dump($ary);die();
|
||||
$ary[] = 3;
|
||||
$this->assertEquals($ary[0], 3);
|
||||
$this->assertEquals($ary->{0}, 3);
|
||||
$this->assertTrue($ary->has(0));
|
||||
$ary['x'] = ['z' => 'y'];
|
||||
$ary['foo'] = 'bar';
|
||||
$this->assertEquals($ary['foo'], 'bar');
|
||||
$this->assertEquals($ary->foo, 'bar');
|
||||
$this->assertTrue($ary->has('foo'));
|
||||
$this->assertEquals($ary['x']['z'], 'y');
|
||||
$ary['x']['z'] = 'm';
|
||||
$this->assertEquals($ary['x']['z'], 'm');
|
||||
$ary[] = 3;
|
||||
$this->assertEquals($ary[0], 3);
|
||||
$this->assertEquals($ary->{0}, 3);
|
||||
$this->assertTrue($ary->has(0));
|
||||
$ary['x'] = ['z' => 'y'];
|
||||
$ary['foo'] = 'bar';
|
||||
$this->assertEquals($ary['foo'], 'bar');
|
||||
$this->assertEquals($ary->foo, 'bar');
|
||||
$this->assertTrue($ary->has('foo'));
|
||||
$this->assertEquals($ary['x']['z'], 'y');
|
||||
$ary['x']['z'] = 'm';
|
||||
$this->assertEquals($ary['x']['z'], 'm');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider various
|
||||
*/
|
||||
public function testJsonSerialize($original, $expected)
|
||||
{
|
||||
$this->assertEquals(json_encode(new Ary($original)), json_encode((array)$original));
|
||||
}
|
||||
/**
|
||||
* @dataProvider various
|
||||
* @param $original
|
||||
*/
|
||||
public function testJsonSerialize($original)
|
||||
{
|
||||
$this->assertEquals(json_encode(new Ary($original)), json_encode((array)$original));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider various
|
||||
*/
|
||||
public function ary()
|
||||
{
|
||||
$test = ['x' => ['xx' => 'xxx']];
|
||||
$ary = new Ary($test);
|
||||
$this->assertEquals(ary($test)->x['xx'], $ary->ary('x')->xx);
|
||||
$this->assertEquals(ary(ary($test)->x['xx']), $ary->ary('x')->ary('xx'));
|
||||
}
|
||||
/**
|
||||
* @dataProvider various
|
||||
*/
|
||||
public function ary()
|
||||
{
|
||||
$test = ['x' => ['xx' => 'xxx']];
|
||||
$ary = new Ary($test);
|
||||
$this->assertEquals(ary($test)->x['xx'], $ary->ary('x')->xx);
|
||||
$this->assertEquals(ary(ary($test)->x['xx']), $ary->ary('x')->ary('xx'));
|
||||
}
|
||||
|
||||
public function testReplace()
|
||||
{
|
||||
$c = new Ary(['foo' => 'x', 'bar' => 'y']);
|
||||
$this->assertEquals(['foo' => 'f', 'bar' => 'y', 'baz' => 'z'], $c->replace(new Ary(['foo' => 'f', 'baz' => 'z']))->all());
|
||||
}
|
||||
|
||||
public function testReplaceAryRecursively()
|
||||
{
|
||||
$base = ['citrus' => ["orange"], 'berries' => ["blackberry", "raspberry"],];
|
||||
$replacements = ['citrus' => ['pineapple'], 'berries' => ['blueberry']];
|
||||
$expect = ['citrus' => ['pineapple'], 'berries' => ['blueberry', 'raspberry']];
|
||||
$c = new Ary($base);
|
||||
$this->assertEquals($expect, $c->replaceRecursively(new Ary($replacements))->all());
|
||||
}
|
||||
|
||||
// public function testOffsetExists()
|
||||
// {
|
||||
|
Reference in New Issue
Block a user