I've seen lots of similar question on here, but I haven't been able to get my desired output. Could someone please help me out? How can generate the following JSON structure? My query is fine, I just can't figure out how to loop through and get this. Thanks
DESIRED OUTPUT
{
"players": [
{
"id": 271,
"fname": "Carlos",
"lname": "Beltran",
"position": "OF",
"stats": [
{
"year": "2010",
"hr": 32,
"rbi": 99,
"team": "NYM"
},
{
"year": "2011",
"hr": 35,
"rbi": 100,
"team": "STL"
},
{
............
}
]
},
{
........
}
]
}
CURRENT OUTPUT
{"0":{"cbs_id":"18817","fname":"Carlos","lname":"Beltran"},"stats":[{"year":"2007","hr":"33","rbi":"112"}]}
{"0":{"cbs_id":"174661","fname":"Willie","lname":"Bloomquist"},"stats":[{"year":"2007","hr":"2","rbi":"13"}]}
{"0":{"cbs_id":"1208693","fname":"Brennan","lname":"Boesch"},"stats":[{"year":"2010","hr":"14","rbi":"67"}]}
Which is generated with: (I know I'm way off)
if ($result = mysqli_query($link, $sql)) {
$player = array();
while ($row = $result->fetch_assoc())
{
$player[] = array (
'cbs_id' => $row['cbs_id'],
'fname' => $row['fname'],
'lname' => $row['lname']
);
$player['stats'][] = array(
'year' => $row['year'],
'hr' => $row['hr'],
'rbi' => $row['rbi']
);
}
$json = json_encode($player);
echo "<pre>$json</pre>";
mysqli_free_result($result);
}
}
NOTE: Each player can have more than one "stats" record (year, hr, rbi, etc)
This may give what you want:
$players = array();
while ($row = $result->fetch_assoc())
{
$id = (int)$row['cbs_id'];
if ( ! isset($players[$id]))
{
// New player, add to $players array.
// For the moment index players by ID so stats can be easily added
// to an existing player. Without indexing (using $players[] = ...),
// the same player would be added for each stats record related to
// him.
$players[$id] = array(
'id' => $id,
'fname' => $row['fname'],
'lname' => $row['lname'],
'stats' => array()
);
}
// Add the stats
$players[$id]['stats'][] = array(
'year' => (int)$row['year'],
'hr' => (int)$row['hr'],
'rbi' => (int)$row['rbi']
);
}
// Players are indexed by their ID in $players but need to be contained in
// a JSON array, so use array_values() to remove indices, e.g. convert
//
// array(
// 271 => array('id' => 271, ...),
// ...
// )
//
// to
//
// array(
// array('id' => 271, ...),
// ...
// )
//
$data = array('players' => array_values($players));
$json = json_encode($data);
Eventually you might leave out the integer casts and let PHP automatically convert stringified numeric data (that's the default behaviour with MySQL query results) back to PHP numbers by using the MYSQLI_OPT_INT_AND_FLOAT_NATIVE mysqli connection option as described in example #5 of this page. Note that it requires the mysqlnd library to be used by PHP (you can check that with phpinfo).
You need an associative array. Something like this should get you started:
$data = array(
'players' => array(
array(
'id' => 271,
'fname': 'Carlos',
'lname': 'Beltran',
'position': 'OF',
'stats' => array(
array(
'year' => 2010,
'hr': 32,
'rbi': 99,
'team': 'NYM'
),
...
)
),
...
)
);
To encode it into json, use json_encode:
$json = json_encode($data);
Related
I'm currently developing this code that traverse a hierarchical array which should compute the sub-total of a property called cur_compensation. My issue is that the changes I do is not getting save
private function computeSubTotal($hierarchy){
foreach($hierarchy["_children"] as $key => $value){
if(isset($value["_children"]))
{
static::computeSubTotal($value);
}
else{
foreach($hierarchy["_children"] as $employee){
$employee_cur_compensation = $employee["cur_compensation"] ?? 0;
if (!isset($hierarchy["cur_compensation"])) {
$hierarchy["cur_compensation"] = 0;
}
$hierarchy["cur_compensation"] += $employee_cur_compensation;
}
return $hierarchy;
}
}
return $hierarchy;
}
This is the function so what it does it goes to the deepest node, the deepest node is a value that does not have any _children which mean it doesn't have any sub department (the hierarchy is sorted that the sub department are always on top)
The issue I have, once it reaches the bottom it computes the cur_compensation by looping through the employees of that department and adding it on the department "cur_compensation" property.
The issue is that, it doesn't save any of my changes.
So the purpose of the function is to add up the 'cur_compensation' of each employee/sub-department.
For example ->
$rows = array(
array(
'name' => "Main",
'id' => 1,
'parent_id' => 0,
'cur_compensation' => 0,
'_children' => array(
array(
'name' => "Dept A",
'id' => 2,
'parent_id' => 1),
),
array(
'name' => "Dept B",
'id' => 3,
'parent_id' => 1,
'_children' => array(
array(
'name' => "Dept C",
'cur_compensation' => 30000,
'id' => 4,
'parent_id' => 3),
array(
'name' => "Employee C",
'cur_compensation' => 30000,
'id' => 7,
'parent_id' => 3
)
)),
array(
'name' => "Employee A",
'cur_compensation' => 20000,
'id' => 5,
'parent_id' => 1
),
array(
'name' => "Employee B",
'cur_compensation' => 30000,
'id' => 6,
'parent_id' => 1
)
)
)
);
The result I want to get would be:
$rows = array(
array(
'name' => "Main",
'id' => 1,
'parent_id' => 0,
'cur_compensation' => 120000,
'_children' => array(
array(
'name' => "Dept A",
'id' => 2,
'cur_compensation' => 0,
'parent_id' => 1),
),
array(
'name' => "Dept B",
'id' => 3,
'parent_id' => 1,
'cur_compensation' => 60000,
'_children' => array(
array(
'name' => "Dept C",
'cur_compensation' => 30000,
'id' => 4,
'parent_id' => 3),
array(
'name' => "Employee C",
'cur_compensation' => 30000,
'id' => 7,
'parent_id' => 3
)
)),
array(
'name' => "Employee A",
'cur_compensation' => 30000,
'id' => 5,
'parent_id' => 1
),
array(
'name' => "Employee B",
'cur_compensation' => 30000,
'id' => 6,
'parent_id' => 1
)
)
)
);
So you would notice that Main and Dept B got the cur_compensation based on the _children property
There's a few things to make note on here - so I'm going to add comments to your existing code, then provide an example of how you could change it.
(I've formatted the code in each case)
class Example {
// filler code so that we can call
public function process($array){
return $this->computeSubTotal($array);
}
private function computeSubTotal($hierarchy) {
// we're not checking whether "_children" property exists before looping on it
foreach ($hierarchy["_children"] as $key => $value) {
if (isset($value["_children"])) {
// we're calling the method, but not doing anything with the return value.
static::computeSubTotal($value);
// we can set the original array value instead which will provide a modified copy
// this can be resolved by uncommenting the line below
// $hierarchy["_children"][$key] = static::computeSubTotal($value);
// also note that if this "child" doesn't have any *grand*children
// then we won't get an updated value due to how this is structured
// to fix this, you could remove the else wrapping so that the code
// below runs always
} else {
// double looping - we're already looping this array
// this will cause the end value to increase exponentially
foreach ($hierarchy["_children"] as $employee) {
$employee_cur_compensation = $employee["cur_compensation"] ?? 0;
if (!isset($hierarchy["cur_compensation"])) {
$hierarchy["cur_compensation"] = 0;
}
$hierarchy["cur_compensation"] += $employee_cur_compensation;
}
// returning whole array inside the loop is not ideal
// we have already adjusted the main array
// comment out this return to prevent that from happening
return $hierarchy;
}
}
return $hierarchy;
}
}
$example = new Example;
// calling this on $rows won't give us anything back
// since $rows doesn't contain the property "_children"
$rows = $example->process($rows);
// in this case, you would want to process each array result
// only on this primary array
foreach($rows as $index => $value){
$rows[$index] = $example->process($value);
}
echo json_encode($rows, JSON_PRETTY_PRINT);
Taking those comments into account, you would end up with something like this:
private function computeSubTotal($hierarchy) {
// we're not checking whether "_children" property exists before looping on it
foreach ($hierarchy["_children"] as $key => $value) {
if (isset($value["_children"])) {
$hierarchy["_children"][$key] = static::computeSubTotal($value);
}
// double looping - we're already looping this array
// this will cause the end value to increase exponentially
foreach ($hierarchy["_children"] as $employee) {
$employee_cur_compensation = $employee["cur_compensation"] ?? 0;
if (!isset($hierarchy["cur_compensation"])) {
$hierarchy["cur_compensation"] = 0;
}
$hierarchy["cur_compensation"] += $employee_cur_compensation;
}
}
return $hierarchy;
}
That's closer but still, it's not quite correct due to the double looping.
I've made a simpler version that is hopefully easy to follow:
private function computeSubTotal($hierarchy) {
if (!isset($hierarchy["_children"])) {
return $hierarchy;
}
// define this outside the loop for clarity
if (!isset($hierarchy["cur_compensation"])) {
$hierarchy["cur_compensation"] = 0;
}
foreach ($hierarchy["_children"] as $key => $value) {
// don't need to check for "_children" property
// as it's now handled in this function
$updated = static::computeSubTotal($value);
// reference the $updated array to increment
// the "cur_compensation" field
$hierarchy["cur_compensation"] += $updated["cur_compensation"] ?? 0;
// update original array
$hierarchy["_children"][$key] = $updated;
}
return $hierarchy;
}
// call like
foreach ($rows as $index => $value) {
$rows[$index] = static::computeSubTotal($value);
}
You will still need to change how you're passing the $rows variable due to it now containing a "_children" property (as shown in the examples) - either pass each element or add additional logic in that function to handle that.
You need to pass the array as a reference.
https://www.php.net/manual/en/language.references.pass.php
PHP passes the array to the function as a pointer, but when you try to update the array, PHP first makes a full copy of the array and updates the copy instead of the original.
Change your function signature to the following and it should be good.
private function computeSubTotal(&$hierarchy){
P.S. You are calling computeSubTotal statically, but the function is not static itself.
im currently trying to update an array with values from another one.
Basically there is a form where you can update data for an object, the form sends a json array like so:
{
"name": "Test2",
"address": "Adresas 2",
"object_id": "44",
"job_id": [
"31",
"33"
],
"amount": [
"500",
"500"
]
}
My goal is to update another array that is being fetched from the database with values of job_idd and amount.
The array from database looks like so:
{
"jobs": [
{
"id": "31",
"amount": "500",
"have": 250
},
{
"id": "33",
"amount": "500",
"have": 0
}
]
}
I need to update the second array values "amount" with the posted values from the first array "amount", but so that the second array still has the original "have" values
I tried using nested foreach method:
$object_id = $_POST['object_id'];
$data = json_encode($_POST);
$json = json_decode($data, true);
$i = 0;
foreach($json['job_id'] as $item) {
$job_id = $item;
$query33 = "SELECT * FROM `objektai` WHERE id='$object_id'";
$result33 = mysqli_query($conn, $query33) or die(mysqli_error($conn));
while($row2 = mysqli_fetch_array($result33)){
$job_info = $row2['info'];
}
$json_22 = json_decode($job_info, true);
foreach ($json_22['jobs'] as $key2 => $entry2) {
$have = $json_22['jobs'][$key2]['have'];
}
$result["jobs"][] = array(
'id' => $job_id,
'kiekis' => $json['amount'][$i],
'turima' => $have,
);
$i++;
}
Usinng the example above the foreach prints the values 2 times and my updated json "have"
has a value of 0, the "amount" entries are updated correctly
Thanks in advance for you help!
UPDATE
adding var_export($_POST):
array ( 'name' => 'Test2',
'address' => 'Adresas 2',
'object_id' => '44',
'job_idd' => array (
0 => '31',
1 => '33',
),
'darbo_kiekis' => array (
0 => '500',
1 => '500',
),
)
When you're looping through the array from the database, you need to compare the id value with $obj_id.
I've also shown below how to use a prepared statement to prevent SQL injection.
I've removed lots of unnecessary code:
No need to convert $_POST to/from JSON.
Use $i => in the foreach loop to get the array index.
You don't need a while loop when processing the query results if it only returns one row.
You don't need $key2, you can just use $entry2.
$object_id = $_POST['object_id'];
$query33 = "SELECT * FROM `objektai` WHERE id = ?";
$stmt33 = $conn->prepare($query33);
$stmt33->bind_param('i', $job_id);
foreach($_POST['job_id'] as $i => $job_id) {
$stmt33->execute();
$result33 = $stmt33->get_result();
$row2 = $result33->fetch_assoc();
$job_info = $row2['info'];
$json_22 = json_decode($job_info, true);
foreach ($json_22['jobs'] as $entry2) {
if ($entry2['id'] == $job_id) {
$result["jobs"][] = array(
'id' => $job_id,
'kiekis' => $json['amount'][$i],
'turima' => $entry2['have']
);
}
}
}
I am new to API I used Codeigniter to create an APi from a MySql Databse Products which have
the field : Amount , quantity, customerName, CustomerPhone, CustomerAddress
the rsult looks:
```[
{
"Id": "1",
"Amount": "21542",
"quantity": "52",
"customerName": "John",
"CustomerPhone": "254215",
"CustomerAddress": "road tvz120",
},```
but i want it to look this way:
```[
{
"Id": "1",
"Amount": "21542",
"quantity": "52",
"customerInfo":{
"customerName": "John",
"CustomerPhone": "254215",
"CustomerAddress": "rue tvz120"},
},```
I mean to group the 3 field concernign customers with the name customer info
my php code is
```public function index_get($id = 0)
{
if(!empty($id)){
$data = $this->db->get_where("Products", ['Id' => $id])->row_array();
}else{
$data = $this->db->get("Products")->result();
}
$this->response($data, REST_Controller::HTTP_OK);
}```
Your Products format is based on database, therefore if you want to change the result format, you have to construct it manually. You need to loop the result before returning the data.
if(!empty($id)){
$data = $this->db->get_where("Products", ['Id' => $id])->row_array();
}else{
$data = $this->db->get("Products")->result();
$newdata = array();
foreach($data as $row)
{
$newdata[] = array(
"Id" => $row->id,
"Amount" => $row->amount,
"quantity" => $row->quantity,
"customerInfo" => array(
"customerName" => $row->customerName,
"CustomerPhone" => $row->CustomerPhone,
"CustomerAddress" => $row->CustomerAddress,
)
);
}
$data = $newdata;
}
$this->response($data, REST_Controller::HTTP_OK);
You cannot perform this via query, you'll have to loop through the result and change it to the desired format, like so -
if(!empty($id)){
$result = $this->db->get_where("Products", ['Id' => $id])->result();
// I'll advise to use result() here instead of row_array() so that you don't face any issue when there's only one row.
}else{
$result = $this->db->get("Products")->result();
}
foreach($result as $res){
$new_result[] = array(
"Id" => $res->Id,
"Amount" => $res->Amount,
"quantity" => $res->quantity,
"customerInfo" => array(
"customerName" => $res->customerName,
"CustomerPhone" => $res->CustomerPhone,
"CustomerAddress" => $res->CustomerAddress
)
);
}
$this->response($new_result, REST_Controller::HTTP_OK); // send newly created array instead
See if this helps you.
How to insert a foreach loop inside a multidimensional array ?
I have a multidimensional array that I use to connect my website to Mailchimp. I have to check with a foreach loop the number of products that the user buys, and add these insiede a array call "lines".
This is at moment my json code, that after I will send to Mailchimp:
$json_data = '{
"id": "2'. $order->id .'",
"customer": {
"id": "71",
"email_address": "'.$order->email.'",
"opt_in_status": true,
"company": "'.$order->company_name.'",
"first_name": "'.$order->pad_firstname.'",
"last_name": "'.$order->pad_lastname.'",
"orders_count": 1,
"total_spent": 86
},
"checkout_url": "https://www.mywebsite.it/en/checkout/confirmation/",
"currency_code": "EUR",
"order_total": 86,
"lines"[{
'.$line_result.'
}]
}';
The $line_result is where I try to add the array of the products.
I know is wrong.
all the array inside the "lines" need be like this:
"lines":[
{
data product 1 ...
},
{
data product 2 ...
}
]
This is my foreach:
foreach ($order->pad_products as $product) {
$line_result['line'] = array(
"id" => "$order->id",
"product_id" => "$product->pad_product_id",
"product_title" => "$product->title",
"product_variant_id" => "$product->id",
"product_variant_title" => "$product->title",
"quantity" => "$product->pad_quantity",
"price" => "$product->prezzo",
);
};
what is the correct way to insert this data and create a multidimensional array like the one I need?
Thank you.
You just need to store all $line_result in global variable, and then, bind it to your json model :
$results = [];
foreach ($order->pad_products as $product) {
$results[] = array(
"id" => $order->id,
"product_id" => $product->pad_product_id,
"product_title" => $product->title,
"product_variant_id" => $product->id,
"product_variant_title" => $product->title,
"quantity" => $product->pad_quantity,
"price" => $product->prezzo,
);
};
$data = json_decode($json_data, true);
$data['lines'] = $results;
$json = json_encode($data);
EDIT : Script array to json
$lines = [];
foreach ($order->pad_products as $product) {
$lines[] = array(
"id" => $order->id,
"product_id" => $product->pad_product_id,
"product_title" => $product->title,
"product_variant_id" => $product->id,
"product_variant_title" => $product->title,
"quantity" => $product->pad_quantity,
"price" => $product->prezzo,
);
}
$data = [
'id' => '2'.$order->id,
'customer' => [
'id' => '71',
'email_address' => $order->email,
'opt_in_status' => true,
'company' => $order->company_name,
'first_name' => $order->pad_firstname,
'last_name' => $order->pad_lastname,
'orders_count' => 1,
'total_spent' => 86
],
'checkout_url' => 'https://www.mywebsite.it/en/checkout/confirmation',
'currency_code' => 'EUR',
'order_total' => 86,
'lines' => $lines
];
$jsonData = json_encode($data, JSON_UNESCAPED_UNICODE);
I want say thank you to #adrianRosi for the help and the input he gives me.
In the end I find my solution, that it's json_encode the array before add into $data in json format.
in this way:
$product_list = [];
foreach ($order->pad_products as $product) {
$product_list[] = array(
"id" => "$id",
"..." => "...",
);
};
$data_products['lines'] = $product_list;
$json_products = json_encode($data_products);
$json_products_edit = substr($json_products, 1, -1); // to delete the {}
$prezzo_totale = $order->pad_price_total;
$json_data = '{
...
...
'.$json_products_edit.'
}';
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Converting an array from one to multi-dimensional based on parent ID values
I am working in PHP.
I have the following array that has relational data (parent child relationships).
Array
(
[5273] => Array
(
[id] => 5273
[name] => John Doe
[parent] =>
)
[6032] => Array
(
[id] => 6032
[name] => Sally Smith
[parent] => 5273
)
[6034] => Array
(
[id] => 6034
[name] => Mike Jones
[parent] => 6032
)
[6035] => Array
(
[id] => 6035
[name] => Jason Williams
[parent] => 6034
)
[6036] => Array
(
[id] => 6036
[name] => Sara Johnson
[parent] => 5273
)
[6037] => Array
(
[id] => 6037
[name] => Dave Wilson
[parent] => 5273
)
[6038] => Array
(
[id] => 6038
[name] => Amy Martin
[parent] => 6037
)
)
I need it to be in this JSON format:
{
"id":"5273",
"name":"John Doe",
"data":{
},
"children":[
{
"id":" Sally Smith",
"name":"6032",
"data":{
},
"children":[
{
"id":"6034",
"name":"Mike Jones",
"data":{
},
"children":[
{
"id":"6035",
"name":"Jason Williams",
"data":{
},
"children":[
{
"id":"node46",
"name":"4.6",
"data":{
},
"children":[
]
}
]
}
]
},
{
"id":"6036",
"name":"Sara Johnson",
"data":{
},
"children":[
]
},
{
"id":"6037",
"name":"Dave Wilson",
"data":{
},
"children":[
{
"id":"6038",
"name":"Amy Martin",
"data":{
},
"children":[
]
}
]
}
]
}
]
}
I know I need to create a multidimensional array and run it through json_encode(). I also believe this method used to do this needs to be recursive because the real world data could have an unknown number of levels.
I would be glad to show some of my approaches but they have not worked.
Can anyone help me?
I was asked to share my work. This is what I have tried but I have not gotten that close to I don't know how helpful it is.
I made an array of just the relationships.
foreach($array as $k => $v){
$relationships[$v['id']] = $v['parent'];
}
I think (based off another SO post) used this relational data to create a the new multidimensional array. If I got this to work I was going to work on adding in the correct "children" labels etc.
$childrenTable = array();
$data = array();
foreach ($relationships as $n => $p) {
//parent was not seen before, put on root
if (!array_key_exists($p, $childrenTable)) {
$childrenTable[$p] = array();
$data[$p] = &$childrenTable[$p];
}
//child was not seen before
if (!array_key_exists($n, $childrenTable)) {
$childrenTable[$n] = array();
}
//root node has a parent after all, relocate
if (array_key_exists($n, $data)) {
unset($data[$n]);
}
$childrenTable[$p][$n] = &$childrenTable[$n];
}
unset($childrenTable);
print_r($data);
<?php
header('Content-Type: application/json; charset="utf-8"');
/**
* Helper function
*
* #param array $d flat data, implementing a id/parent id (adjacency list) structure
* #param mixed $r root id, node to return
* #param string $pk parent id index
* #param string $k id index
* #param string $c children index
* #return array
*/
function makeRecursive($d, $r = 0, $pk = 'parent', $k = 'id', $c = 'children') {
$m = array();
foreach ($d as $e) {
isset($m[$e[$pk]]) ?: $m[$e[$pk]] = array();
isset($m[$e[$k]]) ?: $m[$e[$k]] = array();
$m[$e[$pk]][] = array_merge($e, array($c => &$m[$e[$k]]));
}
return $m[$r][0]; // remove [0] if there could be more than one root nodes
}
echo json_encode(makeRecursive(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'),
)));
demo: https://3v4l.org/s2PNC
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": {
}
}
]
}
]
}
Following code will do the job.. you may want to tweak a bit according to your needs.
$data = array(
'5273' => array( 'id' =>5273, 'name'=> 'John Doe', 'parent'=>''),
'6032' => array( 'id' =>6032, 'name'=> 'Sally Smith', 'parent'=>'5273'),
'6034' => array( 'id' =>6034, 'name'=> 'Mike Jones ', 'parent'=>'6032'),
'6035' => array( 'id' =>6035, 'name'=> 'Jason Williams', 'parent'=>'6034')
);
$fdata = array();
function ConvertToMulti($data) {
global $fdata;
foreach($data as $k => $v)
{
if(empty($v['parent'])){
unset($v['parent']);
$v['data'] = array();
$v['children'] = array();
$fdata[] = $v;
}
else {
findParentAndInsert($v, $fdata);
}
}
}
function findParentAndInsert($idata, &$ldata) {
foreach ($ldata as $k=>$v) {
if($ldata[$k]['id'] == $idata['parent']) {
unset($idata['parent']);
$idata['data'] = array();
$idata['children'] = array();
$ldata[$k]['children'][] = $idata;
return;
}
else if(!empty($v['children']))
findParentAndInsert($idata, $ldata[$k]['children']);
}
}
print_r($data);
ConvertToMulti($data);
echo "AFTER\n";
print_r($fdata);
http://codepad.viper-7.com/Q5Buaz