Repository: codeigniter4/CodeIgniter4 (PHP)

Issue:
Bug: array_flatten_with_dots() loses emtpy arrays
### What happened?

I think the behavior of the ``array_flatten_with_dots`` function is not correct. If the value is an empty array, then the key-value pair is ignored and does not get into the resulting array, which in my opinion violates the integrity of the data.
The documentation also doesn't say that empty arrays are ignored.

### Steps to Reproduce

An example from tests. 
```php
$array = [
    'foo' => 'bar',
    'baz' => [],
    'bar' => [
        'fizz' => 'buzz',
        'nope' => 'yeah',
        'why'  => [],
    ],
];

array_flatten_with_dots($array);
// result 
//    [
//        'foo'      => 'bar',
//        'bar.fizz' => 'buzz',
//        'bar.nope' => 'yeah',
//    ]
```


### Expected Output

    [
        'foo'      => 'bar',
        'baz'      => [],
        'bar.fizz' => 'buzz',
        'bar.nope' => 'yeah',
        'bar.why'  => [],
    ]



Discussion:
>  If the value is an empty array, then the key-value pair is ignored and does not get into the resulting array, which in my opinion violates the integrity of the data.

It seems it depends on use cases.
Can you show a use case?

What would happen if the array that is ignored here was a numerically indexed array with content? Would it be treated as a value in total or would the numbers be used as dot-keys, too?

Because I think the current issue is that the subarray that is ignored here could as well be another level of dot-keys instead of being a preservable value, therefore it is skipped, as no keys are found in it.

Long story short: All levels of arrays are flattened, so an empty array is just interpreted as an empty key list and not as a value.
I think we need to choose one or the other.
1. This is by design, and document it. (Do not use if you need integrity.)
2. This is a bug, fix to get the integrity of the data.

I would go for documentation.
I can imagine adding a designated method `array_flatten_with_dots_fancy` or such which could take parameters as, e.g.

`int maxLevel = 0`, 
`bool emptyArrayAsValue = false`,
`bool keysFromAssociativeArraysOnly = false`.

The current Implementation would then be the default case of the method that allows for more specific flattening control.
@kenjis I discovered this behavior while trying to fix validation error messages for wildcard fields.
Using the ``array_flatten_with_dots`` function I was trying to get an array for further processing. But because the empty array is excluded from the set, the validation class tests fail.

https://github.com/codeigniter4/CodeIgniter4/blob/812af1e6285c352ae9b4da044fd7c1a0e8815d90/tests/system/Validation/ValidationTest.php#L1038-L1045

Instead of
```
['bar.0.foo' => 'baz', 'bar.1.foo' => []]
```
I get
```
['bar.0.foo' => 'baz']
```
The validation succeeds, but the test fails.
Therefore, I want to know. This is a design error of the helper or its normal behavior.
@sfadschm There is a problem with data integrity.
A dot array is an alternate representation of an existing array.
But if the empty array is excluded as a result of the conversion, then the original array from the dotted array can no longer be restored.
> @sfadschm There is a problem with data integrity. A dot array is an alternate representation of an existing array. But if the empty array is excluded as a result of the conversion, then the original array from the dotted array can no longer be restored.

Ok I think I see the problem now. If the method is intended to be reversible (to convert an array forth and back), this looks like a bug.

I found this Implementation which seems right to me to keep consistency:
https://github.com/adbario/php-dot-notation/blob/0a69aaabe706beebac848ef32587116b68875eea/src/Dot.php#L143-L173
Maybe @paulbalandan can clarify, he wrote the method.
I think this is a bug. My intention then was to convert a multidimensional array into a single dimensional one. Therefore, elements should be preserved. The reversibility idea hits me that current behavior is incorrect should we have an `array_explode_from_dots` function.
> array_explode_from_dots

That was my thought as well. Might actually make sense to implement that along with the bugfix, as it could be good for tests.
@iRedds Thank you for your clear example.
The consensus seems to be this is a bug.




Patch:
diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php
index c93acd5365a7..b5350cdd8b70 100644
--- a/system/Helpers/array_helper.php
+++ b/system/Helpers/array_helper.php
@@ -203,7 +203,7 @@ function array_flatten_with_dots(iterable $array, string $id = ''): array
         foreach ($array as $key => $value) {
             $newKey = $id . $key;
 
-            if (is_array($value)) {
+            if (is_array($value) && $value !== []) {
                 $flattened = array_merge($flattened, array_flatten_with_dots($value, $newKey . '.'));
             } else {
                 $flattened[$newKey] = $value;


Test patch:
diff --git a/tests/system/Helpers/ArrayHelperTest.php b/tests/system/Helpers/ArrayHelperTest.php
index 68941d670ce9..90413c570a00 100644
--- a/tests/system/Helpers/ArrayHelperTest.php
+++ b/tests/system/Helpers/ArrayHelperTest.php
@@ -391,11 +391,8 @@ public static function sortByMultipleKeysProvider()
 
     /**
      * @dataProvider arrayFlattenProvider
-     *
-     * @param iterable $input
-     * @param iterable $expected
      */
-    public function testArrayFlattening($input, $expected): void
+    public function testArrayFlattening(array $input, array $expected): void
     {
         $this->assertSame($expected, array_flatten_with_dots($input));
     }
@@ -452,24 +449,22 @@ public function arrayFlattenProvider(): iterable
             ],
             [
                 'foo'      => 'bar',
+                'baz'      => [],
                 'bar.fizz' => 'buzz',
                 'bar.nope' => 'yeah',
+                'bar.why'  => [],
             ],
         ];
 
-        yield 'with-mixed-empty' => [
+        yield 'with-empty-string-index' => [
             [
                 'foo' => 1,
                 ''    => [
                     'bar' => 2,
                     'baz' => 3,
                 ],
-                0 => [
-                    'fizz' => 4,
-                ],
-                1 => [
-                    'buzz' => 5,
-                ],
+                ['fizz' => 4],
+                ['buzz' => 5],
             ],
             [
                 'foo'    => 1,
@@ -479,5 +474,18 @@ public function arrayFlattenProvider(): iterable
                 '1.buzz' => 5,
             ],
         ];
+
+        yield 'empty-array-and-lists' => [
+            [
+                'bar' => [
+                    ['foo' => 'baz'],
+                    ['foo' => []],
+                ],
+            ],
+            [
+                'bar.0.foo' => 'baz',
+                'bar.1.foo' => [],
+            ],
+        ];
     }
 }