Bitrix получить дерево разделов

Как вывести древовидную структуру разделов каталога с элементами из Битрикса в csv?

Понадобилось на одном из проектов рекурсивно вывести древовидную структуру разделов каталога, а также все вложенные элементы в csv файл.

Заказчик просил именно древовидную структуру и именно Excel. Поэтому вложенные разделы находятся на следующей от родительской колонки, также как и вложенные элементы

Наглядность немного страдает, когда есть вложенные разделы и товары одновременно, но заказчкика это устроило. Также, чтобы их различать у товаров вначале я добавил символ «-«

Вообще вывод можно допилить как угодно, главное иметь основную подготовку разделов и товаров к выводу.

Я использовал наработки Бедросовой Юлии и Поповича Алексея, немного адаптировав их под свои нужды получился такой скрипт:

global $arSectElements, $maxDepth; $maxDepth = 0; // максимальная глубина каталога $map = array(); $arParams[«IBLOCK_MAP_ID»] = 1; // — ID инфоблока // собираем товары, ключ — айдишник раздела $resEl = CIBlockElement::GetList(array(),array(«IBLOCK_ID»=>37, «ACTIVE»=>»Y»),false,false,array(«ID»,»NAME»,»IBLOCK_SECTION_ID»)); while($ob = $resEl->Fetch()) < $ob["NAME"] = str_replace(";","",$ob["NAME"]); // у меня были в некоторых товарах ; поэтому пришлось их вырезать $arSectElements[$ob["IBLOCK_SECTION_ID"]][] = $ob; >// получаем все разделы и смотрим максимальный уровень вложенности if(isset($arParams[«IBLOCK_MAP_ID»]))< $arFilter = Array( 'IBLOCK_ID'=>$arParams[«IBLOCK_MAP_ID»], ‘GLOBAL_ACTIVE’=>’Y’ ); $db_list = CIBlockSection::GetList(Array(«left_margin»=>»asc»), $arFilter, true); while($ar_result = $db_list->GetNext()) < $map[$ar_result['ID']]=$ar_result; if($maxDepth < $ar_result["DEPTH_LEVEL"]) $maxDepth = $ar_result["DEPTH_LEVEL"]; >> $maxDepth += 1; // добавляем уровень вложенности т.к. еще товары выводятся // Подготавливаем массив для удобной рекурсии $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]['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’], «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’], «IBLOCK_SECTION_ID» => $val[‘IBLOCK_SECTION_ID’], ); > > > // Сама рекурсивная функция вывода function ShowElementsTree($category_arr, $parent_id, $handle) < global $arSectElements, $maxDepth; // чтобы были тут видны (можно через параметры функции передавать) if (intval($parent_id) >0) < if (isset($category_arr[$parent_id])) < foreach ($category_arr[$parent_id]['CHILDS'] as $value) // Обходим < fwrite($handle, str_repeat(";", $value['DEPTH_LEVEL'] - 1) . $value['NAME'] . str_repeat(";", $maxDepth - $value['DEPTH_LEVEL'])."\r\n"); if (count($category_arr[$value["ID"]]['CHILDS']) >0) < //Рекурсивно вызываем эту же функцию, но с новым $parent_id ShowElementsTree($category_arr, $value["ID"], $handle); >else <> // товары if(!empty($arSectElements[$value[«ID»]])) < foreach($arSectElements[$value["ID"]] as $elem) < fwrite($handle, str_repeat(";", $value['DEPTH_LEVEL']) . " - ".$elem['NAME'] . str_repeat(";", ($maxDepth-$value['DEPTH_LEVEL'] + 1))."\r\n"); >> > > > else < foreach ($category_arr as $parent_id =>$arItems) < if (isset($category_arr[$parent_id])) < $value = $category_arr[$parent_id]; fwrite($handle, $value['NAME'] . str_repeat(";", ($maxDepth-$value['DEPTH_LEVEL']))."\r\n"); foreach ($category_arr[$parent_id]['CHILDS'] as $value) //Обходим < fwrite($handle, str_repeat(";", $value['DEPTH_LEVEL'] - 1) . $value['NAME'] . str_repeat(";", ($maxDepth-$value['DEPTH_LEVEL']))."\r\n"); if (count($category_arr[$value["ID"]]['CHILDS']) >0) < // Рекурсивно вызываем эту же функцию, но с новым $parent_id ShowElementsTree($category_arr, $value["ID"], $handle); >else <> // товары if(!empty($arSectElements[$value[«ID»]])) < foreach($arSectElements[$value["ID"]] as $elem) < fwrite($handle, str_repeat(";", $value['DEPTH_LEVEL'] ) . " - ".$elem['NAME'] . str_repeat(";", ($maxDepth-$value['DEPTH_LEVEL'] + 1))."\r\n"); >> > // товары if(!empty($arSectElements[$value[«ID»]])) < foreach($arSectElements[$value["ID"]] as $elem) < fwrite($handle, str_repeat(";", $value['DEPTH_LEVEL'] ). " - ".$elem['NAME'] . str_repeat(";", ($maxDepth-$value['DEPTH_LEVEL']+1))."\r\n"); >> > > > return $csv_str; > $filename = ‘/home/bitrix/ПУТЬ_ДО_ФАЙЛА/pnx.csv’; // Вначале давайте убедимся, что файл существует и доступен для записи. if (is_writable($filename)) < if (!$handle = fopen($filename, 'w')) < echo "Не могу открыть файл ($filename)"; exit; >$csv = ShowElementsTree($map_sec,false, $handle); // Записываем $somecontent в наш открытый файл. if (fwrite($handle, $somecontent) === FALSE) < echo "Не могу произвести запись в файл ($filename)"; exit; >fclose($handle); > else

