3

I have php array structure like this:

array(
    'servicemanagement.scheduler.events.edit' => 'Edit',
    'servicemanagement.scheduler.events.delete' => 'Delete',
    'servicemanagement.scheduler.events' => 'Events',
    'servicemanagement.scheduler' => 'Scheduler',
    'servicemanagement.subscribers' => 'Subscribers',
    'servicemanagement.subscribers.index' => 'Index',
    'servicemanagement' => 'Service management',
);

And I would like to convert is to multidimensional array like:

array(
    'servicemanagement' => array(
        'id' => 'servicemanagement',
        'title' => 'Service Management',
        'children' => array(
            'scheduler' => array(
                'id' => 'servicemanagement.scheduler',
                'title' => 'Scheduler',
                'children' => array(
                    'events' => array(
                        'id' => 'servicemanagement.scheduler.events',
                        'title' => 'Events',
                        'children' => array(
                            'edit' => array(
                                'id' => 'servicemanagement.scheduler.events.edit',
                                'title' => 'Edit',
                                'children' => array(),
                            ),
                            'delete' => array(
                                'id' => 'servicemanagement.scheduler.events.delete',
                                'title' => 'Delete',
                                'children' => array(),
                            ),
                        ),
                    ),
                ),
            ),
            'subscribers' => array(
                'id' => 'servicemanagement.subscribers',
                'title' => 'Subscribers',
                'children' => array(
                    'index' => array(
                        'id' => 'servicemanagement.subscribers.index',
                        'title' => 'Index',
                    )
                ),
            ),
        ),
    ),
);

I have checked some answers already like this one: How to set a deep array in PHP

But it seems that i could not manage to clear up the writing on top of the arrays and the last record 'servicemanagement' removes all of the previous records.

The function that is used there is

function setArray(&$array, $keys, $value) {
    $keys = explode(".", $keys);
    $current = &$array;
    foreach($keys as $key) {
        $current = &$current[$key];
    }
    $current = $value;
}

Another function that I have found but it is not doing the expected result is:

function unflatten($array,$prefix = '')
{
    $result = array();
    foreach($array as $key=>$value)    {
        if (!empty($prefix)) {
            $key = preg_replace('#^'.preg_quote($prefix).'#','',$key);
        }
        if (strpos($key,'.') !== false) {
            parse_str('result['.str_replace('.','][',$key)."]=".$value);
        } else {
            $result[$key] = $value;
        }
    }
    return $result;
}

It is an option to use recursion to unflatten this array since the end format is the same for all records.

May anyone give me a tip ot this one?

Machavity
  • 30,841
  • 27
  • 92
  • 100
kachar
  • 2,310
  • 30
  • 32

2 Answers2

5

I created an unflatten function for reference here:

https://gist.github.com/Gerst20051/b14c05b72c73b49bc2d306e7c8b86223

$results = [
  'id' => 'abc123',
  'address.id' => 'def456',
  'address.coordinates.lat' => '12.345',
  'address.coordinates.lng' => '67.89',
  'address.coordinates.geo.accurate' => true,
];

function unflatten($data) {
  $output = [];
  foreach ($data as $key => $value) {
    $parts = explode('.', $key);
    $nested = &$output;
    while (count($parts) > 1) {
      $nested = &$nested[array_shift($parts)];
      if (!is_array($nested)) $nested = [];
    }
    $nested[array_shift($parts)] = $value;
  }
  return $output;
}

echo json_encode(unflatten($results));

/*
{
  "id": "abc123",
  "address": {
    "id": "def456",
    "coordinates": {
      "lat": "12.345",
      "lng": "67.89",
      "geo": {
        "accurate": true
      }
    }
  }
}
*/

This was slightly influenced by the following resources:

Andrew
  • 3,733
  • 1
  • 35
  • 36
2

This isn't the cleanest solution but it works as a single function

    $your_array = array(
        'servicemanagement.scheduler.events.edit' => 'Edit',
        'servicemanagement.scheduler.events.delete' => 'Delete',
        'servicemanagement.scheduler.events' => 'Events',
        'servicemanagement.scheduler' => 'Scheduler',
        'servicemanagement.subscribers' => 'Subscribers',
        'servicemanagement.subscribers.index' => 'Index',
        'servicemanagement' => 'Service management',
    );

    function expand($array, $level = 0)
    {
        $result = array();
        $next = $level + 1;

        foreach($array as $key=>$value) {
            $tree = explode('.', $key);
            if(isset($tree[$level])) {
                if(!isset($tree[$next])) {
                    $result[$tree[$level]]['id'] =  $key;
                    $result[$tree[$level]]['title'] = $value;
                    if(!isset($result[$tree[$level]]['children'])) {
                        $result[$tree[$level]]['children'] = array();
                    }
                } else {
                    if(isset($result[$tree[$level]]['children'])) {
                        $result[$tree[$level]]['children'] = array_merge_recursive($result[$tree[$level]]['children'], expand(array($key => $value), $next));
                    } else {
                        $result[$tree[$level]]['children'] = expand(array($key => $value), $next);
                    }
                }

            }
        }

        return $result;

    }
   var_export(expand($your_array));
Mike
  • 1,791
  • 13
  • 13
  • It is good enough and it does the job. We can replace `$result[$tree[$level]]['id'] = implode('.',array_slice($tree, 0, $next));` with `$result[$tree[$level]]['id'] = $key;` – kachar Jun 28 '13 at 14:16
  • I just changed the answer to suit this as it removes unnecessary logic. – Mike Jun 28 '13 at 14:27