Reputation: 10288
I'm trying to create a "plugin" like script for adding to a "menu array".... I'll go straight in..
Lets say I initiate a nav item like so:
$sections->add_section('dashboard');
$DashBoardSection = $sections->load_section('dashboard');
$DashBoardSection->set_role(NULL);
$DashBoardSection->set_nav_item(array(
'identifier' => 'dashboard',
'text' => 'Dashboard',
'url' => NULL,
'position' => NULL
));
starts off by creating a new section and the getting the instance of.
We are then setting a "role" in which we will test against to see if the user is authenticated as being verified to view.
The set nav item simply stores the array. identifier is a reference to the item ( its for when we want to add sub items), all standard apart from "position" which states where it is to sit in the nav i.e. NULL is top level, array('topnav','subnav') will be topnav->subnav->dashboard.
as a test, this could be stored as follows:
Array
(
[0] => Array
(
[identifier] => dashboard
[text] => Dashboard
[url] =>
[position] =>
)
[1] => Array
(
[identifier] => dashboard2
[text] => Dashboard2
[url] =>
[position] => Array
(
[0] => dashboard
)
)
)
my question being how I turn that into the following structure:
Array
(
[0] => Array
(
[identifier] => dashboard
[text] => Dashboard
[url] =>
[position] =>
[children] => Array
(
[0] => Array
(
[identifier] => dashboard2
[text] => Dashboard2
[url] =>
)
)
)
)
pulling my hair out over this one, any help would be very much appreciated.
regards
I currently have
public function build_navigation( $role ){
$role = (int)$role;
$nav = array();
foreach( $this->sections as $section ) {
if( $section->get_role() === NULL || $section->get_role() === $role ) {
$nav_array = $section->get_nav();
foreach( $nav_array as $key => $nav_item ) {
if( $nav_item['position'] === NULL ) {
$nav[$nav_item['identifier']] = $nav_item;
}elseif( is_array( $nav_item['position'] ) ){
#...#
}
}
}
}
return $nav;
}
EDIT
Imagine this is the array given (it can be in any order)
Array
(
[0] => Array
(
[identifier] => dashboard_child2
[text] => Dashboard Child 2
[url] =>
[position] => Array
(
[0] => dashboard
)
)
[1] => Array
(
[identifier] => dashboard_child_child_1
[text] => Dashboard Child Child 1
[url] =>
[position] => Array
(
[0] => dashboard
[1] => dashboard_child1
)
)
[2] => Array
(
[identifier] => dashboard_child1
[text] => Dashboard Child 1
[url] =>
[position] => Array
(
[0] => dashboard
)
)
[3] => Array
(
[identifier] => dashboard
[text] => Dashboard
[url] =>
[position] =>
)
[4] => Array
(
[identifier] => dashboard2
[text] => Dashboard2
[url] =>
[position] => Array
(
[0] => dashboard
)
)
)
Which needs to be formatted as:
Array
(
[dashboard] => Array
(
[text] => Dashboard
[url] =>
[children] => Array
(
[dashboard_child2] => Array
(
[text] => Dashboard Child 2
[url] =>
)
[dashboard_child1] => Array
(
[text] => Dashboard Child 1
[url] =>
[children] => Array
(
[dashboard_child_child_1] => Array
(
[text] => Dashboard Child Child 1
[url] =>
)
)
)
[dashboard2] => Array
(
[text] => Dashboard2
[url] =>
)
)
)
)
Upvotes: 2
Views: 392
Reputation: 20753
Here's my take on the problem, solved with recursion.
You can use multiple positions (i guess this is why it's an array), it will ignore missing positions if at least on of the positions is found, but will complain if every position is missing.
function translate($in) {
$out = array();
// first pass, move root nodes to output
foreach ($in as $k => $row) {
if (!$row['position']) {
$out[$row['identifier']] = $row;
unset($in[$k]);
}
}
// while we have input
do {
$elements_placed = 0;
// step trough input
foreach ($in as $row_index => $row) {
foreach ($row['position'] as $pos) {
// build context for the node placing
$data = array(
'row' => $row,
'in' => &$in,
'row_index' => $row_index,
'elements_placed' => &$elements_placed,
'pos' => $pos,
);
// kick of recursion
walker($out, $data);
}
}
} while ($elements_placed != 0);
if (count($in)) {
trigger_error("Error in user data, can't place every item");
}
return $out;
}
function walker(&$out, $data) {
foreach ($out as &$row) {
// it looks like a node array
if (is_array($row) && isset($row['identifier'])) {
// if it has children recurse in there too
if (isset($row['children'])) {
walker($row['children'], $data);
}
// it looks like a node array that we are looking for place the row
if ($row['identifier'] == $data['pos']) {
if (!isset($row['children'])) {
$row['children'] = array($data['row']['identifier'] => $data['row']);
} else {
$row['children'][$data['row']['identifier']] = $data['row'];
}
// report back to the solver that we found a place
++$data['elements_placed'];
// remove the row from the $in array
unset($data['in'][$data['row_index']]);
}
}
}
}
$in = array (
array (
'identifier' => 'secondlevelchild2',
'text' => 'secondlevelchild2',
'url' => '',
'position' => array (
'dashboard2',
),
),
array (
'identifier' => 'secondlevelchild',
'text' => 'secondlevelchild',
'url' => '',
'position' => array (
'dashboard2',
),
),
array (
'identifier' => 'dashboard',
'text' => 'Dashboard',
'url' => '',
'position' => '',
),
array (
'identifier' => 'dashboard2',
'text' => 'Dashboard2',
'url' => '',
'position' => array (
'dashboard', 'home',
),
),
array (
'identifier' => 'thirdlevelchild',
'text' => 'thirdlevelchild',
'url' => '',
'position' => array (
'secondlevelchild2',
),
),
);
$out = translate($in);
var_export($out);
In it's current form it doesn't remove the identifier
or position
keys from the node arrays once they are placed.
Upvotes: 2
Reputation: 197767
You need a temporary array that maps the identifier to the children array of it so that you can add it there.
If I see that right, you have something like that already here when you add the parent:
$nav[$nav_item['identifier']] = $nav_item;
Edit: Adding the parent needs some caution as pointed out in the comment:
$node = &$nav[$nav_item['identifier']];
$children = isset($node['children']) ? $node['children'] : array();
$node = $nav_item;
$node['children'] = $children;
unset($node);
Just add to the children then:
foreach($nav_item['position'] as $identifier)
{
$nav[$identifier]['children'][] = $nav_item;
}
Also you could use objects, not arrays, so that you do not duplicate data that much (or you can change it later), however, just thinking, this must not be necessary to solve your problem so probably something for later.
Upvotes: 2