Skip to content

Commit

Permalink
Merge pull request #87 from Hi-Folks/feat/nested-set
Browse files Browse the repository at this point in the history
The `set()` method supports nested keys
  • Loading branch information
roberto-butti authored Jun 13, 2024
2 parents f382791 + 7d7aa34 commit faeeab8
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 24 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.1.0 - 2024-06-13
- Add the Arr `set()` method supports 'dot' (or custom) notation for nested arrays for setting nested values, for example, `$arr`->set('first-level.second-level.third-level', "something")`
- Renamed the `$index` parameter, into `$key` for `set()` and `get()` method. Why: in my opinion "index" is more related to array integer keys . "key" is more generic and refers to generic keys (string for example).

## 1.0.3 - 2024-05-25
- Add the Arr `getArr()` method for retrieving portions of complex nested arrays as Arr object.

Expand Down
52 changes: 48 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ The Arr class provides some methods:
- unset(): ability to unset an element by the key

### The `get()` method
The `get()` method supports keys with the dot (or custom) notation for retrieving values from nested arrays.
The `get()` method supports keys/indexes with the dot (or custom) notation for retrieving values from nested arrays.
For example:

```php
Expand Down Expand Up @@ -100,8 +100,8 @@ $fruits->get('red#somestrangefruit',
```

### The `getArr()` method
If you need to manage complex array (nested array), or an array obtained from a complex JSON structure, you can access to a portion of the array and obtain an Arr object.
Just because in case of complex array the get() method could return a classic array.
If you need to manage a complex array (nested array), or an array obtained from a complex JSON structure, you can access a portion of the array and obtain an Arr object.
Just because in the case of a complex array the `get()` method could return a classic array.

Let's see an example:

Expand Down Expand Up @@ -140,10 +140,54 @@ $appleArr = $arr->getArr("apple")
$arr->getArr("apple")->count();

```
### The `set()` method
The `set()` method supports keys with the dot (or custom) notation for setting values for nested arrays.
If a key doesn't exist, the `set()` method will create a new key and will set the value.
If a key already exists, the `set()` method will replace the value related to the key.

For example:

```php
$articleText = "Some words as a sample sentence";
$textField = Arr::make();
$textField->set("type", "doc");
$textField->set("content.0.content.0.text", $articleText);
$textField->set("content.0.content.0.type", "text");
$textField->set("content.0.type", "paragraph");
```

So when you try to set a nested key as "content.0.content.0.text", it will be created elements as a nested array.
So if you try to dump the value of the array of `$textField` you will see the following structure:

```
var_dump($textField->arr());
array(2) {
["type"]=>
string(3) "doc"
["content"]=>
array(1) {
[0]=>
array(2) {
["content"]=>
array(1) {
[0]=>
array(2) {
["text"]=>
string(31) "Some words as a sample sentence"
["type"]=>
string(4) "text"
}
}
["type"]=>
string(9) "paragraph"
}
}
}
```

## Table class
Table class allows you to manage bi dimensional array, something like:
Table class allows you to manage bi-dimensional array, something like:
```
[
['product' => 'Desk', 'price' => 200, 'active' => true],
Expand Down
63 changes: 43 additions & 20 deletions src/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,17 @@ public function arr(): array
}

/**
* Get the element with $index
* Get the element with $key
*
* @param non-empty-string $charNestedKey
*/
public function get(mixed $index, mixed $defaultValue = null, string $charNestedKey = "."): mixed
public function get(mixed $key, mixed $defaultValue = null, string $charNestedKey = "."): mixed
{
if (is_string($index)) {
$indexString = strval($index);
if (str_contains($indexString, $charNestedKey)) {
if (is_string($key)) {
$keyString = strval($key);
if (str_contains($keyString, $charNestedKey)) {
$nestedValue = $this->arr;
foreach (explode($charNestedKey, $indexString) as $nestedKey) {
foreach (explode($charNestedKey, $keyString) as $nestedKey) {
if (is_array($nestedValue) && array_key_exists($nestedKey, $nestedValue)) {
$nestedValue = $nestedValue[$nestedKey];
} else {
Expand All @@ -127,34 +127,34 @@ public function get(mixed $index, mixed $defaultValue = null, string $charNested
return $nestedValue;
}
}
return $this->arr[$index] ?? $defaultValue;
return $this->arr[$key] ?? $defaultValue;
}

/**
* Get the element with $index as Arr object
* Get the element with $key as Arr object
* This is helpful when the element is an array, and you
* need to get the Arr object instead of the classic array
* In the case the $index doesn't exist, an empty Arr can be returned
* In the case the $key doesn't exist, an empty Arr can be returned
* @param non-empty-string $charNestedKey
*/
public function getArr(mixed $index, mixed $defaultValue = null, string $charNestedKey = "."): Arr
public function getArr(mixed $key, mixed $defaultValue = null, string $charNestedKey = "."): Arr
{
$value = $this->getArrNullable($index, $defaultValue, $charNestedKey);
$value = $this->getArrNullable($key, $defaultValue, $charNestedKey);
if (is_null($value)) {
return Arr::make([]);
}
return $value;
}
/**
* Get the element with $index as Arr object
* Get the element with $key as Arr object
* This is helpful when the element is an array, and you
* need to get the Arr object instead of the classic array
* In the case the $index doesn't exist, null can be returned
* In the case the $key doesn't exist, null can be returned
* @param non-empty-string $charNestedKey
*/
public function getArrNullable(mixed $index, mixed $defaultValue = null, string $charNestedKey = "."): Arr|null
public function getArrNullable(mixed $key, mixed $defaultValue = null, string $charNestedKey = "."): Arr|null
{
$value = $this->get($index, $defaultValue, $charNestedKey);
$value = $this->get($key, $defaultValue, $charNestedKey);
if (is_null($value)) {
return null;
}
Expand All @@ -171,21 +171,44 @@ public function getArrNullable(mixed $index, mixed $defaultValue = null, string
}



/**
* Set a value to a specific key
* Set a value to a specific $key
* You can use the dot notation for setting a nested value.
* @param non-empty-string $charNestedKey
*/
public function set(int|string $key, mixed $value): void
public function set(int|string $key, mixed $value, string $charNestedKey = "."): void
{
if (is_string($key)) {
$array = &$this->arr;
$keys = explode($charNestedKey, $key);
foreach ($keys as $i => $key) {
if (count($keys) === 1) {
break;
}
unset($keys[$i]);

if (!isset($array[$key]) || !is_array($array[$key])) {
$array[$key] = [];
}

$array = &$array[$key];
}

$array[array_shift($keys)] = $value;
return;

}
$this->arr[$key] = $value;
}

/**
* Unset an array element by their key if it exists
*/
public function unset(mixed $index): bool
public function unset(mixed $key): bool
{
if ($this->get($index)) {
unset($this->arr[$index]);
if ($this->get($key)) {
unset($this->arr[$key]);
return true;
}

Expand Down
61 changes: 61 additions & 0 deletions tests/ArrSetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

use HiFolks\DataType\Arr;

it('Basic set', function (): void {
$arr = Arr::make(['A', 'B', 'C']);
expect($arr->set(0, 1));
expect($arr)->toHaveCount(3);
expect($arr->set("some", 1));
expect($arr)->toHaveCount(4);
$arr->set("some.thing", 123);
expect($arr)->toHaveCount(4);
expect($arr->get("some.thing"))->toBe(123);
$arr->set("test.key.not.exists", "999");
expect($arr)->toHaveCount(5);
expect($arr->get("test"))->toHaveCount(1);
expect($arr->get("test.key"))->toHaveCount(1);
expect($arr->get("test.XXX"))->toBeNull();
$arr->set("test#key#not#exists", "111", "#");
expect($arr)->toHaveCount(5);
expect($arr->get("test"))->toHaveCount(1);
expect($arr->get("test.key"))->toHaveCount(1);
expect($arr->get("test.XXX"))->toBeNull();
//$arr->set(null,1);
});

it(
'Nested set array',
function (): void {
$articleText = "Some words as a sample sentence";
$textFieldArray = [
"type" => "doc",
"content" => [
[
"content" => [
[
"text" => $articleText,
"type" => "text"
]
],
"type" => "paragraph"
]
]
];
$textField = Arr::make();
$textField->set("type", "doc");
$textField->set("content.0.content.0.text", $articleText);
$textField->set("content.0.content.0.type", "text");
$textField->set("content.0.type", "paragraph");

expect($textField->arr()["content"][0]["content"][0]["text"])->toBe($articleText);
expect($textField->getArr("content.0.content.0.text"))->toHaveCount(1);
expect($textField->get("content.0.content.0.text"))->toBeString();

$textField->set("content.0.content.0.text", "Changing Text");
expect($textField->arr()["content"][0]["content"][0]["text"])->toBe("Changing Text");
expect($textField->getArr("content.0.content.0.text"))->toHaveCount(1);
expect($textField->get("content.0.content.0.text"))->toBeString();

}
);

0 comments on commit faeeab8

Please sign in to comment.