Skip to content

D7 в инфоблоках. Разделы.

Содержание


Устаревший подход

\CIBlockSection::GetList Много лет для получения элементов, разделов и т.п. Bitrix использовал классические методы `GetList` классов `CIBlockElement`, `CIBlockSection` и т.п.

Постараемся решить задачу

Получить список активных разделов инфоблока. Для выборки потребуются поля

  • ID
  • NAME
  • CODE
  • PICTURE и путь до файла
  • Детальную ссылку раздела, состоящую из "пути" символьных кодов всех родительских разделов + символьный код самого раздела
  • Хлебные крошки для каждого раздела
  • Свойство типа строка UF_OFFER_COUNT
  • Свойство типа список UF_FILTER_TYPE (Значение списка)
  • Названия элементов множественного свойства типа привязка к элементам инфоблока UF_FAQ_ID
  • Количество активных элементов разделе

Стандартный запрос на получение разделов инфоблока с его свойствами.

php
$rsResult = \CIBlockSection::GetList(
			array('SORT'=>"ASC"), //Сортировка
			array("IBLOCK_ID"=>IBLOCK_CATALOG_CATALOG,'ACTIVE'=>'Y'),//Фильтр
			true, //Количество элементов в разделе
			array('ID','NAME','CODE','PICTURE','SECTION_PAGE_URL','UF_OFFER_COUNT','UF_FILTER_TYPE','UF_FAQ_ID'), // Поля выбора
			false, //Навигация
		);
mysql
SELECT DISTINCT BS.ID AS ID,
BS.NAME AS NAME,
BS.CODE AS CODE,
BS.PICTURE AS PICTURE,
B.SECTION_PAGE_URL AS SECTION_PAGE_URL,
BS.XML_ID AS EXTERNAL_ID,
B.IBLOCK_TYPE_ID AS IBLOCK_TYPE_ID,
BS.IBLOCK_ID AS IBLOCK_ID,
B.CODE AS IBLOCK_CODE,
B.XML_ID AS IBLOCK_EXTERNAL_ID,
BS.GLOBAL_ACTIVE AS GLOBAL_ACTIVE,
BS.SORT AS SORT,COUNT(DISTINCT BE.ID) as ELEMENT_CNT, BUF.UF_OFFER_COUNT, BUF.UF_FILTER_TYPE, BUF.UF_FAQ_ID
				FROM b_iblock_section BS
					INNER JOIN b_iblock B ON BS.IBLOCK_ID = B.ID
LEFT JOIN b_uts_iblock_6_section BUF ON BUF.VALUE_ID = BS.ID
					INNER JOIN b_iblock_section BSTEMP ON BSTEMP.IBLOCK_ID = BS.IBLOCK_ID
						LEFT JOIN b_iblock_section_element BSE ON BSE.IBLOCK_SECTION_ID=BSTEMP.ID
					LEFT JOIN b_iblock_element BE ON (BSE.IBLOCK_ELEMENT_ID=BE.ID
						AND ((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL )
						AND BE.IBLOCK_ID = BS.IBLOCK_ID
				)
				)
				WHERE 1=1
					AND BSTEMP.IBLOCK_ID = BS.IBLOCK_ID
						AND BSTEMP.LEFT_MARGIN >= BS.LEFT_MARGIN
						AND BSTEMP.RIGHT_MARGIN <= BS.RIGHT_MARGIN
				AND  ((((BS.IBLOCK_ID = '6'))))
				AND  ((((BS.ACTIVE='Y'))))
				AND  ((((B.ID = '6'))))
			GROUP BY BS.ID, B.ID
				ORDER BY  BS.SORT asc

Как мы видим, тут отсутсвует ссылки на разделы (Они будут формироваться в цикле - запросы в цикле), количество элементов не учитывает активность, свойства UF_FILTER_TYPE и UF_FAQ_ID не отвечают условиям задачи.

Альтернативой этому подходу является использование запросов D7

Получение разделов D7. Классический подход.

Для выполнения такой же задачи обратимся к запросу битрикс \Bitrix\Main\ORM\Query\Query.

php
$obQuery = new \Bitrix\Main\ORM\Query\Query(\Bitrix\Iblock\Model\Section::compileEntityByIblock(IBLOCK_CATALOG_CATALOG));

Данный объект запроса \Bitrix\Main\ORM\Query\Query имеет следующие наиболее используемые методы:

  • getQuery - возвращает итогогой запрос в виде строки
  • setSelect - устанавливает поля для выборки
  • addSelect - добавление поля в выборку
  • setOrder - установка сортировки
  • addOrder - добавление сортировки
  • setGroup - установка группировки
  • addGroup - добавление группировки
  • where - установка фильтра
  • whereIn - установка фильтра IN
  • whereNotIn - установка фильтра NOT IN
  • whereLike - установка фильтра LIKE
  • whereNull - установка фильтра WHERE NULL
  • whereNotNull - установка фильтра WHERE NOT NULL
  • setLimit - установка ограничения выборки
  • setOffset - установки смещения ограничения выборки
  • exec - выполнение запроса
  • registerRuntimeField - добавление в запрос нового поля (Например, присоединение другой таблицы или вычисляемое поле MAX, COUNT и т.п.)

Основной запрос на получение разделов

Сформируем простой запрос на получение разделов

php
$obQuery = new \Bitrix\Main\ORM\Query\Query(\Bitrix\Iblock\Model\Section::compileEntityByIblock(IBLOCK_CATALOG_CATALOG));
$obQuery
    ->setSelect(array("ID","CODE", "NAME", "PICTURE"))
    ->where("IBLOCK_ID","=",IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true);

Метод where может принимать разное количество и разные типы параметров

Три параметра
  1. Название поля
  2. Условие (=, >, < , >=, <=, !=)
  3. Значение
Два параметра
  1. Название поля булевого типа. В терминах битрикса значение такого поля хранится в БД в виде строки Y/N
  2. Значение - булево true/false