Читайте также:  Сок дерева грецкого ореха

Источник

Получение иерархии разделов

Приведу небольшой примерчик как одним запросом и одним циклом получить иерархию разделов в виде:

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

Источник

GetList

Возвращает список разделов, отсортированных в порядке arOrder по фильтру arFilter. Нестатический метод.

Смотрите также

Параметры вызова

  • id — код раздела;
  • section — код родительской раздела;
  • name — название раздела;
  • code — символьный код раздела;
  • active — активности раздела;
  • left_margin — левая граница;
  • depth_level — глубина вложенности (начинается с 1);
  • sort — индекс сортировки;
  • created — по времени создания раздела;
  • created_by — по идентификатору создателя раздела;
  • modified_by — по идентификатору пользователя изменившего раздел;
  • element_cnt — количество элементов в разделе, работает только если bIncCnt = true;
  • timestamp_x — по времени последнего изменения.
  • asc — по возрастанию;
  • desc — по убыванию.
  • ACTIVE — фильтр по активности (Y|N);
  • GLOBAL_ACTIVE — фильтр по активности, учитывая активность вышележащих разделов (Y|N);
  • NAME — по названию (можно искать по шаблону [%_]);
  • CODE — по символьному коду (по шаблону [%_]);
  • XML_ID или EXTERNAL_ID — по внешнему коду (по шаблону [%_]);
  • SECTION_ID — по коду раздела-родителя (если указать false, то будут возвращены корневые разделы);
  • DEPTH_LEVEL — по уровню вложенности (начинается с 1);
  • LEFT_BORDER, RIGHT_BORDER — по левой и правой границе (используется, когда необходимо выбрать некий диапазон разделов, см. пример №4);
  • LEFT_MARGIN, RIGHT_MARGIN — по положению в дереве (используется, когда необходима выборка дерева подразделов, см. пример №4);
  • ID — по коду раздела;
  • IBLOCK_ID — по коду родительского информационного блока. Обязателен, если нужно получить пользовательское свойство;
  • IBLOCK_ACTIVE — по активности родительского информационного блока;
  • IBLOCK_NAME — по названию информационного блока (по шаблону [%_]);
  • IBLOCK_TYPE — по типу информационного блока (по шаблону [%_]);
  • IBLOCK_CODE по символьному коду информационного блока (по шаблону [%_]);
  • IBLOCK_XML_ID или IBLOCK_EXTERNAL_ID — по внешнему коду информационного блока (по шаблону [%_]);
  • TIMESTAMP_X — по времени последнего изменения;
  • DATE_CREATE — по времени создания;
  • MODIFIED_BY — по коду пользователя изменившему раздел;
  • CREATED_BY — по содателю;
  • SOCNET_GROUP_ID — по привязке к группе Социальной сети;
  • MIN_PERMISSION — фильтр по правам доступа, по умолчанию принимает R (уровень доступа Чтение);
  • CHECK_PERMISSIONS — если установлено значение «N», то проверки прав не происходит;
  • PERMISSIONS_BY — фильтрация по правам произвольного пользователя. Значение — ID пользователя или 0 (неавторизованный).
  • PROPERTY по значениям свойств внутрилежащих элементов, PROPERTY — массив вида Array(«код свойства»=>»значение», . ).
  • HAS_ELEMENT — по наличию элемента. Используется в компоненте catalog.detail.

