Skip to content

Commit faeeab8

Browse files
Merge pull request #87 from Hi-Folks/feat/nested-set
The `set()` method supports nested keys
2 parents f382791 + 7d7aa34 commit faeeab8

4 files changed

Lines changed: 156 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.1.0 - 2024-06-13
4+
- 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")`
5+
- 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).
6+
37
## 1.0.3 - 2024-05-25
48
- Add the Arr `getArr()` method for retrieving portions of complex nested arrays as Arr object.
59

README.md

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ The Arr class provides some methods:
6565
- unset(): ability to unset an element by the key
6666

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

7171
```php
@@ -100,8 +100,8 @@ $fruits->get('red#somestrangefruit',
100100
```
101101

102102
### The `getArr()` method
103-
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.
104-
Just because in case of complex array the get() method could return a classic array.
103+
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.
104+
Just because in the case of a complex array the `get()` method could return a classic array.
105105

106106
Let's see an example:
107107

@@ -140,10 +140,54 @@ $appleArr = $arr->getArr("apple")
140140
$arr->getArr("apple")->count();
141141

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

148+
For example:
149+
150+
```php
151+
$articleText = "Some words as a sample sentence";
152+
$textField = Arr::make();
153+
$textField->set("type", "doc");
154+
$textField->set("content.0.content.0.text", $articleText);
155+
$textField->set("content.0.content.0.type", "text");
156+
$textField->set("content.0.type", "paragraph");
157+
```
158+
159+
So when you try to set a nested key as "content.0.content.0.text", it will be created elements as a nested array.
160+
So if you try to dump the value of the array of `$textField` you will see the following structure:
161+
162+
```
163+
var_dump($textField->arr());
164+
165+
array(2) {
166+
["type"]=>
167+
string(3) "doc"
168+
["content"]=>
169+
array(1) {
170+
[0]=>
171+
array(2) {
172+
["content"]=>
173+
array(1) {
174+
[0]=>
175+
array(2) {
176+
["text"]=>
177+
string(31) "Some words as a sample sentence"
178+
["type"]=>
179+
string(4) "text"
180+
}
181+
}
182+
["type"]=>
183+
string(9) "paragraph"
184+
}
185+
}
186+
}
187+
```
144188

