Okay this might be an ugly solution but if you put everything in a function it look good :). The good thing is that it will work in your scenario.
Code:
$inputData = array(
array(
'Section_Id' => 1,
'Section_Name' => "Section1",
'Section_Parent' => NULL,
'Section_Position' => 1,
'Section_Depth' => 0,
),
array(
'Section_Id' => 2,
'Section_Name' => "Section2",
'Section_Parent' => NULL,
'Section_Position' => 0,
'Section_Depth' => 0
),
array(
'Section_Id' => 4,
'Section_Name' => "SubSection2ForSection2",
'Section_Parent' => 2,
'Section_Position' => 1,
'Section_Depth' => 1
),
array(
'Section_Id' => 5,
'Section_Name' => "SubSection1ForSection2",
'Section_Parent' => 2,
'Section_Position' => 0,
'Section_Depth' => 1
),
array(
'Section_Id' => 3,
'Section_Name' => "SubSection1ForSection1",
'Section_Parent' => 1,
'Section_Position' => 0,
'Section_Depth' => 1
)
);
$parentRecords = array();
$childRecords = array();
$sorted = array();
/* split in two collections */
foreach ($inputData as $sectionData) {
if (is_null($sectionData['Section_Parent'])) {
/* assume this is a parent */
$parentRecords[] = $sectionData;
} else {
/* assume we are on child row */
$childRecords[] = $sectionData;
}
}
/* now first order parents by Section_Position */
usort($parentRecords, function($a, $b) {
if ($a['Section_Position'] == $b['Section_Position']) {
return 0;
}
return $a['Section_Position'] > $b['Section_Position'] ? 1 : -1;
});
/* now the actual sorting */
foreach ($parentRecords as $parentData) {
$parentId = $parentData['Section_Id'];
/* now get all children of this parent */
$parentChildren = array();
foreach ($childRecords as $childData) {
if ($childData['Section_Parent'] == $parentId) {
$parentChildren[] = $childData;
}
}
/* now sort the children by Section_Position */
usort($parentChildren, function($a, $b) {
if ($a['Section_Position'] == $b['Section_Position']) {
return 0;
}
return $a['Section_Position'] > $b['Section_Position'] ? 1 : -1;
});
$sorted[] = $parentData;
$sorted = array_merge($sorted, $parentChildren);
}
echo '<pre>' . print_r($sorted, true) . '</pre>';
exit;
OUTPUT:
Array
(
[0] => Array
(
[Section_Id] => 2
[Section_Name] => Section2
[Section_Parent] =>
[Section_Position] => 0
[Section_Depth] => 0
)
[1] => Array
(
[Section_Id] => 5
[Section_Name] => SubSection1ForSection2
[Section_Parent] => 2
[Section_Position] => 0
[Section_Depth] => 1
)
[2] => Array
(
[Section_Id] => 4
[Section_Name] => SubSection2ForSection2
[Section_Parent] => 2
[Section_Position] => 1
[Section_Depth] => 1
)
[3] => Array
(
[Section_Id] => 1
[Section_Name] => Section1
[Section_Parent] =>
[Section_Position] => 1
[Section_Depth] => 0
)
[4] => Array
(
[Section_Id] => 3
[Section_Name] => SubSection1ForSection1
[Section_Parent] => 1
[Section_Position] => 0
[Section_Depth] => 1
)
)
NOTE: first sort is done by respect to parents Section_Position and then to child's Section_Position
U P D A T E
First I want to say sorry to moderators for the long long discussion that we had with @Akorna but I needed to give him this code and I think it will do the job for the future. So @Akorna the code that should work for you is this one:
$inputData = array(
array(
'section_id' => 333,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 0,
'section_title' => 'Introduction'),
array(
'section_id' => 334,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 1,
'section_title' => 'Glossary'),
array(
'section_id' => 335,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 2,
'section_title' => 'Commands'),
array(
'section_id' => 336,
'section_depth' => 1,
'section_parent' => 332,
'section_position' => 3,
'section_title' => 'Components'),
array(
'section_id' => 337,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 0,
'section_title' => 'Introduction'),
array(
'section_id' => 407,
'section_depth' => 2,
'section_parent' => 401,
'section_position' => 2,
'section_title' => 'Web Application'),
array(
'section_id' => 338,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 1,
'section_title' => 'AbstractContainer'),
array(
'section_id' => 406,
'section_depth' => 2,
'section_parent' => 401,
'section_position' => 1,
'section_title' => 'Web Application'),
array(
'section_id' => 339,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 2,
'section_title' => 'ActionsContainer'),
array(
'section_id' => 340,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 3,
'section_title' => 'BrowserIncompatibility'),
array(
'section_id' => 404,
'section_depth' => 2,
'section_parent' => 402,
'section_position' => 3,
'section_title' => 'Web Application'),
array(
'section_id' => 341,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 4,
'section_title' => 'CollapsibleContainer'),
array(
'section_id' => 342,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 5,
'section_title' => 'DetailsContainer'),
array(
'section_id' => 343,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 6,
'section_title' => 'DynamicMenu'),
array(
'section_id' => 403,
'section_depth' => 2,
'section_parent' => 402,
'section_position' => 1,
'section_title' => 'Web Application'),
array(
'section_id' => 344,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 7,
'section_title' => 'Settings'),
array(
'section_id' => 345,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 8,
'section_title' => 'SubfilesViewer'),
array(
'section_id' => 346,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 9,
'section_title' => 'Taxonomy Management'),
array(
'section_id' => 402,
'section_depth' => 1,
'section_parent' => 400,
'section_position' => 2,
'section_title' => 'Web Application'),
array(
'section_id' => 401,
'section_depth' => 1,
'section_parent' => 400,
'section_position' => 1,
'section_title' => 'Web Application'),
array(
'section_id' => 347,
'section_depth' => 2,
'section_parent' => 336,
'section_position' => 10,
'section_title' => 'UploadQueue'),
array(
'section_id' => 400,
'section_depth' => 0,
'section_parent' => null,
'section_position' => 5,
'section_title' => 'Web Application'),
array(
'section_id' => 332,
'section_depth' => 0,
'section_parent' => null,
'section_position' => 3,
'section_title' => 'Web Application')
);
/* first order by section_depth and then by section_position */
$inputData = array_orderby($inputData, 'section_depth', SORT_ASC, 'section_position', SORT_ASC);
$parents = array();
$sortedByParent = false;
while (!$sortedByParent) {
$elems = array_splice($inputData, count($inputData) - 1, 1);
if (!count($elems)) {
$sortedByParent = true;
$inputData = array_merge($inputData, $parents);
continue;
}
$elem = $elems[0];
if ($elem['section_depth'] == 0) {
if (!isset($elem['children'])) {
$elem['children'] = array();
}
$parents[] = $elem;
} else {
$inputData = put_in_parent($elem, $inputData);
}
}
/* now we have $inputData in nice format like
* parent(child, child, child(child, child(child, child)), child(child(child(child)))),
* parent(child, child, child(child, child(child, child)), child(child(child(child))))
* */
$inputData = merge_children_recursively(array_reverse($inputData));
function merge_children_recursively($inputData) {
$children = array();
foreach ($inputData as $row) {
if (isset($row['children'])) {
/* this ksort call is necessary because the key is actually section_position */
ksort($row['children']);
$rowCopy = $row;
unset($rowCopy['children']);
$children[] = $rowCopy;
$children = array_merge($children, merge_children_recursively($row['children']));
} else {
$children[] = $row;
}
}
return $children;
}
function put_in_parent($elem, $inputData) {
foreach ($inputData as $k => $row) {
if ($row['section_id'] == $elem['section_parent']) {
if (!isset($inputData[$k]['children'])) {
$inputData[$k]['children'] = array();
}
$inputData[$k]['children'][$elem['section_position']] = $elem;
break;
}
}
return $inputData;
}
function array_orderby() {
$args = func_get_args();
$data = array_shift($args);
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row) {
$tmp[$key] = $row[$field];
}
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}
echo '<pre>' . print_r($inputData, true) . '</pre>';
exit;
I did remove some stuff from the input data so I could orient myself. Just try to give your input data to the logic and let me know what is the result.