Значения фильтра одиночное значение или массив.

Важно! Чтобы фильтрация выполнялась по пользовательским свойствам, необходимо обязательно передавать в фильтр IBLOCK_ID. Само свойство надо указывать в виде UF_.

  • ELEMENT_SUBSECTIONS — подсчитывать элементы вложенных подразделов или нет (Y|N). По умолчанию Y;
  • CNT_ALL — подсчитывать еще неопубликованные элементы (Y|N). По умолчанию N. Актуально при установленном модуле документооборота;
  • CNT_ACTIVE — при подсчете учитывать активность элементов (Y|N). По умолчанию N. Учитывается флаг активности элемента ACTIVE и даты начала и окончания активности.

Примечание: в случае если в фильтре есть ключ PROPERTY то в количестве элементов вернется то значение, которое попадает под этот фильтр по значению свойств.

  • ID — ID группы информационного блока.
  • CODE — Символьный идентификатор.
  • EXTERNAL_ID или XML_ID — Внешний код.
  • IBLOCK_ID — ID информационного блока.
  • IBLOCK_SECTION_ID — ID группы родителя, если не задан то группа корневая.
  • TIMESTAMP_X — Дата последнего изменения параметров группы.
  • SORT — Порядок сортировки (среди групп внутри одной группы-родителя).
  • NAME — Наименование группы.
  • ACTIVE — Флаг активности (Y|N)
  • GLOBAL_ACTIVE — Флаг активности, учитывая активность вышележащих (родительских) групп (Y|N). Вычисляется автоматически (не может быть изменен вручную).
  • PICTURE — Код картинки в таблице файлов.
  • DESCRIPTION — Описание группы.
  • DESCRIPTION_TYPE — Тип описания группы (text/html).
  • LEFT_MARGIN — Левая граница группы. Вычисляется автоматически (не устанавливается вручную).
  • RIGHT_MARGIN — Правая граница группы. Вычисляется автоматически (не устанавливается вручную).
  • DEPTH_LEVEL — Уровень вложенности группы. Начинается с 1. Вычисляется автоматически (не устанавливается вручную).
  • SEARCHABLE_CONTENT Содержимое для поиска при фильтрации групп. Вычисляется автоматически. Складывается из полей NAME и DESCRIPTION (без html тэгов, если DESCRIPTION_TYPE установлен в html).
  • SECTION_PAGE_URL — Шаблон URL-а к странице для детального просмотра раздела. Определяется из параметров информационного блока. Изменяется автоматически.
  • MODIFIED_BY — Код пользователя, в последний раз изменившего элемент.
  • DATE_CREATE — Дата создания элемента.
  • CREATED_BY — Код пользователя, создавшего элемент.
  • DETAIL_PICTURE — Код картинки в таблице файлов для детального просмотра.
  • bShowAll — разрешить вывести все элементы при постраничной навигации;
  • iNumPage — номер страницы при постраничной навигации;
  • nPageSize — количество элементов на странице при постраничной навигации;
  • nTopCount — ограничить количество возвращаемых методом записей сверху значением этого ключа (ключ доступен с версии 15.5.5 ).

Возвращаемое значение

Примечание №1: для вывода пользовательских свойств обязательно должен быть передан IBLOCK_ID и в arSelect код необходимых свойств UF_XXX. Если необходимо вывести все пользовательские свойства, то в arSelect необходимо передать UF_*.

Примечание №2: поле для сортировки left_margin, так называемая «сквозная» сортировка, высчитывается на основании поля sort, уровня вложенности и сортировкой верхнего уровня. Отличие полей sort и left_margin в том, что sort указывается пользователем, для сортировки разделов между собой в пределах одного раздела-родителя, а вычисляемое left_margin предназначено для сортировки во всем информационном блоке.

