Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to flatten a multidimensional collection (array) to a dot notation version in a macro (Laravel)?

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 ....

});
like image 281
online Thomas Avatar asked Jan 28 '23 07:01

online Thomas


1 Answers

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.

like image 139
Troyer Avatar answered Feb 05 '23 16:02

Troyer