- Как вывести из инфоблока определенные разделы и вложенные элементы в виде дерева?
- Получение иерархии разделов
- Форум
- Центр поддержки
- Продукты
- Управление сайтом
- Битрикс24
- Интернет-магазин + CRM
- Решения
- Для интернет-магазинов
- Каталог готовых решений
- Внедрение
- Выбрать партнера
- Проверить партнера
- Стать партнером
- Построение дерева категорий в Bitrix. Left-margin и Right-margin.
Как вывести из инфоблока определенные разделы и вложенные элементы в виде дерева?
1. Делаешь выборку разделов по ИД — $idSections = array(104,105,106); // ID разделов
А элементы получаешь все, без ограничений. Я так понимаю элементы тоже нужны только для указанных разделов, тогда в массив $arFilter для CIBlockElement::GetList стоит добавить это ограничение
$arFilter = array("IBLOCK_ID" => $IBLOCK_ID, "ACTIVE_DATE" => "Y", "ACTIVE" => "Y", 'IBLOCK_SECTION_ID' => $idSections);
И вот это дело array(«nPageSize» => 100) тоже убери, хитрец)) — поставь false
2. Лично от меня пожелание, если пишешь в процедурном стиле, когда делаешь выборку собирай массив с ключами = ID, например вместо
while ($sectRes = $dbResSect->GetNext())
while ($sectRes = $dbResSect->GetNext())
3. Все дело в коде под комментариями
// Находим все разделы элемента и собираем их в массив // Собираем массив из разделов и элементов
Запросы в цикле — это плохо, больше элементов в цикле = больше запросов
Итого меняем три блока
1. Добавляем ID в ключи
// Получаем разделы и собираем их в массив while ($sectRes = $dbResSect->GetNext())
2. Добавляем разделы в фильтр, убираем nPageSize и добавляем ключи = ID
// Формируем массив элементов по фильтру //. $arFilter = array("IBLOCK_ID" => $IBLOCK_ID, 'IBLOCK_SECTION_ID' => $idSections, "ACTIVE_DATE" => "Y", "ACTIVE" => "Y"); $res = CIBlockElement::GetList(array("ID" => "ASC"), $arFilter, false, false, $arSelect); while ($el = $res->Fetch())
3. Меняем проблемный блок, т.е. все что ниже комментария // Находим все разделы элемента и собираем их в массив
$elementIdsBySectionIds = []; $iterator = \Bitrix\Iblock\SectionElementTable::getList([ 'select' => ['IBLOCK_SECTION_ID', 'IBLOCK_ELEMENT_ID'], 'filter' => ['IBLOCK_SECTION_ID' => $idSections] ]); while($row = $iterator->fetch()) < $elementIdsBySectionIds[$row['IBLOCK_SECTION_ID']][$row['IBLOCK_ELEMENT_ID']] = $row['IBLOCK_ELEMENT_ID']; >// здесь как раз пригодятся ключи = ID foreach($elementIdsBySectionIds as $sectionId => $elementIds) < foreach($elementIds as $elementId) < if(isset($arResult["ITEMS"][$elementId])) < $arSections[$sectionId]['ITEMS'][] = $arResult["ITEMS"][$elementId]; >> > $arResult = $arSections;
CModule::IncludeModule('iblock'); //Подключаем модуль "Информационные блоки" // Параметры $IBLOCK_ID = 7; // ID ифноблока $idSections = array(104,105,106); // ID разделов // Формируем список разделов по фильтру $dbResSect = CIBlockSection::GetList( array("SORT" => 'asc'), // Параметры сортировки array( "IBLOCK_ID" => $IBLOCK_ID, // ID инфоблока "ID" => $idSections, // Массив разделов ), false, array("ID", "NAME", "UF_ITEMPROP") // Выбираем необходимые поля разделов. ); // Получаем разделы и собираем их в массив while ($sectRes = $dbResSect->GetNext()) < $arSections[$sectRes['ID']] = $sectRes; >// Формируем массив элементов по фильтру $arResult = []; $arSelect = Array( "ID", "NAME", "IBLOCK_ID", "IBLOCK_SECTION_ID", "PROPERTY_FILE", "PROPERTY_ITEMPROP", ); $arFilter = array("IBLOCK_ID" => $IBLOCK_ID, 'IBLOCK_SECTION_ID' => $idSections, "ACTIVE_DATE" => "Y", "ACTIVE" => "Y"); $res = CIBlockElement::GetList(array("ID" => "ASC"), $arFilter, false, false, $arSelect); while ($el = $res->Fetch()) < $arResult["ITEMS"][$el['ID']] = $el; >$elementIdsBySectionIds = []; $iterator = \Bitrix\Iblock\SectionElementTable::getList([ 'select' => ['IBLOCK_SECTION_ID', 'IBLOCK_ELEMENT_ID'], 'filter' => ['IBLOCK_SECTION_ID' => $idSections] ]); while($row = $iterator->fetch()) < $elementIdsBySectionIds[$row['IBLOCK_SECTION_ID']][$row['IBLOCK_ELEMENT_ID']] = $row['IBLOCK_ELEMENT_ID']; >foreach($elementIdsBySectionIds as $sectionId => $elementIds) < foreach($elementIds as $elementId) < if(isset($arResult["ITEMS"][$elementId])) < $arSections[$sectionId]['ITEMS'][] = $arResult["ITEMS"][$elementId]; >> > $arResult = $arSections;
UPD
На моей выборке, примерно 15 товаров, стало меньше на 53 запроса к БД
Источник
Получение иерархии разделов
Приведу небольшой примерчик как одним запросом и одним циклом получить иерархию разделов в виде:
Array ( [ROOT] => Array ( [CHILD] => Array ( [12] => Array ( [ID] => 12 [~ID] => 12 [NAME] => Раздел с ид 12 [~NAME] => Раздел с ид 12 [DEPTH_LEVEL] => 1 [~DEPTH_LEVEL] => 1 [CHILD] => Array ( [63] => Array ( [ID] => 63 [~ID] => 63 . [CHILD] => Array ( . ) ) . [63] => Array ( [ID] => 63 [~ID] => 63 . ) . ) ) . ) ) )
На мой взгляд, с такой структурой работать в большинстве случаев удобнее, чем со списком, отсортированном по LEFT_MARGIN
$arFilter = array( 'ACTIVE' => 'Y', 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'GLOBAL_ACTIVE'=>'Y', ); $arSelect = array('IBLOCK_ID','ID','NAME','DEPTH_LEVEL','IBLOCK_SECTION_ID'); $arOrder = array('DEPTH_LEVEL'=>'ASC','SORT'=>'ASC'); $rsSections = CIBlockSection::GetList($arOrder, $arFilter, false, $arSelect); $sectionLinc = array(); $arResult['ROOT'] = array(); $sectionLinc[0] = &$arResult['ROOT']; while($arSection = $rsSections->GetNext()) < $sectionLinc[intval($arSection['IBLOCK_SECTION_ID'])]['CHILD'][$arSection['ID']] = $arSection; $sectionLinc[$arSection['ID']] = &$sectionLinc[intval($arSection['IBLOCK_SECTION_ID'])]['CHILD'][$arSection['ID']]; >unset($sectionLinc);
Если мы получаем только активные элементы, то важно указать в фильтре ‘GLOBAL_ACTIVE’=>’Y’, иначе мы можем получить активный элемент с неактивным предком, и его некуда будет определить в иерархию.
В $arSelect нужно не забыть указать IBLOCK_SECTION_ID, иначе иерархию построить не получится
Первое поле в сортировке $arOrder должно быть ‘DEPTH_LEVEL’=>’ASC’, так как иерархия строится от предков к потомкам
Построение иерархии происходит через массив ссылок $sectionLinc
Источник
Форум
Необходимо выстроить дерево состоящее из элементов и разделов некоторого инфоблока, причем по принципу: «сначала каталоги, потом файлы»:
Раздел 1
Раздел 2
Раздел 2
Раздел 3
Элемент 3
Элемент 3
Раздел 2
Элемент 2
Элемент 2
.
.
Элемент 1
.
.
Окончательный массив, аналогичен массиву пунктов меню.
Мое предварительное решение было таким:
1. Получаем список разделов («LEFT_MARGIN» => «ASC»)
2. Для каждого раздела получаем список его элементов
3. В дополнительном цикле собираем массив с нужной последовательностью элементов и разделов
Быть может существует более оптимальное решение? Например, какой-нибудь хитро построенный запрос, позволяющий получить все и сразу и в нужной последовательности Буду рад любым идеям
Судя по всему, нет. Прежде всего, метод не позволяет выбрать пользовательские поля разделов, и если я правильно понимаю, существенного выигрыша от его использования в решении данной задачи я не получаю — те же два запроса, да еще и с урезанными возможностями.. Впрочем, должен сказать, что я и не надеялся сократить количество запросов, а вот избавиться от последнего цикла хотелось бы. Просто предположил, что данная задача уже кем-то решалась, и был найден оптимальный подход
1. Сформировать массив секций (по LEFT_MARGIN), ключами массива сделать ID секции.
2. Забить ID секций в массив.
3. Запросить список элементов, передав в фильтре секции.
4. Профетчить элементы, присоединяя каждый в нужную секцию массива секций по ключу.
5. Нарисовать результирующий массив в шаблоне.
Компонент (и.с.) — существительное мужского рода (ГОСТ 34.003-90).
Спасибо, Дмитрий! В итоге, что-то в этом роде у меня и получилось.. правда, реальное дерево несколько сложнее, чем мной описано выше. Приведу здесь сокращенный код того что вышло, может быть кому-то пригодится:
/*********** * Разделы * ***********/ $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"] > > > $arResult["ITEMS"][] = $arSection; $arStack[] = $arSection["ID"]; $previousLevel = $arSection["DEPTH_LEVEL"]; >
Я выпустил компонент для построения дерева инфоблока из разделов и элементов — http://marketplace.1c-bitrix.ru/solutions/twozebras.infoblocktree/
/*********** * Разделы * ***********/ $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"] > > > $arResult["ITEMS"][] = $arSection; $arStack[] = $arSection["ID"]; $previousLevel = $arSection["DEPTH_LEVEL"]; >
А зачем приравнивать $previousLevel = 0 ? В данном коде у вас дерево не построется! Поменял на 1, и у меня заработало. Спасибо!
Центр поддержки
Продукты
Управление сайтом
Битрикс24
Интернет-магазин + CRM
Решения
Для интернет-магазинов
Каталог готовых решений
Внедрение
Выбрать партнера
Проверить партнера
Стать партнером
1С-Битрикс http://www.1c-bitrix.ru Общие вопросы info@1c-bitrix.ru Приобретение и лицензирование продуктов : sales@1c-bitrix.ru Маркетинг/мероприятия/PR marketing@1c-bitrix.ru Партнерская программа partners@1c-bitrix.ru Мы работаем с 10:00 до 19:00 по московскому времени. Офис в Москве 127287 Россия Московская область Москва 2-я Хуторская улица дом 38А строение 9 Офис в Калининграде +7 (4012) 51-05-64 Офис в Калининграде 236001 Россия Калининградская область Калининград Московский проспект 261 Офис в Киеве ukraine@1c-bitrix.ru Телефон в Киеве +3 (8044)221-55-33 Офис в Киеве 01033 Украина Калининградская область Киев улица Шота Руставели 39/41 офис 1507
© 2001-2023 «Битрикс», «1С-Битрикс». Работает на 1С-Битрикс: Управление сайтом. Политика конфиденциальности
Источник
Построение дерева категорий в Bitrix. Left-margin и Right-margin.
Обычно эти данные автоматически генерируются ядром Битрикса, при заполнении разделов из администраторской панели. Но в нашем случае, был перенос из другой CMS. Для того что бы понять как правильно указать эти параметры, разберем на конкретных примерах.
DEPTH_LEVEL = 1.
Только родительские разделы.
Итак, в этом примере у нас есть 4 корневых раздела, у которых DEPTH_LEVEL = 1. Как видно на картинке, LEFT_MARGIN и RIGHT_MARGIN меняются в зависимости от расположения раздела.
DEPTH_LEVEL = 1-3.
Теперь у нас есть древовидный каталог, с самым глубоким уровнем вложенности 3. Более глубокую вложенность я рассматривать не буду, так как этот пример хорошо показывает основной принцип построения.
У нас все так же присутствует 4 корневых раздела, но вот LEFT_MARGIN и RIGHT_MARGIN сильно изменились. Если внимательно посмотреть на раздел «Музыка», то RIGHT_MARGIN уже 8, а не 2 как это было в предыдущем примере. Так же и LEFT_MARGIN меняется у дочерних разделов. Это хорошо видно на разделе «Приколы», где уровень вложенности равен 3м.
По сути, определение этих параметров остается таким же, мы последовательно идем по всем разделам, включая вложенные, только RIGHT_MARGIN у родительского уже будет равен: RIGHT_MARGIN последнего вложенного раздела увеличенного на единицу.
Источник