Дополнительно

Выбор пользовательских свойств разделов возможен только при передаче в ключ фильтра IBLOCK_ID одиночного значения.

Примеры использования

$arIBTYPE = CIBlockType::GetByIDLang($type, LANGUAGE_ID);
if($arIBTYPE!==false)
// выборка только активных разделов из инфоблока $IBLOCK_ID, в которых есть элементы
// со значением свойства SRC, начинающееся с https://
$arFilter = Array('IBLOCK_ID'=>$IBLOCK_ID, 'GLOBAL_ACTIVE'=>'Y', 'PROPERTY'=>Array('SRC'=>'https://%'));
$db_list = CIBlockSection::GetList(Array($by=>$order), $arFilter, true);
$db_list->NavStart(20);
echo $db_list->NavPrint($arIBTYPE["SECTION_NAME"]);
while($ar_result = $db_list->GetNext())
echo $ar_result['ID'].' '.$ar_result['NAME'].': '.$ar_result['ELEMENT_CNT'].'
';
>
echo $db_list->NavPrint($arIBTYPE["SECTION_NAME"]);
>
?>
//пример выборки дерева подразделов для раздела $rsParentSection = CIBlockSection::GetByID(ID_необходимой_секции); if ($arParentSection = $rsParentSection->GetNext()) < $arFilter = array('IBLOCK_ID' =>$arParentSection['IBLOCK_ID'],'>LEFT_MARGIN' => $arParentSection['LEFT_MARGIN'],' $arParentSection['RIGHT_MARGIN'],'>DEPTH_LEVEL' => $arParentSection['DEPTH_LEVEL']); // выберет потомков без учета активности $rsSect = CIBlockSection::GetList(array('left_margin' => 'asc'),$arFilter); while ($arSect = $rsSect->GetNext()) < // получаем подразделы >>
//в шаблоне меню, построенного по структуре инфоблока, менять ссылку на элемент, если заполнено пользовательское поле "­­ASC"), Array("IBLOCK_ID" => $uf_iblock_id, "ID" => $uf_section_id), false, $uf_name); if($uf_value = $uf_arresult->GetNext()): if(strlen($uf_value["UF_PAGE_LINK"]) > 0): //проверяем что поле заполнено $arItem["LINK"] = $uf_value["UF_PAGE_LINK"]; //подменяем ссылку и используем её в дальнейшем endif; endif; endif; ?>
//рассмотрим разницу использования фильтра по LEFT_MARGIN, RIGHT_MARGIN и LEFT_BORDER, RIGHT_BORDER //допустим, что у некоторого раздела LEFT_MARGIN (значение в базе) = 10, RIGHT_MARGIN (значение в базе) = 40 //в первом примере кода будет выбран как сам раздел, так и все его подразделы, //поскольку всегда LEFT_MARGIN раздела-потомка > LEFT_MARGIN раздела-родителя //и RIGHT_MARGIN раздела-потомка < RIGHT_MARGIN раздела-родителя $arFilter = array('IBLOCK_ID' =>10, 'LEFT_MARGIN' => 10, 'RIGHT_MARGIN' => 40); $rsSections = CIBlockSection::GetList(array('LEFT_MARGIN' => 'ASC'), $arFilter); while ($arSection = $rsSections->Fetch()) < echo htmlspecialcharsbx($arSection['NAME']).' LEFT_MARGIN: '.$arSection['LEFT_MARGIN'].' RIGHT_MARGIN: '.$arSection['RIGHT_MARGIN'].'&ltbr>'; > //во втором примере кода будет возвращена только одна запись - сам раздел $arFilter = array('IBLOCK_ID' => 10, 'LEFT_BORDER' => 10, 'RIGHT_BORDER' => 40); $rsSections = CIBlockSection::GetList(array('LEFT_MARGIN' => 'ASC'), $arFilter); while ($arSction = $rsSections->Fetch()) < echo htmlspecialcharsbx($arSection['NAME']).' LEFT_MARGIN: '.$arSection['LEFT_MARGIN'].' RIGHT_MARGIN: '.$arSection['RIGHT_MARGIN'].'
'; >

Источник

Оцените статью