Один параметр
  1. Вложенное условие \Bitrix\Main\ORM\Query\Query::filter(). Подробнее

Все три вызова идентичны и приведут к одному результату:

php
$obQuery
    ->setSelect(array("ID","CODE", "NAME", "PICTURE"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true);

$obQuery
    ->setSelect(array("ID","CODE", "NAME", "PICTURE"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE","=","Y");

$obQuery
    ->setSelect(array("ID","CODE", "NAME", "PICTURE"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where((
        \Bitrix\Main\ORM\Query\Query::filter()
        ->logic(ConditionTree::LOGIC_AND)
        ->where('ACTIVE',true)
    ));
mysql
    
SELECT
  `iblock_section`.`ID` AS `ID`,
  `iblock_section`.`CODE` AS `CODE`,
  `iblock_section`.`NAME` AS `NAME`,
  `iblock_section`.`PICTURE` AS `PICTURE`
FROM `b_iblock_section` `iblock_section`
WHERE `iblock_section`.`IBLOCK_ID` = 6 AND `iblock_section`.`ACTIVE` = 'Y'

  

Как видно из запроса у нет лишних сущностей и условий.

php
$rsResult = $obQuery->exec();
while ($arRow = $rsResult->fetch()) {
    //какие-то действия с массивом
}

Результат выборки:

php
array(4)
[
    "ID"      => string(3) "112"
    "CODE"    => string(20) "sredstva-dlya-ukhoda"
    "NAME"    => string(34) "Средства для ухода"
    "PICTURE" => string(4) "2446"
]

registerRuntimeField

php
public function registerRuntimeField($name, $fieldInfo = null)
  • $name - название поля (устаревшее)
  • $fieldInfo - описание поля - экземпляр класса \Bitrix\Main\ORM\Fields\Field

В качестве первого аргумента можно сразу подать описание поля $fieldInfo

Зачастую, в качестве $fieldInfo подается экземпляр 1одно из следующих классов:

  • \Bitrix\Main\ORM\Fields\Relations\Reference - присоединение таблицы
  • \Bitrix\Main\ORM\Fields\ExpressionField - вычисляемое поле (MAX, COUNT и т.п.)

Добавление полей в запрос

Путь к файлу

Для "вычисления" пути до файла поля PICTURE воспользуемся классом \Bitrix\Main\ORM\Fields\ExpressionField и MySql функцией CONCAT

При этом сам ID файла в поле PICTURE нам не нужен, так что удалим его из запроса

php
$obQuery
    ->setSelect(array("ID","CODE", "NAME"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true)
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "PICTURE_FILE",
              \Bitrix\Main\FileTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.PICTURE', 'ref.ID')
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->registerRuntimeField(
          new \Bitrix\Main\ORM\Fields\ExpressionField( //Сразу сформируем путь
              "PICTURE_FILE_SRC", //Название выражения
              'CONCAT("/upload/",%s, "/" ,%s)', //Функция MySql
              array('PICTURE_FILE.SUBDIR', 'PICTURE_FILE.FILE_NAME') //Значения шаблона подстановки
          )
    )
    ->addSelect("PICTURE_FILE_SRC");

В функции MySql допускается использование шаблонов подстановки %s, значения которых устанавливаются в массиве 3го аргумента по порядку использвания.

mysql
    
SELECT
	`iblock_section`.`ID` AS `ID`,
	`iblock_section`.`CODE` AS `CODE`,
	`iblock_section`.`NAME` AS `NAME`,
	CONCAT("/upload/",`iblock_section_picture_file`.`SUBDIR`, "/" ,`iblock_section_picture_file`.`FILE_NAME`) AS `PICTURE_FILE_SRC`
FROM `b_iblock_section` `iblock_section`
LEFT JOIN `b_file` `iblock_section_picture_file` ON `iblock_section`.`PICTURE` = `iblock_section_picture_file`.`ID`
WHERE `iblock_section`.`IBLOCK_ID` = 6 AND `iblock_section`.`ACTIVE` = 'Y'

  
php
array(4)
[
    "ID"               => string(3) "112"
    "CODE"             => string(20) "sredstva-dlya-ukhoda"
    "NAME"             => string(34) "Средства для ухода"
    "PICTURE_FILE_SRC" => string(55) "/upload/iblock/bfd/ggxmnog0amwahvb3cz4hhngmdjkwn3lw.png"
]

Свойства раздела UF_* типа строка

Специально регистрировать свойства раздела нет необходимости, они автоматически попадут в запрос

php
$obQuery
    ->setSelect(array("ID","CODE", "NAME", "PICTURE","UF_OFFER_COUNT"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true);
mysql
    
SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	`iblock_section6_uts_object`.`UF_OFFER_COUNT` AS `UF_OFFER_COUNT`,
	CONCAT("/upload/",`iblock_section6_picture_file`.`SUBDIR`, "/" ,`iblock_section6_picture_file`.`FILE_NAME`) AS `PICTURE_FILE_SRC`
FROM `b_iblock_section` `iblock_section6`
LEFT JOIN `b_file` `iblock_section6_picture_file` ON `iblock_section6`.`PICTURE` = `iblock_section6_picture_file`.`ID`
LEFT JOIN `b_uts_iblock_6_section` `iblock_section6_uts_object` ON `iblock_section6`.`ID` = `iblock_section6_uts_object`.`VALUE_ID`
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
    
  
php
array(4)
[
    "ID"             => string(3) "112"
    "CODE"           => string(20) "sredstva-dlya-ukhoda"
    "NAME"           => string(34) "Средства для ухода"
    "UF_OFFER_COUNT" => string(2) "10"
]

Свойства раздела UF_* типа список

Если просто добавить поле в выборку - мы получим ID значения, а не само значение. Для того, чтобы вывести значение списка, необходимо присоединить таблицу со значением списка b_user_field_enum

К сожалению, в ORM битрикса на данный момент нет такой таблицы, но мы можем добавить ее в свой проект с помощью инструмента Bitrix. Инструкция по добавлению таблицы

Назовем данную таблицу \Bitrix\User\FieldEnumTable. В основной запрос ID значения списка можно и не добавлять

php
$obQuery
    ->setSelect(array("ID","CODE", "NAME", "PICTURE"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true)
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FILTER_TYPE",
              \Bitrix\User\FieldEnumTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.UF_FILTER_TYPE', 'ref.ID')
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->addSelect("FILTER_TYPE.VALUE","FILTER_TYPE_VALUE")
mysql
    
SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	`iblock_section6`.`PICTURE` AS `PICTURE`,
	`iblock_section6_filter_type`.`VALUE` AS `FILTER_TYPE_VALUE`
FROM `b_iblock_section` `iblock_section6`
LEFT JOIN `b_uts_iblock_6_section` `iblock_section6_uts_object` ON `iblock_section6`.`ID` = `iblock_section6_uts_object`.`VALUE_ID`
LEFT JOIN `b_user_field_enum` `iblock_section6_filter_type` ON `iblock_section6_uts_object`.`UF_FILTER_TYPE` = `iblock_section6_filter_type`.`ID`
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
  
  
php
array(5)
[
    "ID"                => string(3) "112"
    "CODE"              => string(20) "sredstva-dlya-ukhoda"
    "NAME"              => string(34) "Средства для ухода"
    "PICTURE"           => string(4) "2446"
    "FILTER_TYPE_VALUE" => string(29) "Тип инструмента"
]

Свойства раздела UF_* типа привязка к элементу

Так же как и в случае со списком, в значении поля хранится ID элемента. Для того, чтобы получить не только ID, но и, напрмиер, название NAME, присоединим таблицу с элементами к запросу.

Скорее всего, в логике задачи предполагается, что нам нужны только активные элементы

Т.к. поле UF_FAQ_ID - множественное, то просто присоединив его к запросу мы не получим искомого результат. Все потому, что значения множественных пользовательских полей хранятся в БД особенным образом.

  1. Значение хранится в таблице значений b_uts_iblock_{ID ИБ}_section в виде сериализованного массива b_uts_iblock_section После выполнения запроса значение автоматически десирализуется и получим массив значений. Это удобно, когда в значениях хранятся, напрмиер, строки.
php
$obQuery
    ->setSelect(array("ID","CODE", "NAME", "UF_FAQ_ID"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true);
mysql
    
SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	`iblock_section6_uts_object`.`UF_FAQ_ID` AS `UF_FAQ_ID`
FROM `b_iblock_section` `iblock_section6`
LEFT JOIN `b_uts_iblock_6_section` `iblock_section6_uts_object` ON `iblock_section6`.`ID` = `iblock_section6_uts_object`.`VALUE_ID`
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
  
  
php
array(4)
[
    "ID"        => string(3) "112"
    "CODE"      => string(20) "sredstva-dlya-ukhoda"
    "NAME"      => string(34) "Средства для ухода"
    "UF_FAQ_ID" =>  array(2)
        [
            0 => int(6055)
            1 => int(5052)
        ]
]
  1. Значения хранятся в таблице b_utm_iblock_{ID ИБ}_section также как и значения множественных свойств элементов. b_utm_iblock_section В этой таблице
  • VALUE_ID - ID раздела
  • FIELD_ID - ID поля
  • VALUE - текстовое значение (для строк)
  • VALUE_INT - целочисленное значение (для чисел, привязок к элементам и разделам)
  • VALUE_DOUBLE - дробное значение (Для простых чисел)
  • VALUE_DATE - значение в виде даты (Для дат)

К сожалению, в ядре нет возможности получить ORM сущность этой таблицы. Сформируем ее самостоятельно.

php
$obUtmEntity = \Bitrix\Main\ORM\Entity::compileEntity(
    "b_utm_iblock_" . IBLOCK_CATALOG_CATALOG . "_section",
    array(
        'ID' => array(
            'data_type' => 'integer',
        ),
        'VALUE_ID' => array(
            'data_type' => 'integer',
        ),
        'FIELD_ID' => array(
            'data_type' => 'integer',
        ),
        'VALUE_INT' => array(
            'data_type' => 'integer',
        ),
    ),
    ['table_name' => "b_utm_iblock_" . IBLOCK_CATALOG_CATALOG . "_section"]
);

Для данного запроса нам не нужны поля VALUE, VALUE_DOUBLE и VALUE_DATE.

Также нам необходимо знать и ID свойства UF_FAQ_ID

php
//Получение свойства UF_FAQ_ID
$obFieldQuery = \Bitrix\Main\UserFieldTable::query();
$obFieldQuery
    ->setSelect(array('ID'))
    ->where('ENTITY_ID', "=", "IBLOCK_" . IBLOCK_CATALOG_CATALOG . "_SECTION")
    ->where('FIELD_NAME', '=', 'UF_FAQ_ID');
$arFaqIdField = $obFieldQuery->exec()->fetch();

$obQuery
    ->setSelect(array("ID", "CODE", "NAME"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE", true)
    //Подключение скомпилированной сущности таблицы
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FAQ_ID",
              $obUtmEntity,
              \Bitrix\Main\ORM\Query\Join::on('this.ID', 'ref.VALUE_ID')
                    ->where('ref.FIELD_ID', '=', $arFaqIdField['ID'])
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    //Подключение таблицы с элементами
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FAQ_ELEMENT",
              \Bitrix\Iblock\ElementTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.FAQ_ID.VALUE_INT', 'ref.ID')
                    ->where("ref.ACTIVE",true)
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->addSelect("FAQ_ELEMENT.NAME","FAQ_ELEMENT_NAME")
    ->addSelect("FAQ_ELEMENT.ID","FAQ_ELEMENT_ID") //или ->addSelect("FAQ_ID.VALUE_INT","FAQ_ELEMENT_ID")
    ;
mysql
    
SELECT
  `iblock_section6`.`ID` AS `ID`,
  `iblock_section6`.`CODE` AS `CODE`,
  `iblock_section6`.`NAME` AS `NAME`,
  `iblock_section6_faq_element`.`NAME` AS `FAQ_ELEMENT_NAME`,
  `iblock_section6_faq_element`.`ID` AS `FAQ_ELEMENT_ID`
FROM `b_iblock_section` `iblock_section6`
       LEFT JOIN `b_utm_iblock_6_section` `iblock_section6_faq_id` ON `iblock_section6`.`ID` = `iblock_section6_faq_id`.`VALUE_ID` AND `iblock_section6_faq_id`.`FIELD_ID` = 35
       LEFT JOIN `b_iblock_element` `iblock_section6_faq_element` ON `iblock_section6_faq_id`.`VALUE_INT` = `iblock_section6_faq_element`.`ID` AND `iblock_section6_faq_element`.`ACTIVE` = 'Y'
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
    
  
php
array(5)
[
    "ID"               => string(3) "112"
    "CODE"             => string(20) "sredstva-dlya-ukhoda"
    "NAME"             => string(34) "Средства для ухода"
    "FAQ_ELEMENT_NAME" => string(76) "Как ухаживать за волосами после кератина?"
    "FAQ_ELEMENT_ID"   => string(4) "6055"
]

Конечно, необходимо помнить, что т.к. свойство множественное, то в результат выборки добавятся дублирующие строки с разными значениями полей FAQ_ELEMENT_NAME и FAQ_ELEMENT_ID

Количество активных элементов разделе

Для агрегирующих полей используется класс \Bitrix\Main\ORM\Fields\ExpressionField. Но если мы применим его, система добавить группировку по всем выбираем полям

php
$obQuery
    ->setSelect(array("ID", "CODE", "NAME"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE", true)
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "ELEMENTS",
              \Bitrix\Iblock\ElementTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.ID', 'ref.IBLOCK_SECTION_ID')
                    ->where("ref.ACTIVE",true)
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->registerRuntimeField(
          new \Bitrix\Main\ORM\Fields\ExpressionField( //Сразу сформируем путь
              "ELEMENTS_COUNT", //Название выражения
              'COUNT(%s)', //Функция MySql
              array('ELEMENTS.ID') //Значения шаблона подстановки
          )
    )
    ->addSelect("ELEMENTS_COUNT");
mysql
    
SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	COUNT(`iblock_section6_elements`.`ID`) AS `ELEMENTS_COUNT`
FROM `b_iblock_section` `iblock_section6`
LEFT JOIN `b_iblock_element` `iblock_section6_elements` ON `iblock_section6`.`ID` = `iblock_section6_elements`.`IBLOCK_SECTION_ID` AND `iblock_section6_elements`.`ACTIVE` = 'Y'
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
GROUP BY `iblock_section6`.`ID`, `iblock_section6`.`CODE`, `iblock_section6`.`NAME`
    
  

Чтобы избежать группировки по всем полям, воспользуемся под запросом.

php
$obSubQuery = \Bitrix\Iblock\ElementTable::query()
    ->setSelect(array('ELEMENTS_COUNT'))
    ->where("IBLOCK_SECTION_ID", '=', new SqlExpression('%s'))
    ->where('ACTIVE', '=', 'Y')
    ->registerRuntimeField(
            new ExpressionField('ELEMENTS_COUNT', 'COUNT(%s)', array('ID'))
    )
    ->setTableAliasPostfix('_count');
$obQuery
    ->setSelect(array("ID", "CODE", "NAME"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE", true)
    ->registerRuntimeField(
          new ExpressionField(
              "ELEMENTS_COUNT",
              '(' . $obSubQuery->getQuery() . ')',
              array('ID')
          )
    )
    ->addSelect("ELEMENTS_COUNT");
mysql
    
"SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	(SELECT
	COUNT(`iblock_element_count`.`ID`) AS `ELEMENTS_COUNT`
FROM `b_iblock_element` `iblock_element_count`
WHERE `iblock_element_count`.`IBLOCK_SECTION_ID` = `iblock_section6`.`ID` AND `iblock_element_count`.`ACTIVE` = 'Y') AS `ELEMENTS_COUNT`
FROM `b_iblock_section` `iblock_section6`
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
  
  
php
array(4)
[
    "ID"             => string(3) "112"
    "CODE"           => string(20) "sredstva-dlya-ukhoda"
    "NAME"           => string(34) "Средства для ухода"
    "ELEMENTS_COUNT" => string(2) "23"
]

Детальная ссылка на раздел

Детальная ссылка на раздел состоит из "пути" символьных кодов родительских разделов + символьный код самого раздела.

Получим путь из символьных кодов разделов, используя подзапрос. Также не забудем и про шаблон детальной страницы, который хранится в свойствах инфоблока.

php
$obSubQuery = \Bitrix\Iblock\SectionTable::query()
    ->setSelect(array('SECTION_CODE_PATH'))
    ->where('LEFT_MARGIN', '<=', new SqlExpression('%s'))
    ->where('RIGHT_MARGIN', '>=', new SqlExpression('%s'))
    ->where('IBLOCK_ID', '=', new SqlExpression('%s'))
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_CODE_PATH',
              'GROUP_CONCAT(CODE ORDER BY LEFT_MARGIN ASC SEPARATOR \'/\')'
          )
    )
    ->setTableAliasPostfix('_groups');
$obQuery
    ->setSelect(array("ID", "CODE", "NAME"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE", true)
    ->registerRuntimeField(
          new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "PARENT_SECTION",
              \Bitrix\Iblock\SectionTable::class,
              Join::on('this.IBLOCK_SECTION_ID', 'ref.ID')
          )
    )
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_CODE_PATH',
              '(' . $obSubQuery->getQuery() . ')',
              array(
                  'PARENT_SECTION.LEFT_MARGIN',
                  'PARENT_SECTION.RIGHT_MARGIN',
                  'PARENT_SECTION.IBLOCK_ID',
              )
          )
    )
    ->addSelect('SECTION_CODE_PATH')
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "IBLOCK",
              \Bitrix\Iblock\IblockTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.IBLOCK_ID', 'ref.ID')
              ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
          )
    ->addSelect("IBLOCK.SECTION_PAGE_URL", "SECTION_PAGE_URL_TEMPLATE");
mysql
    
SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	(SELECT
	GROUP_CONCAT(CODE ORDER BY LEFT_MARGIN ASC SEPARATOR '/') AS `SECTION_CODE_PATH`
FROM `b_iblock_section` `iblock_section_groups`
WHERE `iblock_section_groups`.`LEFT_MARGIN` <= `iblock_section6_parent_section`.`LEFT_MARGIN` AND `iblock_section_groups`.`RIGHT_MARGIN` >= `iblock_section6_parent_section`.`RIGHT_MARGIN` AND `iblock_section_groups`.`IBLOCK_ID` = `iblock_section6_parent_section`.`IBLOCK_ID`) AS `SECTION_CODE_PATH`,
	`iblock_section6_iblock`.`SECTION_PAGE_URL` AS `SECTION_PAGE_URL_TEMPLATE`
FROM `b_iblock_section` `iblock_section6`
LEFT JOIN `b_iblock_section` `iblock_section6_parent_section` ON `iblock_section6`.`IBLOCK_SECTION_ID` = `iblock_section6_parent_section`.`ID`
LEFT JOIN `b_iblock` `iblock_section6_iblock` ON `iblock_section6`.`IBLOCK_ID` = `iblock_section6_iblock`.`ID`
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6

  

Теперь осталось только подставить в шаблон SECTION_PAGE_URL_TEMPLATE значения полей CODE и SECTION_CODE_PATH;

php
$rsResult = $obQuery->exec();
while ($arRow = $rsResult->fetch()) {
    $arRow['SECTION_PAGE_URL'] = str_replace(
        array("#SECTION_CODE_PATH#" . (strlen($arRow['SECTION_CODE_PATH']) > 0 ? "" : "/"), "#SITE_DIR#"),
        array($arRow['SECTION_CODE_PATH'], ""),
        $arRow['SECTION_PAGE_URL_TEMPLATE']
    ) . $arRow['CODE'] . "/";
}
php
array(6)
[
    "ID"                        => string(3) "112"
    "CODE"                      => string(20) "sredstva-dlya-ukhoda"
    "NAME"                      => string(34) "Средства для ухода"
    "SECTION_CODE_PATH"         => NULL
    "SECTION_PAGE_URL_TEMPLATE" => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"          => string(30) "/catalog/sredstva-dlya-ukhoda/"
]
array(6)
[
    "ID"                        => string(3) "117"
    "CODE"                      => string(11) "slavyanskie"
    "NAME"                      => string(20) "Славянские"
    "SECTION_CODE_PATH"         => string(33) "volosy-dlya-narashchivaniya/lenty"
    "SECTION_PAGE_URL_TEMPLATE" => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"          => string(55) "/catalog/volosy-dlya-narashchivaniya/lenty/slavyanskie/"
]

На самом деле, дополнительно присоединять поля PARENT_SECTION и IBLOCK не требуется, т.к. они уже есть в полях сущности и добавятся автоматически

php
$obQuery
      ->setSelect(array("ID", "CODE", "NAME"))
      ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
      ->where("ACTIVE", true)
      ->registerRuntimeField(
                  new ExpressionField(
                          'SECTION_CODE_PATH',
                          '(' . $obSubQuery->getQuery() . ')',
                          array(
                              'PARENT_SECTION.LEFT_MARGIN',
                              'PARENT_SECTION.RIGHT_MARGIN',
                              'PARENT_SECTION.IBLOCK_ID',
                          )
                  )
      )
      ->addSelect('SECTION_CODE_PATH')
      ->addSelect("IBLOCK.SECTION_PAGE_URL", "SECTION_PAGE_URL_TEMPLATE");

Получение хлебных крошек для каждого раздела

Данная задача очень похожа на получение детальной ссылки на раздел, только вместо символьных кодов необходимо получить путь из полей NAME

php
$obSubQueryCode = \Bitrix\Iblock\SectionTable::query()
    ->setSelect(array('SECTION_CODE_PATH'))
    ->where('LEFT_MARGIN', '<=', new SqlExpression('%s'))
    ->where('RIGHT_MARGIN', '>=', new SqlExpression('%s'))
    ->where('IBLOCK_ID', '=', new SqlExpression('%s'))
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_CODE_PATH',
              'GROUP_CONCAT(CODE ORDER BY LEFT_MARGIN ASC SEPARATOR \'/\')'
          )
    )
    ->setTableAliasPostfix('_groups');
$obSubQueryName = \Bitrix\Iblock\SectionTable::query()
    ->setSelect(array('SECTION_NAME_PATH'))
    ->where('LEFT_MARGIN', '<=', new SqlExpression('%s'))
    ->where('RIGHT_MARGIN', '>=', new SqlExpression('%s'))
    ->where('IBLOCK_ID', '=', new SqlExpression('%s'))
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_NAME_PATH',
              'GROUP_CONCAT(NAME ORDER BY LEFT_MARGIN ASC SEPARATOR \'/\')'
          )
    )
    ->setTableAliasPostfix('_groups');
$obQuery
    ->setSelect(array("ID", "CODE", "NAME"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE", true)
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_CODE_PATH',
              '(' . $obSubQueryCode->getQuery() . ')',
              array(
                  'PARENT_SECTION.LEFT_MARGIN',
                  'PARENT_SECTION.RIGHT_MARGIN',
                  'PARENT_SECTION.IBLOCK_ID',
              )
          )
    )
    ->addSelect('SECTION_CODE_PATH')
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_NAME_PATH',
              '(' . $obSubQueryName->getQuery() . ')',
              array(
                  'PARENT_SECTION.LEFT_MARGIN',
                  'PARENT_SECTION.RIGHT_MARGIN',
                  'PARENT_SECTION.IBLOCK_ID',
              )
          )
    )
    ->addSelect('SECTION_NAME_PATH')
    ->addSelect("IBLOCK.SECTION_PAGE_URL", "SECTION_PAGE_URL_TEMPLATE");
php
array(7)
[
    "ID"                        => string(3) "112"
    "CODE"                      => string(20) "sredstva-dlya-ukhoda"
    "NAME"                      => string(34) "Средства для ухода"
    "SECTION_CODE_PATH"         => NULL
    "SECTION_NAME_PATH"         => NULL
    "SECTION_PAGE_URL_TEMPLATE" => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"          => string(30) "/catalog/sredstva-dlya-ukhoda/"
]
array(7)
[
    "ID"                        => string(3) "117"
    "CODE"                      => string(11) "slavyanskie"
    "NAME"                      => string(20) "Славянские"
    "SECTION_CODE_PATH"         => string(33) "volosy-dlya-narashchivaniya/lenty"
    "SECTION_NAME_PATH"         => string(53) "Волосы для наращивания/Ленты"
    "SECTION_PAGE_URL_TEMPLATE" => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"          => string(55) "/catalog/volosy-dlya-narashchivaniya/lenty/slavyanskie/"
]

Итоговый запрос

Итоговый запрос выглядит следующим образом:

php
$obUtmEntity = \Bitrix\Main\ORM\Entity::compileEntity(
    "b_utm_iblock_" . IBLOCK_CATALOG_CATALOG . "_section",
    array(
        'ID' => array(
            'data_type' => 'integer',
        ),
        'VALUE_ID' => array(
            'data_type' => 'integer',
        ),
        'FIELD_ID' => array(
            'data_type' => 'integer',
        ),
        'VALUE_INT' => array(
            'data_type' => 'integer',
        ),
    ),
    ['table_name' => "b_utm_iblock_" . IBLOCK_CATALOG_CATALOG . "_section"]
);
$obSubQueryCount = \Bitrix\Iblock\ElementTable::query()
    ->setSelect(array('ELEMENTS_COUNT'))
    ->where("IBLOCK_SECTION_ID", '=', new SqlExpression('%s'))
    ->where('ACTIVE', '=', 'Y')
    ->registerRuntimeField(
            new ExpressionField('ELEMENTS_COUNT', 'COUNT(%s)', array('ID'))
    )
    ->setTableAliasPostfix('_count');
$obSubQueryCode = \Bitrix\Iblock\SectionTable::query()
    ->setSelect(array('SECTION_CODE_PATH'))
    ->where('LEFT_MARGIN', '<=', new SqlExpression('%s'))
    ->where('RIGHT_MARGIN', '>=', new SqlExpression('%s'))
    ->where('IBLOCK_ID', '=', new SqlExpression('%s'))
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_CODE_PATH',
              'GROUP_CONCAT(CODE ORDER BY LEFT_MARGIN ASC SEPARATOR \'/\')'
          )
    )
    ->setTableAliasPostfix('_groups');
$obSubQueryName = \Bitrix\Iblock\SectionTable::query()
    ->setSelect(array('SECTION_NAME_PATH'))
    ->where('LEFT_MARGIN', '<=', new SqlExpression('%s'))
    ->where('RIGHT_MARGIN', '>=', new SqlExpression('%s'))
    ->where('IBLOCK_ID', '=', new SqlExpression('%s'))
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_NAME_PATH',
              'GROUP_CONCAT(NAME ORDER BY LEFT_MARGIN ASC SEPARATOR \'/\')'
          )
    )
    ->setTableAliasPostfix('_groups');

$obQuery = new \Bitrix\Main\ORM\Query\Query(\Bitrix\Iblock\Model\Section::compileEntityByIblock(IBLOCK_CATALOG_CATALOG));
$obQuery
    ->setSelect(array("ID","CODE", "NAME","UF_OFFER_COUNT"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true)
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "PICTURE_FILE",
              \Bitrix\Main\FileTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.PICTURE', 'ref.ID')
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->registerRuntimeField(
          new \Bitrix\Main\ORM\Fields\ExpressionField( //Сразу сформируем путь
              "PICTURE_FILE_SRC", //Название выражения
              'CONCAT("/upload/",%s, "/" ,%s)', //Функция MySql
              array('PICTURE_FILE.SUBDIR', 'PICTURE_FILE.FILE_NAME') //Значения шаблона подстановки
          )
    )
    ->addSelect("PICTURE_FILE_SRC")
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FILTER_TYPE",
              \Bitrix\User\FieldEnumTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.UF_FILTER_TYPE', 'ref.ID')
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->addSelect("FILTER_TYPE.VALUE","FILTER_TYPE_VALUE")
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FAQ_ID",
              $obUtmEntity,
              \Bitrix\Main\ORM\Query\Join::on('this.ID', 'ref.VALUE_ID')
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FAQ_ID_FIELD",
              \Bitrix\Main\UserFieldTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.FAQ_ID.FIELD_ID', 'ref.ID')
                  ->where("ref.FIELD_NAME","=","UF_FAQ_ID")
                  ->where("ref.ENTITY_ID","=","IBLOCK_".IBLOCK_CATALOG_CATALOG."_SECTION")
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FAQ_ELEMENT",
              \Bitrix\Iblock\ElementTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.FAQ_ID.VALUE_INT', 'ref.ID')
                    ->where("ref.ACTIVE",true)
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->addSelect("FAQ_ELEMENT.NAME","FAQ_ELEMENT_NAME")
    ->addSelect("FAQ_ELEMENT.ID","FAQ_ELEMENT_ID")
    ->registerRuntimeField(
          new ExpressionField(
              "ELEMENTS_COUNT",
              '(' . $obSubQueryCount->getQuery() . ')',
              array('ID')
          )
    )
    ->addSelect("ELEMENTS_COUNT")
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_CODE_PATH',
              '(' . $obSubQueryCode->getQuery() . ')',
              array(
                  'PARENT_SECTION.LEFT_MARGIN',
                  'PARENT_SECTION.RIGHT_MARGIN',
                  'PARENT_SECTION.IBLOCK_ID',
              )
          )
    )
    ->addSelect('SECTION_CODE_PATH')
    ->registerRuntimeField(
          new ExpressionField(
              'SECTION_NAME_PATH',
              '(' . $obSubQueryName->getQuery() . ')',
              array(
                  'PARENT_SECTION.LEFT_MARGIN',
                  'PARENT_SECTION.RIGHT_MARGIN',
                  'PARENT_SECTION.IBLOCK_ID',
              )
          )
    )
    ->addSelect('SECTION_NAME_PATH')
    ->addSelect("IBLOCK.SECTION_PAGE_URL", "SECTION_PAGE_URL_TEMPLATE");
