I have a query that pulls all food categories, a function that iterates recursively to create a tree, and finally another recursive function that flattens it while adding a depth indicator.
The recursion works fine. I am having difficulty passing the parent breadcrumbs down to each children. There must be a crumb for each level, even the last.
Although crumb accumulation requires the current node be for a specific parent, the function carries over all past crumbs somehow, even crumbs from children of other parents. The rest of the structure abides by the parent/children relationship. I cannot see why the breadcrumbs don't.
a small sample of the query results
$QueryResults = array
(
0 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 42
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 1
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Alcoholic'
)
)
),
1 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 39
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Beef'
)
)
),
2 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 1
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => NULL
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Beverages'
)
)
),
3 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 44
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 1
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Carbonated'
)
)
),
4 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 46
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 1
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Coffee'
)
)
),
5 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 4
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => NULL
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Meats'
)
)
),
6 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 44
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Processed Meats'
)
)
),
7 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 45
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 44
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Luncheon Meats'
)
)
),
8 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 7
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Pork'
)
)
),
9 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 8
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Poultry'
)
)
)
)
;
here's my attempt at processing the database query results (the tree flattens after this completes).
function buildTree($elements, $parentId, $crumbs) {
$branch = array();
foreach ($elements as $element) {
if ($element['Fields'][1]['Value'] == $parentId) {
$currentCrumbs[] = array('Fields' => array(0 => array('FieldName' => 'id','Value' => $element['Fields'][0]['Value']),1 => array('FieldName' => 'Crumb','Value' => $element['Fields'][2]['Value'])));
if (is_array($crumbs)) { // lower levels
$combinedCrumbs = array_merge($crumbs, $currentCrumbs);
} else { // top level
$combinedCrumbs = $currentCrumbs;
}
$element['BreadCrumbs'] = $combinedCrumbs;
$children = buildTree($elements, $element['Fields'][0]['Value'], $combinedCrumbs);
if ($children) {
$element['SubGroups'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
This part of the database is like this, but other parts are more layers deep:
The full structure takes a lot of space to display, so this is just one node containing "carbonated" beverages. It correctly carries over the "Beverages", but then it also contains the crumb from "Alcoholic" leaf which is not a part of the "Carbonated" chain. I don't know how the crumb from the "Alcoholic" instance of this function made its way into the "Carbonated" chain of function instances. The rest of the tree builds correctly. It's not a local problem--"Beverages" also makes its way into the "Meats" top level node.
Current behavior (notice how "Alcoholic" is present):
[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => parent_id
[Value] => 1
)
[2] => Array
(
[FieldName] => name
[Value] => Carbonated
)
)
[BreadCrumbs] => Array
(
[0] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 1
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Beverages
)
)
)
[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 42
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Alcoholic
)
)
)
[2] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Carbonated
)
)
)
)
)
Expected Behavior:
[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => parent_id
[Value] => 1
)
[2] => Array
(
[FieldName] => name
[Value] => Carbonated
)
)
[BreadCrumbs] => Array
(
[0] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 1
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Beverages
)
)
)
[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Carbonated
)
)
)
)
)
I Understand this structure is more verbose and deeper than it probably needs to be if it were associative instead of indexed, but for reasons not related and in ways not obvious, it is what it is.
I have a separate failed effort on the flattened array with its parent_id intact and a depth indicator added, but a solution there would work too.
How can i adjust this such that only the crumbs for the given chain accumulate?
Looked into it and this worked for me:
function buildTree($elements, $parentId, $crumbs) {
$branch = array();
foreach ($elements as $element) {
if ($element['Fields'][1]['Value'] == $parentId) {
$currentCrumbs = array(array('Fields' => array(0 => array('FieldName' => 'id','Value' => $element['Fields'][0]['Value']),1 => array('FieldName' => 'Crumb','Value' => $element['Fields'][2]['Value']))));
if (is_array($crumbs)) { // lower levels
$combinedCrumbs = combineArrays($crumbs, $currentCrumbs);
} else { // top level
$combinedCrumbs = $currentCrumbs;
}
$element['BreadCrumbs'] = $combinedCrumbs;
$children = buildTree($elements, $element['Fields'][0]['Value'], $combinedCrumbs);
if ($children) {
$element['SubGroups'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
The main problem was that you have appended elements to $currentCrumbs
, like
$currentCrumbs[]= ...
So, when there are more elements to process, that is, there are more than one siblings, such as in the case of Alcoholic and Carbonated, whose parent is Beverages, at the first step Alcoholic is "added" to a non-existing array, that is, a new array is being created with a single element, Alcoholic. Then, when it is proceeding to the second step, that is, to Carbonated, then Alcoholic is already in $currentCrumbs
and Carbonated
is added to it, resulting in an array of two elements.
Instead, I'm creating a new array at every iteration of the loop.
Also, I wrapped an array around the array and separated the merging. The result was a success: