Небольшой ремейк для себя .
CModule::IncludeModule('iblock');
$map=array();
$arParams["IBLOCK_MAP_ID"] = XX; // - каким-то образом задается параметр с ID инфоблока
$sort_by = 'name'; // поле, по которому нужно произвести сортировку разделов
$sort_order = 'asc'; // направление сортировки
if(isset($arParams["IBLOCK_MAP_ID"])){
$arFilter = Array(
'IBLOCK_ID'=>$arParams["IBLOCK_MAP_ID"],
'GLOBAL_ACTIVE'=>'Y'
);
$db_list = CIBlockSection::GetList(Array($sort_by=>$sort_order), $arFilter, true);
while($ar_result = $db_list->GetNext()) {
$map[''.$ar_result['ID']]=$ar_result;
}
}
Таким образом, в переменной $map получаем полный список разделов, отсортированных по нужному полю и в нужном направлении.
Дальше - строим дерево из разделов:
$map_sec = array();
foreach ($map as $key => $val) {
if ($val['IBLOCK_SECTION_ID'] > 0) {
$parent_id = $map[$val['IBLOCK_SECTION_ID']]['ID'];
if(!isset($map_sec[$parent_id])){
$map_sec[$parent_id]['ID'] = $map[$parent_id]['ID'];
$map_sec[$parent_id]['CODE'] = $map[$parent_id]['CODE'];
$map_sec[$parent_id]['NAME'] = $map[$parent_id]['NAME'];
$map_sec[$parent_id]['SECTION_PAGE_URL'] = $map[$parent_id]['SECTION_PAGE_URL'];
$map_sec[$parent_id]['UF_SOMECODE'] = $map[$parent_id]['UF_SOMECODE'];
$map_sec[$parent_id]['DEPTH_LEVEL'] = $map[$parent_id]['DEPTH_LEVEL'];
$map_sec[$parent_id]['IBLOCK_SECTION_ID'] = $map[$parent_id]['IBLOCK_SECTION_ID'];
}
$map_sec[$parent_id]['CHILDS'][$val['ID']] = array(
"ID" => $val['ID'],
"CODE" => $val['CODE'],
"NAME" => $val['NAME'],
"DEPTH_LEVEL" => $val['DEPTH_LEVEL'],
"SECTION_PAGE_URL" => $val['SECTION_PAGE_URL'],
"UF_SOMECODE" => $val['UF_SOMECODE'],
"IBLOCK_SECTION_ID" => $val['IBLOCK_SECTION_ID'],
);
} else {
if(!isset($map_sec[$val['ID']])){
$map_sec[$val['ID']] = array(
"ID" => $val['ID'],
"CODE" => $val['CODE'],
"NAME" => $val['NAME'],
"DEPTH_LEVEL" => $val['DEPTH_LEVEL'],
"SECTION_PAGE_URL" => $val['SECTION_PAGE_URL'],
"UF_SOMECODE" => $val['UF_SOMECODE'],
"IBLOCK_SECTION_ID" => $val['IBLOCK_SECTION_ID'],
);
}
}
}
Таким образом, в переменной $map_sec хранится дерево разделов. В отличие от гениально простого алгоритма, предложенного Юлией по ссылке в начале статьи - данный алгоритм также учитывает и те разделы, который не имеют подразделов, а являются листьями на первом же уровне вложенности.
Ну и напоследок, алгоритм вывода дерева, начиная с конкретного узла, или всего дерева целиком:
function ShowElementsTree($category_arr, $parent_id)
{
if (intval($parent_id) > 0) {
if (isset($category_arr[$parent_id])) {
foreach ($category_arr[$parent_id]['CHILDS'] as $value) { // Обходим
echo "<div style=\"margin-left:" . ($value['DEPTH_LEVEL'] * 25) . "px;\">" . $value['ID'] . '. ' . $value['NAME'] . ' (' . $value['ELEMENT_CNT'] . ')' . "</div>";
echo "<div style=\"margin-left:" . ($value['DEPTH_LEVEL'] * 35) . "px;\">";
// тут выводим какие-то дополнительные данные о разделе
echo "</div>";
if (count($category_arr[$value["ID"]]['CHILDS']) > 0) {
//Рекурсивно вызываем эту же функцию, но с новым $parent_id
self::ShowElementsTree($category_arr, $value["ID"]);
} else {
//Выводим листик
}
}
}
} else {
foreach ($category_arr as $parent_id => $arItems) {
if (isset($category_arr[$parent_id])) {
$value = $category_arr[$parent_id];
echo "<div>" . $value['ID'] . '. ' . $value['NAME'] . ' (' . $value['ELEMENT_CNT'] . ')' . "</div>";
foreach ($category_arr[$parent_id]['CHILDS'] as $value) { //Обходим
echo "<div style=\"margin-left:" . ($value['DEPTH_LEVEL'] * 25) . "px;\">" . $value['ID'] . '. ' . $value['NAME'] . ' (' . $value['ELEMENT_CNT'] . ')' . "</div>";
echo "<div style=\"margin-left:" . ($value['DEPTH_LEVEL'] * 35) . "px;\">";
// тут выводим какие-то дополнительные данные о разделе
echo "</div>";
if (count($category_arr[$value["ID"]]['CHILDS']) > 0) {
// Рекурсивно вызываем эту же функцию, но с новым $parent_id
self::ShowElementsTree($category_arr, $value["ID"]);
} else {
//Выводим листик
}
}
}
}
}
}
Таким образом, если нужно вывести все дерево, вызываем функцию:
ShowElementsTree($map_sec,'');
а для того, чтобы вывести ветку только для одного раздела, вторым параметром передаем этот раздел.
Надеюсь, кому-то кроме меня этот алгоритм будет полезен ...
Всем легкого кода!
UPDATE 2015-09-29: Понадобилось тут мне дерево разделов в формате массива, а не в формате echo-публикаций. Вот родилась новая функция:
function GetSectionsTreeArray(&$category_arr, $parent_id){
$arResult = array();
if (intval($parent_id) > 0) {
if (isset($category_arr[$parent_id])) {
foreach ($category_arr[$parent_id]['CHILDS'] as $value) {
if (count($category_arr[$value["ID"]]['CHILDS']) > 0) {
//Рекурсивно вызываем эту же функцию, но с новым $parent_id
$value['CHILDS'] = self::GetSectionsMenu($category_arr, $value["ID"]);
}
$arResult[$value["ID"]] = $value;
}
}
} else {
foreach ($category_arr as $parent_id => $arItems) {
if (isset($category_arr[$parent_id])) {
$value = $category_arr[$parent_id];
if(intval($value['DEPTH_LEVEL']) > 1) continue;
foreach ($category_arr[$parent_id]['CHILDS'] as $value2) {
if (count($category_arr[$value2["ID"]]['CHILDS']) > 0) {
$value2['CHILDS'] = self::GetSectionsMenu($category_arr, $value2["ID"]);
}
$value['CHILDS'][$value2["ID"]] = $value2;
}
$arResult[$value["ID"]] = $value;
}
}
}
return $arResult;
}