mysql
    
SELECT
	`iblock_section6`.`ID` AS `ID`,
	`iblock_section6`.`CODE` AS `CODE`,
	`iblock_section6`.`NAME` AS `NAME`,
	`iblock_section6_uts_object`.`UF_OFFER_COUNT` AS `UF_OFFER_COUNT`,
	CONCAT("/upload/",`iblock_section6_picture_file`.`SUBDIR`, "/" ,`iblock_section6_picture_file`.`FILE_NAME`) AS `PICTURE_FILE_SRC`,
	`iblock_section6_filter_type`.`VALUE` AS `FILTER_TYPE_VALUE`,
	`iblock_section6_faq_element`.`NAME` AS `FAQ_ELEMENT_NAME`,
	`iblock_section6_faq_element`.`ID` AS `FAQ_ELEMENT_ID`,
	(SELECT
	COUNT(`iblock_element_count`.`ID`) AS `ELEMENTS_COUNT`
FROM `b_iblock_element` `iblock_element_count`
WHERE `iblock_element_count`.`IBLOCK_SECTION_ID` = `iblock_section6`.`ID` AND `iblock_element_count`.`ACTIVE` = 'Y') AS `ELEMENTS_COUNT`,
	(SELECT
	GROUP_CONCAT(CODE ORDER BY LEFT_MARGIN ASC SEPARATOR '/') AS `SECTION_CODE_PATH`
FROM `b_iblock_section` `iblock_section_groups`
WHERE `iblock_section_groups`.`LEFT_MARGIN` <= `iblock_section6_parent_section`.`LEFT_MARGIN` AND `iblock_section_groups`.`RIGHT_MARGIN` >= `iblock_section6_parent_section`.`RIGHT_MARGIN` AND `iblock_section_groups`.`IBLOCK_ID` = `iblock_section6_parent_section`.`IBLOCK_ID`) AS `SECTION_CODE_PATH`,
	(SELECT
	GROUP_CONCAT(NAME ORDER BY LEFT_MARGIN ASC SEPARATOR '/') AS `SECTION_NAME_PATH`
FROM `b_iblock_section` `iblock_section_groups`
WHERE `iblock_section_groups`.`LEFT_MARGIN` <= `iblock_section6_parent_section`.`LEFT_MARGIN` AND `iblock_section_groups`.`RIGHT_MARGIN` >= `iblock_section6_parent_section`.`RIGHT_MARGIN` AND `iblock_section_groups`.`IBLOCK_ID` = `iblock_section6_parent_section`.`IBLOCK_ID`) AS `SECTION_NAME_PATH`,
	`iblock_section6_iblock`.`SECTION_PAGE_URL` AS `SECTION_PAGE_URL_TEMPLATE`
