Okay, this is how it works, you were actually not too far off as you started, but what you actually look for are references. This is a general procedure:
As there is a relation between parent and child-nodes on their ID, you first need to index the data based on the ID. I do this here with an array ($rows
) to simulate your data access, if you read from the database, it would be similar. With this indexing you can also add additional properties like your empty data:
// create an index on id
$index = array();
foreach($rows as $row)
{
$row['data'] = (object) array();
$index[$row['id']] = $row;
}
So now all entries are indexed on their ID. This was the first step.
The second step is equally straight forward. Because we now can access each node based on it's ID in the $index
, we can assign the children to their parent.
There is one "virtual" node, that is the one with the ID 0. It does not exists in any of the rows, however, if we could add children to it too, we can use this children collection as the store for all root nodes, in your case, there is a single root node.
Sure, for the ID 0
, we should not process the parent - because it does not exists.
So let's do that. We make use of references here because otherwise the same node could not be both parent and child:
// build the tree
foreach($index as $id => &$row)
{
if ($id === 0) continue;
$parent = $row['parent'];
$index[$parent]['children'][] = &$row;
}
unset($row);
Because we use references, the last line takes care to unset the reference stored in $row
after the loop.
Now all children have been assigned to their parents. That could it be already, however lets not forget the last step, the actual node for the output should be accessed.
For brevity, just assign the root node to the $index
itself. If we remember, the only root node we want is the first one in the children array in the node with the ID 0
:
// obtain root node
$index = $index[0]['children'][0];
And that's it. We can use it now straight away to generate the JSON:
// output json
header('Content-Type: application/json');
echo json_encode($index);
Finally the whole code at a glance:
<?php
/**
* @link http://stackoverflow.com/questions/11239652/php-create-a-multidimensional-array-from-an-array-with-relational-data
*/
$rows = array(
array('id' => 5273, 'parent' => 0, 'name' => 'John Doe'),
array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),
array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),
array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),
array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),
array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),
array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),
);
// create an index on id
$index = array();
foreach($rows as $row)
{
$row['data'] = (object) [];
$index[$row['id']] = $row;
}
// build the tree
foreach($index as $id => &$row)
{
if ($id === 0) continue;
$parent = $row['parent'];
$index[$parent]['children'][] = &$row;
}
unset($row);
// obtain root node
$index = $index[0]['children'][0];
// output json
header('Content-Type: application/json');
echo json_encode($index, JSON_PRETTY_PRINT);
Which would create the following json (here with PHP 5.4s' JSON_PRETTY_PRINT
):
{
"id": 5273,
"parent": 0,
"name": "John Doe",
"data": {
},
"children": [
{
"id": 6032,
"parent": 5273,
"name": "Sally Smith",
"data": {
},
"children": [
{
"id": 6034,
"parent": 6032,
"name": "Mike Jones",
"data": {
},
"children": [
{
"id": 6035,
"parent": 6034,
"name": "Jason Williams",
"data": {
}
}
]
}
]
},
{
"id": 6036,
"parent": 5273,
"name": "Sara Johnson",
"data": {
}
},
{
"id": 6037,
"parent": 5273,
"name": "Dave Wilson",
"data": {
},
"children": [
{
"id": 6038,
"parent": 6037,
"name": "Amy Martin",
"data": {
}
}
]
}
]
}