Добро пожаловать на сайт <БагБД>, где вы можете задавать вопросы о программировании и разработке на Битрикс и Битрикс24, и получать быстрые и квалифицированные ответы от профессионалов!

Дерево из элементов и разделов

00 голосов
4
Добрый день!

Задача:

Необходимо выстроить дерево состоящее из элементов и разделов некоторого инфоблока, причем по принципу: "сначала каталоги, потом файлы":

Раздел 1
  Раздел 2
  Раздел 2
    Раздел 3
    Элемент 3
    Элемент 3
  Раздел 2
  Элемент 2
  Элемент 2
  .
  .
Элемент 1
.
.

Окончательный массив, аналогичен массиву пунктов меню.

Мое предварительное решение было таким:

1. Получаем список разделов ("LEFT_MARGIN" => "ASC")
2. Для каждого раздела получаем список его элементов
3. В дополнительном цикле собираем массив с нужной последовательностью элементов и разделов

Быть может существует более оптимальное решение? Например, какой-нибудь хитро построенный запрос, позволяющий получить все и сразу и в нужной последовательности :) Буду рад любым идеям
спросил 28 Ноя, 13 от Sturmwind (300 баллов)

4 Ответы

00 голосов
ответил 23 Янв, 14 от sickmind (4,660 баллов)
00 голосов
Судя по всему, нет. Прежде всего, метод не позволяет выбрать пользовательские поля разделов, и если я правильно понимаю, существенного выигрыша от его использования в решении данной задачи я не получаю - те же два запроса, да еще и с урезанными возможностями.. Впрочем, должен сказать, что я и не надеялся сократить количество запросов, а вот избавиться от последнего цикла хотелось бы... Просто предположил, что данная задача уже кем-то решалась, и был найден оптимальный подход
ответил 11 Май, 14 от Sturmwind (300 баллов)
00 голосов
1. Сформировать массив секций (по LEFT_MARGIN), ключами массива сделать ID секции.
2. Забить ID секций в массив.
3. Запросить список элементов, передав в фильтре секции.
4. Профетчить элементы, присоединяя каждый в нужную секцию массива секций по ключу.
5. Нарисовать результирующий массив в шаблоне.
ответил 07 Сен, 14 от Eddie (2,060 баллов)
00 голосов
Спасибо, Дмитрий! В итоге, что-то в этом роде у меня и получилось.. правда, реальное дерево несколько сложнее, чем мной описано выше. Приведу здесь сокращенный код того что вышло, может быть кому-то пригодится:

Код
/***********
 * Разделы *
 ***********/

$rs_section = CIBlockSection::GetList(Array("LEFT_MARGIN" => "ASC"), $arFilter, true, Array("UF_*"));
while($ar_section = $rs_section->Fetch())
{
   $arResult["SECTIONS"][$ar_section["ID"]] = $ar_section;
}

/************
 * Элементы *
 ************/

$rs_element = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
while($ar_element = $rs_element->GetNext(false, false))
{   
   if(array_key_exists($ar_element["IBLOCK_SECTION_ID"], $arResult["ELEMENTS"]))
   {
      $arResult["ELEMENTS"][$ar_element["IBLOCK_SECTION_ID"]][$ar_element["ID"]] = $ar_element;
   }
   else
   {
      $arResult["ELEMENTS"][$ar_element["IBLOCK_SECTION_ID"]] = Array();
      $arResult["ELEMENTS"][$ar_element["IBLOCK_SECTION_ID"]][$ar_element["ID"]] = $ar_element;
   }   
}

/*********************
 * Построение дерева *
 *********************/

$previousLevel = 0;
$arStack = Array();
foreach($arResult["SECTIONS"] as $arSection)
{
   if($previousLevel && $arSection["DEPTH_LEVEL"] <= $previousLevel)
   {      
      $delta = $previousLevel - $arSection["DEPTH_LEVEL"];
      for($i = 0; $i < ($delta + 1); $i++)
      {
         $section_id = array_pop($arStack);
         if(array_key_exists($section_id, $arResult["ELEMENTS"]))
         {   
            foreach($arResult["ELEMENTS"][$section_id] as $arElement)
            {
               $arResult["ITEMS"][] = $arElement;
            }
         }
      }
   }

   $arResult["ITEMS"][] = $arSection;   
   
   $arStack[] = $arSection["ID"];   
   $previousLevel = $arSection["DEPTH_LEVEL"];   
}
ответил 13 Янв, 15 от Sturmwind (300 баллов)

Похожие вопросы

0 голосов
3 ответов
0 голосов
5 ответов
0 голосов
1 ответ
0 голосов
6 ответов
0 голосов
3 ответов