FROM `b_iblock_section` `iblock_section6`
LEFT JOIN `b_file` `iblock_section6_picture_file` ON `iblock_section6`.`PICTURE` = `iblock_section6_picture_file`.`ID`
LEFT JOIN `b_uts_iblock_6_section` `iblock_section6_uts_object` ON `iblock_section6`.`ID` = `iblock_section6_uts_object`.`VALUE_ID`
LEFT JOIN `b_user_field_enum` `iblock_section6_filter_type` ON `iblock_section6_uts_object`.`UF_FILTER_TYPE` = `iblock_section6_filter_type`.`ID`
LEFT JOIN `b_utm_iblock_6_section` `iblock_section6_faq_id` ON `iblock_section6`.`ID` = `iblock_section6_faq_id`.`VALUE_ID`
LEFT JOIN `b_user_field` `iblock_section6_faq_id_field` ON `iblock_section6_faq_id`.`FIELD_ID` = `iblock_section6_faq_id_field`.`ID` AND `iblock_section6_faq_id_field`.`FIELD_NAME` = 'UF_FAQ_ID' AND `iblock_section6_faq_id_field`.`ENTITY_ID` = 'IBLOCK_6_SECTION'
LEFT JOIN `b_iblock_element` `iblock_section6_faq_element` ON `iblock_section6_faq_id`.`VALUE_INT` = `iblock_section6_faq_element`.`ID` AND `iblock_section6_faq_element`.`ACTIVE` = 'Y'
LEFT JOIN `b_iblock_section` `iblock_section6_parent_section` ON `iblock_section6`.`IBLOCK_SECTION_ID` = `iblock_section6_parent_section`.`ID`
LEFT JOIN `b_iblock` `iblock_section6_iblock` ON `iblock_section6`.`IBLOCK_ID` = `iblock_section6_iblock`.`ID`
WHERE `iblock_section6`.`IBLOCK_ID` = 6 AND `iblock_section6`.`ACTIVE` = 'Y' AND `iblock_section6`.`IBLOCK_ID` = 6
    
  
php
array(13)
[
    "ID"                        => string(3) "112"
    "CODE"                      => string(20) "sredstva-dlya-ukhoda"
    "NAME"                      => string(34) "Средства для ухода"
    "UF_OFFER_COUNT"            => string(2) "10"
    "PICTURE_FILE_SRC"          => string(55) "/upload/iblock/bfd/ggxmnog0amwahvb3cz4hhngmdjkwn3lw.png"
    "FILTER_TYPE_VALUE"         => string(29) "Тип инструмента"
    "FAQ_ELEMENT_NAME"          => string(76) "Как ухаживать за волосами после кератина?"
    "FAQ_ELEMENT_ID"            => string(4) "6055"
    "ELEMENTS_COUNT"            => string(1) "0"
    "SECTION_CODE_PATH"         => NULL
    "SECTION_NAME_PATH"         => NULL
    "SECTION_PAGE_URL_TEMPLATE" => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"          => string(30) "/catalog/sredstva-dlya-ukhoda/"
]
array(13)
[
    "ID"                        => string(3) "117"
    "CODE"                      => string(11) "slavyanskie"
    "NAME"                      => string(20) "Славянские"
    "UF_OFFER_COUNT"            => string(2) "20"
    "PICTURE_FILE_SRC"          => string(55) "/upload/iblock/692/1dxcciwycphrc705pa4kdebo0k1782xn.png"
    "FILTER_TYPE_VALUE"         => string(20) "Назначение"
    "FAQ_ELEMENT_NAME"          => string(100) "Какого размера капсулы используются при наращивании?  "
    "FAQ_ELEMENT_ID"            => string(4) "5052"
    "ELEMENTS_COUNT"            => string(1) "0"
    "SECTION_CODE_PATH"         => string(33) "volosy-dlya-narashchivaniya/lenty"
    "SECTION_NAME_PATH"         => string(53) "Волосы для наращивания/Ленты"
    "SECTION_PAGE_URL_TEMPLATE" => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"          => string(55) "/catalog/volosy-dlya-narashchivaniya/lenty/slavyanskie/"
]

