PHP Recursion with Associative Array (Menu structure) - php

I've been banging my head against a wall today. I have a mysql table that has a list of menu items which have a recursive parent/child relationship. I need to create an associative array that matches it.
Here is my code, and below it is an explanation of my problem.
MySQL Database
CREATE TABLE IF NOT EXISTS `menus` (
`sectionid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parentid` int(10) unsigned NOT NULL DEFAULT '0',
`name` varchar(128) NOT NULL DEFAULT '',
PRIMARY KEY (`sectionid`)
);
INSERT INTO `menus` (`sectionid`, `parentid`, `name`) VALUES
(1, 0,'DOWNLOADS'),(4, 1,'Player Scenarios'),
(5, 1,'Co Op Scenarios'),(9, 1,'MAPS');
PHP CODE
function get_db_children($parentid) {
$mysqli = mysqli_open();
$sqlStr = "select sectionid as childid from menus where parentid=$parentid order by sectionid";
$result = $mysqli->query($sqlStr);
$mysqli->close();
return $result;
}
function get_children(&$node) {
foreach ($node as $key=>$value) {
$result = get_db_children($key);
while ($row = $result->fetch_assoc()) {
$tmp = array($row['childid'] => array());
$node[$key][$row['childid']]= get_children($tmp);
}
}
return $node;
}
===========================================
The above functions are called from my main script as follows:
$categories[0] = array ();
get_children($categories);
print "Categories=".print_r($categories);
exit;
==============
My PROBLEM.
My problem is that the structure of the returned array is not QUITE how I want it.
The code above returns:
Categories=
Array ( [0] => Array
( [1] => Array
( [1] => Array
( [4] => Array
( [4] => Array ( ) )
[5] => Array
( [5] => Array ( ) )
[9] => Array
( [9] => Array ( ) )
)
)
)
)
What I want is:
Categories=
Array ( [0] => Array
( [1] => Array
(
( [4] => Array ( ) )
( [5] => Array ( ) )
( [9] => Array ( ) )
)
)
)
A null array indicates no children.
I can't figure out how to get rid of the double up on key values. :(
If anyone can help, would be much appreciated.
Cheers,
Nap

Changing the approach a little has fixed my problem. Instead of passing the $categories array by reference, I just pass the ID of the parent menu item and return the array.
Code below uses same SQL data and SQL accessor function get_db_children($parentid) as given in my OP. I'm sure this could be improved upon, but at least I've got my result.
#Josh, thnx for your input.
PHP Functions
function get_twigs($nodeid) {
$result = get_db_children($nodeid);
if ($result->num_rows != 0) {
while ($row = $result->fetch_assoc()) {
$node[$row['childid']] = array();
$node[$row['childid']] = get_twigs($row['childid']);
}
} else {
$node=NULL; // or any other 'no children below me indicator.
}
return $node;
}
function get_branch($nodeid) {
$node[$nodeid] = array();
$node[$nodeid] = get_twigs($nodeid);
return $node;
}
PHP Caller
$categories = get_branch(0);
Finally got it going.
:)

you are passing in the $node by reference therefore instead of doing $node[$key][$row['childid']] = get_children($tmp); you should really be doing
$value[$row['childid']] = get_children($tmp)
or
$node[$row['childid']] = get_children($temp)
but if you go with the second option you will have to pass in $categories[0] on the first call to get_children (which is what you are doing when you are making the recurring calls)
update:
ill try and explain the reason for that...
as you can see the first entry (0) is not duplicated. only after the first recurring call is where your problem starts, the reason for that is because you are passing in the child array by reference therefore the second time around [as a example] when you call get_children the $node var actually already refers to the nested part
array(
0=>array(
1=>array(/*this is what $node actually is the second time around*/
/*when you say $node[$key][$row['childid']] what you are actually saying is assign the value to array[0][1][1][4] = array())*/
)
)
);
i hope this helps. if i can think of a way to explain it batter ill come back and update...

Related

PHP recursive function returning null array

