5

Example input as json

{
   "user":{
      "name":"Thomas",
      "age":101
   },
   "shoppingcart":{
      "products":{
         "p1":"someprod",
         "p2":"someprod2"
      },
      "valuta":"eur",
      "coupon":null,
      "something":[
         "bla1",
         "bla2"
      ]
   }
}

Expected output

[
    'user.name' => 'Thomas',
    'user.age' => 101,
    'shoppingcart.products.p1' => 'someprod',
    ...
    'shoppingcart.something.1' => 'bla1'
]

I have written this function however it produces the wrong output. Next to that, I would like to rewrite said function to a macro for Collection but I cannot wrap my head around it. The problem is also that the current function as is requires a global var to keep track of the result.

public function dotFlattenArray($array, $currentKeyArray = []) {

        foreach ($array as $key => $value) {
            $explodedKey = preg_split('/[^a-zA-Z]/', $key);
            $currentKeyArray[] = end($explodedKey);
            if (is_array($value)) {
                $this->dotFlattenArray($value, $currentKeyArray);
            } else {
                $resultArray[implode('.', $currentKeyArray)] = $value;
                array_pop($currentKeyArray);
            }
        }
        $this->resultArray += $resultArray;
    }

So my problem is twofold: 1. Sometimes the function does not give the right result 2. How can I rewrite this recursive function to a macro

Collection::macro('dotflatten', function () {
    return ....

});
Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109
online Thomas
  • 8,864
  • 6
  • 44
  • 85

1 Answers1

8

The thing you are trying to do is called transform an multidimensional array to array with dot notation.

You don't need to reinvent the wheel, Laravel have already a helper for it, called array_dot().

The array_dot function flattens a multi-dimensional array into a single level array that uses "dot" notation to indicate depth:

$array = ['products' => ['desk' => ['price' => 100]]];

$flattened = array_dot($array);

// ['products.desk.price' => 100]

You only need to transform your json to array with json_decode() and then flat it with array_dot() to get an array with dot notation.

Troyer
  • 6,765
  • 3
  • 34
  • 62
  • Is there a way to pass a `depth` value as for the Collection `flatten()` method? In my use case my multidimensional array as a constant depth, but i need to flatten in to the second to last level – fudo Dec 14 '20 at 15:01
  • Also available as the `Arr::dot()` helper. – Jason Dec 07 '22 at 11:39