Получение разделов D7. Подход realweb.api.

Несмотря на достигнутый положительный результат, можно заметить, что сформированный запрос достаточно сложен для составления, восприятия и редактирования. В realweb.api реализованы некоторые методы выборки, которые облегчают написание и чтение запроса. Подробнее про работу с разделами инфоблока в realweb.api

  • registerPicture - путь к картинке
  • registerSectionCodePath - путь из символьных кодов
  • registerSectionNamePath - путь из имен
  • registerSectionEnumField - значение свойства типа список
  • registerSectionMultiField - множественное свойство

Перепишем этот запрос, используя ядро realweb.api.

php
$obQuery = \Realweb\Api\Model\Iblock\Section\Table::queryIblock(IBLOCK_CATALOG_CATALOG);
$obQuery
    ->setSelect(array("ID","CODE", "NAME","UF_OFFER_COUNT"))
    ->where("IBLOCK_ID", "=", IBLOCK_CATALOG_CATALOG)
    ->where("ACTIVE",true)
    ->registerPicture()
    ->registerSectionCodePath()
    ->registerSectionNamePath()
    ->registerSectionEnumField("UF_FILTER_TYPE")
    ->registerSectionMultiField("UF_FAQ_ID",IBLOCK_CATALOG_CATALOG,"FAQ_ID")
    ->registerRuntimeField(
          (new \Bitrix\Main\ORM\Fields\Relations\Reference(
              "FAQ_ELEMENT",
              \Bitrix\Iblock\ElementTable::class,
              \Bitrix\Main\ORM\Query\Join::on('this.FAQ_ID_VALUE_INT', 'ref.ID')
                    ->where("ref.ACTIVE",true)
          ))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)
    )
    ->addSelect("FAQ_ELEMENT.NAME","FAQ_ELEMENT_NAME")
    ->addSelect("IBLOCK.SECTION_PAGE_URL", "SECTION_PAGE_URL_TEMPLATE");