145189
## Table class
146-
Table class allows you to manage bi dimensional array, something like:
190+
Table class allows you to manage bi-dimensional array, something like:
147191
```
148192
[
149193
['product' => 'Desk', 'price' => 200, 'active' => true],

src/Arr.php

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,17 @@ public function arr(): array
107107
}
108108

109109
/**
110-
* Get the element with $index
110+
* Get the element with $key
111111
*
112112
* @param non-empty-string $charNestedKey
113113
*/
114-
public function get(mixed $index, mixed $defaultValue = null, string $charNestedKey = "."): mixed
114+
public function get(mixed $key, mixed $defaultValue = null, string $charNestedKey = "."): mixed
115115
{
116-
if (is_string($index)) {
117-
$indexString = strval($index);
118-
if (str_contains($indexString, $charNestedKey)) {
116+
if (is_string($key)) {
117+
$keyString = strval($key);
118+
if (str_contains($keyString, $charNestedKey)) {
119119
$nestedValue = $this->arr;
120-
foreach (explode($charNestedKey, $indexString) as $nestedKey) {
120+
foreach (explode($charNestedKey, $keyString) as $nestedKey) {
121121
if (is_array($nestedValue) && array_key_exists($nestedKey, $nestedValue)) {
122122
$nestedValue = $nestedValue[$nestedKey];
123123
} else {
@@ -127,34 +127,34 @@ public function get(mixed $index, mixed $defaultValue = null, string $charNested
127127
return $nestedValue;
128128
}
129129
}
130-
return $this->arr[$index] ?? $defaultValue;
130+
return $this->arr[$key] ?? $defaultValue;
131131
}
132132

133133
/**
134-
* Get the element with $index as Arr object
134+
* Get the element with $key as Arr object
135135
* This is helpful when the element is an array, and you
136136
* need to get the Arr object instead of the classic array
137-
* In the case the $index doesn't exist, an empty Arr can be returned
137+
* In the case the $key doesn't exist, an empty Arr can be returned
138138
* @param non-empty-string $charNestedKey
139139
*/
140-
public function getArr(mixed $index, mixed $defaultValue = null, string $charNestedKey = "."): Arr
140+
public function getArr(mixed $key, mixed $defaultValue = null, string $charNestedKey = "."): Arr
141141
{
142-
$value = $this->getArrNullable($index, $defaultValue, $charNestedKey);
142+
$value = $this->getArrNullable($key, $defaultValue, $charNestedKey);
143143
if (is_null($value)) {
144144
return Arr::make([]);
145145
}
146146
return $value;
147147
}
148148
/**
149-
* Get the element with $index as Arr object
149+
* Get the element with $key as Arr object
150150
* This is helpful when the element is an array, and you
151151
* need to get the Arr object instead of the classic array
152-
* In the case the $index doesn't exist, null can be returned
152+
* In the case the $key doesn't exist, null can be returned
153153
* @param non-empty-string $charNestedKey
154154
*/
155-
public function getArrNullable(mixed $index, mixed $defaultValue = null, string $charNestedKey = "."): Arr|null
155+
public function getArrNullable(mixed $key, mixed $defaultValue = null, string $charNestedKey = "."): Arr|null
156156
{
157-
$value = $this->get($index, $defaultValue, $charNestedKey);
157+
$value = $this->get($key, $defaultValue, $charNestedKey);
158158
if (is_null($value)) {
159159
return null;
160160
}
@@ -171,21 +171,44 @@ public function getArrNullable(mixed $index, mixed $defaultValue = null, string
171171
}
172172

173173

174+
174175
/**
175-
* Set a value to a specific key
176+
* Set a value to a specific $key
177+
* You can use the dot notation for setting a nested value.
178+
* @param non-empty-string $charNestedKey
176179
*/
177-
public function set(int|string $key, mixed $value): void
180+
public function set(int|string $key, mixed $value, string $charNestedKey = "."): void
178181
{
182+
if (is_string($key)) {
183+
$array = &$this->arr;
184+
$keys = explode($charNestedKey, $key);
185+
foreach ($keys as $i => $key) {
186+
if (count($keys) === 1) {
187+
break;
188+
}
189+
unset($keys[$i]);
190+
191+
if (!isset($array[$key]) || !is_array($array[$key])) {
192+
$array[$key] = [];
193+
}
194+
195+
$array = &$array[$key];
196+
}
197+
198+
$array[array_shift($keys)] = $value;
199+
return;
200+
201+
}
179202
$this->arr[$key] = $value;
180203
}
181204

182205
/**
183206
* Unset an array element by their key if it exists
184207
*/
185-
public function unset(mixed $index): bool
208+
public function unset(mixed $key): bool
186209
{
187-
if ($this->get($index)) {
188-
unset($this->arr[$index]);
210+
if ($this->get($key)) {
211+
unset($this->arr[$key]);
189212
return true;
190213
}
191214

tests/ArrSetTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
use HiFolks\DataType\Arr;
4+
5+
it('Basic set', function (): void {
6+
$arr = Arr::make(['A', 'B', 'C']);
7+
expect($arr->set(0, 1));
8+
expect($arr)->toHaveCount(3);
9+
expect($arr->set("some", 1));
10+
expect($arr)->toHaveCount(4);
11+
$arr->set("some.thing", 123);
12+
expect($arr)->toHaveCount(4);
13+
expect($arr->get("some.thing"))->toBe(123);
14+
$arr->set("test.key.not.exists", "999");
15+
expect($arr)->toHaveCount(5);
16+
expect($arr->get("test"))->toHaveCount(1);
17+
expect($arr->get("test.key"))->toHaveCount(1);
18+
expect($arr->get("test.XXX"))->toBeNull();
19+
$arr->set("test#key#not#exists", "111", "#");
20+
expect($arr)->toHaveCount(5);
21+
expect($arr->get("test"))->toHaveCount(1);
22+
expect($arr->get("test.key"))->toHaveCount(1);
23+
expect($arr->get("test.XXX"))->toBeNull();
24+
//$arr->set(null,1);
25+
});
26+
27+
it(
28+
'Nested set array',
29+
function (): void {
30+
$articleText = "Some words as a sample sentence";
31+
$textFieldArray = [
32+
"type" => "doc",
33+
"content" => [
34+
[
35+
"content" => [
36+
[
37+
"text" => $articleText,
38+
"type" => "text"
39+
]
40+
],
41+
"type" => "paragraph"
42+
]
43+
]
44+
];
45+
$textField = Arr::make();
46+
$textField->set("type", "doc");
47+
$textField->set("content.0.content.0.text", $articleText);
48+
$textField->set("content.0.content.0.type", "text");
49+
$textField->set("content.0.type", "paragraph");
50+
51+
expect($textField->arr()["content"][0]["content"][0]["text"])->toBe($articleText);
52+
expect($textField->getArr("content.0.content.0.text"))->toHaveCount(1);
53+
expect($textField->get("content.0.content.0.text"))->toBeString();
54+
55+
$textField->set("content.0.content.0.text", "Changing Text");
56+
expect($textField->arr()["content"][0]["content"][0]["text"])->toBe("Changing Text");
57+
expect($textField->getArr("content.0.content.0.text"))->toHaveCount(1);
58+
expect($textField->get("content.0.content.0.text"))->toBeString();
59+
60+
}
61+
);

0 commit comments

Comments
 (0)