Skip to content

Commit

Permalink
Set nested values (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
SmetDenis authored Sep 2, 2023
1 parent 718c1df commit f08f881
Show file tree
Hide file tree
Showing 5 changed files with 410 additions and 61 deletions.
85 changes: 51 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,57 @@ composer require jbzoo/data

### Comparison with pure PHP

Action | JBZoo/Data | Simple PHP Array
--------------------- | ------------------------------------------------- | --------------------------------------------
Create | `$d = data($someData)` | `$ar = [/* ... */];`
Supported formats | Array, Object, ArrayObject, JSON, INI, Yml | Array
Load form file | *.php, *.ini, *.yml, *.json, serialized | -
Get value or default | `$d->get('key', 42)` | `array_key_exists('k', $ar) ? $ar['k'] : 42`
Get undefined #1 | `$d->get('undefined')` (no any notice) | `$ar['undefined'] ?? null`
Get undefined #2 | `$d->find('undefined')` | `$ar['und'] ?? null`
Get undefined #3 | `$d->undefined === null` (no any notice) | -
Get undefined #4 | `$d['undefined'] === null` (no any notice) | -
Get undefined #5 | `$d['undef']['undef'] === null` (no any notice) | -
Comparing #1 | `$d->get('key') === $someVar` | `$ar['key'] === $someVar`
Comparing #2 | `$d->is('key', $someVar)` | -
Comparing #3 | `$d->is('key', $someVar, true)` (strict) | -
Like array | `$d['key']` | `$ar['key']`
Like object #1 | `$d->key` | -
Like object #2 | `$d->get('key')` | -
Like object #3 | `$d->find('key')` | -
Like object #4 | `$d->offsetGet('key')` | -
Isset #1 | `isset($d['key'])` | `isset($ar['key'])`
Isset #2 | `isset($d->key)` | `array_key_exists('key', $ar)`
Isset #3 | `$d->has('key')` | -
Nested key #1 | `$d->find('inner.inner.prop', $default)` | `$ar['inner']['inner']['prop']` (error?)
Nested key #2 | `$d->inner['inner']['prop']` | -
Nested key #3 | `$d['inner']['inner']['prop']` | -
Export to Serialized | `echo (new Data([/* ... */]))` | `echo serialize([/* ... */])`
Export to JSON | `echo (new JSON([/* ... */]))` (readable) | `echo json_encode([/* ... */])`
Export to Yml | `echo (new Yml ([/* ... */]))` (readable) | -
Export to Ini | `echo (new Ini([/* ... */]))` (readable) | -
Export to PHP Code | `echo (new PHPArray ([/* ... */]))` (readable) | -
JSON | **+** | -
Filters | **+** | -
Search | **+** | -
Flatten Recursive | **+** | -
--------------------------------------------------------------------------------
| Action | JBZoo/Data | Pure PHP way |
|:-------------------------------------|:------------------------------------------------|:-----------------------------------------|
| Create | `$d = data($someData)` | `$ar = [/* ... */];` |
| Supported formats | Array, Object, ArrayObject, JSON, INI, Yml | Array |
| Load form file | *.php, *.ini, *.yml, *.json, serialized | - |
| Get value or default | `$d->get('key', 42)` | `$ar['key'] ?? 42` |
| Get undefined #1 | `$d->get('undefined')` (no any notice) | `$ar['undefined'] ?? null` |
| Get undefined #2 | `$d->find('undefined')` | `$ar['und'] ?? null` |
| Get undefined #3 | `$d->undefined === null` (no any notice) | - |
| Get undefined #4 | `$d['undefined'] === null` (no any notice) | - |
| Get undefined #5 | `$d['undef']['undef'] === null` (no any notice) | - |
| Comparing #1 | `$d->get('key') === $someVar` | `$ar['key'] === $someVar` |
| Comparing #2 | `$d->is('key', $someVar)` | - |
| Comparing #3 | `$d->is('key', $someVar, true)` (strict) | - |
| Like array | `$d['key']` | `$ar['key']` |
| Like object #1 | `$d->key` | - |
| Like object #2 | `$d->get('key')` | - |
| Like object #3 | `$d->find('key')` | - |
| Like object #4 | `$d->offsetGet('key')` | - |
| Isset #1 | `isset($d['key'])` | `isset($ar['key'])` |
| Isset #2 | `isset($d->key)` | `array_key_exists('key', $ar)` |
| Isset #3 | `$d->has('key')` | - |
| Nested key #1 | `$d->find('inner.inner.prop', $default)` | `$ar['inner']['inner']['prop']` (error?) |
| Nested key #2 | `$d->inner['inner']['prop']` | - |
| Nested key #3 | `$d['inner']['inner']['prop']` | - |
| Export to Serialized | `echo data([/* ... */])` | `echo serialize([/* ... */])` |
| Export to JSON | `echo (json([/* ... */]))` (readable) | `echo json_encode([/* ... */])` |
| Export to Yml | `echo yml([/* ... */])` (readable) | - |
| Export to Ini | `echo ini([/* ... */])` (readable) | - |
| Export to PHP Code | `echo phpArray([/* ... */])` (readable) | - |
| JSON | **+** | - |
| Filters | **+** | - |
| Search | **+** | - |
| Flatten Recursive | **+** | - |
| Set Value | `$d['value'] = 42` | $ar['value'] = 42 |
| Set Nested Value | `$d->set('q.w.e.r.t.y') = 42` | $ar['q']['w']['e']['r']['t']['y'] = 42 |
| Set Nested Value (if it's undefined) | `$d->set('q.w.e.r.t.y') = 42` | PHP Notice errors... |


### Know your data

```php
$json = json('{ "some": "thing", "number": 42 }');
dump($json->getSchema();
// [
// "some" => "string",
// "number" => "int"
// ]

```


#### Methods
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

"require-dev" : {
"jbzoo/toolbox-dev" : "^7.0",
"jbzoo/utils" : "^7.0",
"jbzoo/utils" : "^7.1.1",
"symfony/yaml" : ">=4.4",

"symfony/polyfill-ctype" : ">=1.27.0",
Expand Down
42 changes: 37 additions & 5 deletions src/AbstractData.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace JBZoo\Data;

use JBZoo\Utils\Arr;
use JBZoo\Utils\Filter;

/**
Expand Down Expand Up @@ -98,14 +99,25 @@ public function get(string $key, mixed $default = null, mixed $filter = null): m

/**
* Set a value in the data.
* @param string $name The key used to set the value
* @param mixed $value The value to set
* @param string $pathKey The key used to set the value
* @param mixed $value The value to set
* @param string $separator The separator to use when searching for sub keys. Default is '.'
*
* @psalm-suppress UnsafeInstantiation
*/
public function set(string $name, mixed $value): static
public function set(string $pathKey, mixed $value, string $separator = '.'): self
{
$this->offsetSet($name, $value);
if (\str_contains($pathKey, $separator) && $separator !== '') {
$keys = \explode($separator, $pathKey);
} else {
$keys = [$pathKey];
}

return $this;
$arrayCopy = $this->getArrayCopy();
self::setNestedValue($arrayCopy, $keys, $value);

// @phpstan-ignore-next-line
return new static($arrayCopy);
}

/**
Expand Down Expand Up @@ -254,6 +266,11 @@ public function is(string $key, mixed $compareWith = true, bool $strictMode = fa
return $value == $compareWith;
}

public function getSchema(): array
{
return Arr::getSchema($this->getArrayCopy());
}

/**
* Filter value before return.
*/
Expand Down Expand Up @@ -288,6 +305,21 @@ protected static function isMulti(array $array): bool
return \count($arrayCount) > 0;
}

private static function setNestedValue(array &$array, array $keys, mixed $value): void
{
$key = \array_shift($keys);

if (\count($keys) === 0) {
$array[$key] = $value;
} else {
if (!isset($array[$key]) || !\is_array($array[$key])) {
$array[$key] = [];
}

self::setNestedValue($array[$key], $keys, $value);
}
}

private static function checkDeprecatedFilter(string $prefix, mixed $filter): void
{
if (!\is_string($filter)) {
Expand Down
190 changes: 190 additions & 0 deletions tests/DataPackageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

namespace JBZoo\PHPUnit;

use JBZoo\Markdown\Table;

final class DataPackageTest extends \JBZoo\Codestyle\PHPUnit\AbstractPackageTest
{
protected string $packageName = 'Data';
Expand All @@ -25,4 +27,192 @@ protected function setUp(): void
parent::setUp();
$this->excludedPathsForCopyrights[] = 'resource';
}

public function testComparativetablelInReadme(): void
{
$rows = [
[
'Create',
'`$d = data($someData)`',
'`$ar = [/* ... */];`',
],
[
'Supported formats',
'Array, Object, ArrayObject, JSON, INI, Yml',
'Array',
],
[
'Load form file',
'*.php, *.ini, *.yml, *.json, serialized',
'-',
],
[
'Get value or default',
"`\$d->get('key', 42)`",
"`\$ar['key'] ?? 42`",
],
[
'Get undefined #1',
"`\$d->get('undefined')` (no any notice)",
"`\$ar['undefined'] ?? null`",
],
[
'Get undefined #2',
'`$d->find(\'undefined\')`',
'`$ar[\'und\'] ?? null`',
],
[
'Get undefined #3',
'`$d->undefined === null` (no any notice)',
'-',
],
[
'Get undefined #4',
"`\$d['undefined'] === null` (no any notice)",
'-',
],
[
'Get undefined #5',
"`\$d['undef']['undef'] === null` (no any notice)",
'-',
],
[
'Comparing #1',
"`\$d->get('key') === \$someVar`",
'`$ar[\'key\'] === $someVar`',
],
[
'Comparing #2',
"`\$d->is('key', \$someVar)`",
'-',
],
[
'Comparing #3',
"`\$d->is('key', \$someVar, true)` (strict)",
'-',
],
[
'Like array',
"`\$d['key']`",
"`\$ar['key']`",
],
[
'Like object #1',
'`$d->key`',
'-',
],
[
'Like object #2',
"`\$d->get('key')`",
'-',
],
[
'Like object #3',
"`\$d->find('key')`",
'-',
],
[
'Like object #4',
'`$d->offsetGet(\'key\')`',
'-',
],
[
'Isset #1',
"`isset(\$d['key'])`",
"`isset(\$ar['key'])`",
],
[
'Isset #2',
'`isset($d->key)`',
"`array_key_exists('key', \$ar)`",
],
[
'Isset #3',
"`\$d->has('key')`",
'-',
],
[
'Nested key #1',
'`$d->find(\'inner.inner.prop\', $default)`',
"`\$ar['inner']['inner']['prop']` (error?)",
],
[
'Nested key #2',
"`\$d->inner['inner']['prop']`",
'-',
],
[
'Nested key #3',
"`\$d['inner']['inner']['prop']`",
'-',
],
[
'Export to Serialized',
'`echo data([/* ... */])`',
'`echo serialize([/* ... */])`',
],
[
'Export to JSON',
'`echo (json([/* ... */]))` (readable)',
'`echo json_encode([/* ... */])`',
],
[
'Export to Yml',
'`echo yml([/* ... */])` (readable)',
'-',
],
[
'Export to Ini',
'`echo ini([/* ... */])` (readable)',
'-',
],
[
'Export to PHP Code',
'`echo phpArray([/* ... */])` (readable)',
'-',
],
[
'JSON',
'**+**',
'-',
],
[
'Filters',
'**+**',
'-',
],
[
'Search',
'**+**',
'-',
],
[
'Flatten Recursive',
'**+**',
'-',
],
[
'Set Value',
"`\$d['value'] = 42`",
"\$ar['value'] = 42",
],
[
'Set Nested Value',
"`\$d->set('q.w.e.r.t.y') = 42`",
"\$ar['q']['w']['e']['r']['t']['y'] = 42",
],
[
"Set Nested Value (if it's undefined)",
"`\$d->set('q.w.e.r.t.y') = 42`",
'PHP Notice errors...',
],
];

$table = (new Table())
->setHeaders(['Action', 'JBZoo/Data', 'Pure PHP way'])
->setAlignments([Table::ALIGN_LEFT, Table::ALIGN_LEFT, Table::ALIGN_LEFT])
->appendRows($rows);

isFileContains($table->render(), PROJECT_ROOT . '/README.md');
}
}
Loading

0 comments on commit f08f881

Please sign in to comment.