Количество элементов выбирается также, как и в классическом подходе.

php
array(24)
[
    "ID"                           => string(3) "117"
    "CODE"                         => string(11) "slavyanskie"
    "NAME"                         => string(20) "Славянские"
    "UF_OFFER_COUNT"               => string(2) "20"
    "PICTURE_SRC"                  => string(55) "/upload/iblock/692/1dxcciwycphrc705pa4kdebo0k1782xn.png"
    "SECTION_CODE_PATH"            => string(33) "volosy-dlya-narashchivaniya/lenty"
    "SECTION_NAME_PATH"            => string(53) "Волосы для наращивания/Ленты"
    "UF_FILTER_TYPE_ID"            => string(1) "8"
    "UF_FILTER_TYPE_USER_FIELD_ID" => string(2) "29"
    "UF_FILTER_TYPE_VALUE"         => string(20) "Назначение"
    "UF_FILTER_TYPE_DEF"           => string(1) "N"
    "UF_FILTER_TYPE_SORT"          => string(3) "500"
    "UF_FILTER_TYPE_XML_ID"        => string(32) "6fbe1b28b224cc607b74849a13b21a3a"
    "FAQ_ID"                       => string(4) "5052"
    "FAQ_ID_ID"                    => string(2) "14"
    "FAQ_ID_VALUE_ID"              => string(3) "117"
    "FAQ_ID_FIELD_ID"              => string(2) "35"
    "FAQ_ID_VALUE"                 => NULL
    "FAQ_ID_VALUE_INT"             => string(4) "5052"
    "FAQ_ID_VALUE_DOUBLE"          => NULL
    "FAQ_ID_VALUE_DATE"            => NULL
    "FAQ_ELEMENT_NAME"             => string(100) "Какого размера капсулы используются при наращивании?  "
    "SECTION_PAGE_URL_TEMPLATE"    => string(39) "#SITE_DIR#/catalog/#SECTION_CODE_PATH#/"
    "SECTION_PAGE_URL"             => string(55) "/catalog/volosy-dlya-narashchivaniya/lenty/slavyanskie/"
]