I have a huge array in which keys are also not constant in most of the cases, but there are 3 keys that always constant (#name,#default_value,#value) and #default_value and #value is different i want to get these kind of sub arrays in 1 simple array , for this purpose i am using recursion in whole array and checking out if these 3 keys are present there i can print these values inside recursion easily but I am not able to get those values in return. So that i can precess them further.
$form=array();
$form['field_one']['#name']="field_one";
$form['field_one']['#default_value']="old";
$form['field_one']['#value']="new";
$form['field_two']['#name']="field_two";
$form['field_two']['#default_value']="old";
$form['field_two']['#value']="new";
$form['field_three']['#name']="field_three";
$form['field_three']['#default_value']="old";
$form['field_three']['#value']="old";
$form['thiscouldbeanotherarray']['idk']['field_four']['#name']="field_four";
$form['thiscouldbeanotherarray']['idk']['field_four']['#default_value']="old";
$form['thiscouldbeanotherarray']['idk']['field_four']['#value']="new";
$arr_get = get_updatedvalues($form,array());
var_dump($arr_get);
function get_updatedvalues($form,$fields) {
if (!is_array($form)) {
return;
}
foreach($form as $k => $value) {
if(str_replace('#','',$k) =='default_value' && ($form['#default_value'] != $form['#value'] ) ){
$fields['field'][$form['#name']] = array("name" => $form['#name'],"old_value" =>$form['#default_value'],"new_value" =>$form['#value']);
var_dump($fields);
}
get_updatedvalues($value,$fields);
}
return $fields;
}
If you run this code it will give you $arr_get > array (size=0), there i need all three values
If I understand correctly, you need to pass fields as a reference in order to change it:
function get_updatedvalues($form, &$fields) {
To do that, however, you'll need to change your initial call so that you have a variable to pass as the reference:
$array = [];
$arr_get = get_updatedvalues($form,$array);
Running this I get:
Array
(
[field] => Array
(
[field_one] => Array
(
[name] => field_one
[old_value] => old
[new_value] => new
)
[field_two] => Array
(
[name] => field_two
[old_value] => old
[new_value] => new
)
[field_four] => Array
(
[name] => field_four
[old_value] => old
[new_value] => new
)
)
)

Issue regarding multidimensional array

I am trying to retrieve values from a multidimensional array. In this case below code is working
echo $orderList['Orders']['Order'][1]['OrderItems']['OrderItem']['SKU'];
But this is not working
for($i=0;$i<count($orderList);$i++)
{
$order_info['order_sku'] = $orderList['Orders']['Order'][$i]['OrderItems']['OrderItem']['SKU'];
}
Can anyone say what is the problem ??
UPDATE
Actually my array like below.I would like to retrieve RowId value; Thanks
Array
(
[0] => Array
(
[OrderItems] => Array
(
[OrderItem] => Array
(
[RowId] => 1
)
)
)
)
Perhaps
for($i=0;$i<count($orderList['Orders']['Order']);$i++) { ... }
or even
foreach($orderList['Orders']['Order'] as $order) {
$order_info['order_sku'] = $order['OrderItems']['OrderItem']['SKU'];
}
How about:
for($i=0;$i<count($orderList);$i++) {
$order_info['order_sku'] = $orderList[$i]['OrderItems']['OrderItem']['RowId'];
}

Arrange parent-child relationship

I have read the Build a tree from a flat array in PHP and the Convert a series of parent-child relationships into a hierarchical tree? but could not figure out how to implement it for my problem. There is a pairs of relations as such:
Array
(
[0] => catalog.iden = catalog_sub.parent
[1] => catalog.group = catalog_group.iden
[2] => catalog_photo.iiden = catalog.iden
)
I have not NULL, or 0, or any explicit condition to stop looping. All what I know is what field has primary key with auto_increment attribute. Say in that example it will be field named 'iden' so in the relation it will be "parent".
I have spent a week to resolve this problem but with no result. So could anybody help me to arrange this array in order of relations. It may be tree of flat array.
Thanks in advance.
UPDATE
So far I only managed to do so:
foreach($matches[0] as &$match) {
$ref = explode('=', $match); // split by = sign
$lft = explode('.', $ref[0]);
$rgt = explode('.', $ref[1]);
if($lft[1] == 'iden') {
$arr[$lft[0]][$rgt[0]] = $rgt[1];
} else {
$arr[$rgt[0]][$lft[0]] = $lft[1];
}
}
What gives sorting by primary key and grouping by used tables:
Array
(
[catalog] => Array
(
[catalog_sub] => parent
[catalog_photo] => iiden
)
[catalog_group] => Array
(
[catalog] => group
)
)

get unique value from array and sum totals

From this Array() I want to grab the values of amount_total, shipping and partner and total them up by specific partner. So for example the partner=>2665 should have a amount_total of 41.79 + 55.95 and so on please help. I don't want to do it through SQL because I need the data as it is as well.
Array
(
[0] => Array
(
[amount_total] => 41.79
[amount_shipping] => 4.99
[amount_partner] => 14.8
[partner] => 2665
)
[1] => Array
(
[amount_total] => 55.95
[amount_shipping] => 19.96
[amount_partner] => 11
[partner] => 2665
)
[2] => Array
(
[amount_total] => 51.96
[amount_shipping] => 7.98
[amount_partner] => 23.98
[partner] => 51754
)
[3] => Array
(
[amount_total] => 24.55
[amount_shipping] => 4.99
[amount_partner] => 5.67
[partner] => 11513
)
)
You could use PHP to achieve this, but this won't be necessary.
The database can do this much more efficiently
I assume your current query looks something like this
SELECT
`amount_total`,
`amount_shipping`,
`amount_partner`,
`partner`
FROM
`salesLeads`
WHERE
[..]
MySQL gives you nice aggregate functions like SUM you can use with GROUP BY
SELECT
SUM( `amount_total` ) AS `amount_total`,
SUM( `amount_shipping` ) AS `amount_shipping`,
SUM( `amount_partner` ) AS `amount_partner`.
`partner`
FROM
`salesLeads`
WHERE
[..]
GROUP BY
`partner`
in your PHP script you access this the same way but it has the final numbers grouped and summarized by partner already
e.g.
if ($result = $mysqli->query($query)) {
while ($row = $result->fetch_assoc()) {
print_r( $row );
}
$result->close();
}
EDIT
Because you wanted a PHP solution, which again is more efficient than querying twice:
$partnerSums = array();
while ( $row = $result->fetch_assoc() ) {
if ( !array_key_exists( $row['partner'], $partnerSums ) {
$partnerSums[$row['partner']] = $row;
} else {
$partnerSums[$row['partner']]['amount_total'] += $row['amount_total'];
$partnerSums[$row['partner']]['amount_shipping'] += $row['amount_shipping'];
$partnerSums[$row['partner']]['amount_partner'] += $row['amount_partner'];
}
}
print_r( $partnerSums );
I think looping through this array and storing the totals in new array, along with checking in_array (more here) should be sufficient. All you need to do is every time you loop through an element, check if it's already in new array, and if it is - perform necessary mathematical operation
I would suggest something like this:
$res['totals']=array();
foreach($result as $res)
{
$partner = $result['partner'];
$res['totals'][$partner]+=$result['total_amount'];
}
This way you get all the data you need in just one place: the partner array '$res'.
Hope it helps you.

PHP - Removing one array layer

I have a simple PHP function that will grab information from a database based on a unique ID:
function oracleGetGata($query, $id="id") {
global $conn;
$results = array();
$sql = OCI_Parse($conn, $query);
OCI_Execute($sql);
while ( false!==($row=oci_fetch_assoc($sql)) ) {
$results[ $row[$id] ] = $row;
}
return $results;
}
So for example $array = oracleGetData('select * from table') would return:
[1] => Array
(
[Title] => Title 1
[Description] => Description 1
)
[2] => Array
(
[Title] => Title 2
[Description] => Description 2
)
This is fine, however, if I just want to return one record $array = oracleGetData('select * from table where id = 1') it returns the data like:
[] => Array
(
[Title] => Title 1
[Description] => Description 1
)
Not only am I unsure of how to reference this (there is nothing identifying the array) I'd also like to somehow change my function so if it just returns one record, it will just be a simple one dimensional array.
I've looked into the usual PHP array functions but can't find anything that'll help, nor an easy way of identifying how deep the array is.
Would really appreciate any help, thank you
Use array_pop():
$array = array_pop(oracleGetData('select * from table where id = 1'));
You will then get one single array:
Array
(
[Title] => Title 1
[Description] => Description 1
)
Instead of an array embedded in another one:
Array
(
[] => Array
(
[Title] => Title 1
[Description] => Description 1
)
}
I think there is an logic error in your script:
Change
$results[ $row[$id] ] = $row;
into
$results[] = $row;
The problem is, that you want to have the Database key value as array key value, but you don't know the Database key, since you don't know what the query will look like.
You could try:
$results[$row['id']] = $row;
But this only works when all of your results have a Database key named "id".
You pass a $id in the function signature, but in the loop you uses $row[$id], Why? Maybe the error is there.
If you want a sequencial id in your result set, you don't need use the $id, you can uses array_push() function
array_push($result, $row);
OR
$results[] = $row;

Categories