При переходе на новое ядро Bitrix Framework (D7) разработчики часто сталкиваются с неожиданностью: в таблице Bitrix\Iblock\ElementTable отсутствует готовое поле DETAIL_PAGE_URL. Это не баг и не упущение, а архитектурная особенность. Адрес страницы с подробным описанием элемента — это не статичное значение, а динамический шаблон, который хранится в настройках конкретного инфоблока (например, /catalog/#SECTION_CODE#/#ELEMENT_CODE#/).
Чтобы финальная ссылка была корректной, Битриксу нужно совместить два источника данных: сам шаблон из параметров инфоблока и конкретные значения полей текущего элемента (ID, CODE, SECTION_ID и т.д.). В этой заметке разберем, как элегантно и производительно решить эту задачу в стиле D7.
Универсальный рецепт: объединяем выборку данных и стандартный обработчик
Секрет прост: нужно явно попросить Битрикс отдать нам шаблон URL вместе с данными элемента, а затем передать всё это в проверенный временем метод \CIBlock::ReplaceDetailUrl.
Способ 1. Работа с массивом данных (классический fetch)
Использовать можно как класс-спецификацию вашего инфоблока (если задан API_CODE, например ElementCatalogTable), так и базовый \Bitrix\Iblock\ElementTable. Ключевой момент — в секции select мы делаем связку с таблицей инфоблока через алиас IBLOCK.DETAIL_PAGE_URL.
<?php
declare(strict_types=1);
use Bitrix\Main\Loader;
use Bitrix\Iblock\Elements\ElementCatalogTable; // Подставьте свой API_CODE или используйте ElementTable
Loader::includeModule('iblock');
$elementId = 333;
// Выполняем запрос, явно запрашивая шаблон из родительского инфоблока
$elementData = ElementCatalogTable::getList([
'select' => [
'ID',
'CODE',
'IBLOCK_SECTION_ID',
'TEMPLATE' => 'IBLOCK.DETAIL_PAGE_URL' // Здесь мы получаем строку типа "/catalog/#CODE#/"
],
'filter' => ['=ID' => $elementId]
])->fetch();
if ($elementData) {
// Магия подстановки: шаблон + реальные значения элемента
$fullUrl = \CIBlock::ReplaceDetailUrl(
$elementData['TEMPLATE'],
$elementData,
true, // Добавлять ли домен и путь к сайту (SITE_DIR)
'E' // Указываем, что работаем с Элементом (Element)
);
echo $fullUrl; // Готовый адрес для вставки в href
}
Способ 2. Работа с объектами (DTO, метод fetchObject)
Если вы предпочитаете строгую типизацию и удобную навигацию по связям через геттеры (getIblock(), getSection()), используйте выборку объекта. Но метод \CIBlock::ReplaceDetailUrl умеет работать только с массивами, поэтому потребуется небольшое преобразование через collectValues().
$elementObject = ElementCatalogTable::getList([
'select' => [
'ID',
'CODE',
'IBLOCK_SECTION_ID',
'IBLOCK.DETAIL_PAGE_URL'
],
'filter' => ['=ID' => $elementId]
])->fetchObject();
if ($elementObject) {
// Извлекаем шаблон из объекта инфоблока
$template = $elementObject->getIblock()->getDetailPageUrl();
// Превращаем объект элемента в ассоциативный массив полей
$fieldsArray = $elementObject->collectValues();
$fullUrl = \CIBlock::ReplaceDetailUrl($template, $fieldsArray, true, 'E');
echo $fullUrl;
}
Что скрывается за параметрами ReplaceDetailUrl
Метод \CIBlock::ReplaceDetailUrl
— это старый добрый инструмент из старого ядра, который идеально справляется с заменой плейсхолдеров. Он принимает четыре аргумента:
-
$url— Строка-шаблон из поляDETAIL_PAGE_URLинфоблока. Может содержать маски#ID#,#CODE#,#SECTION_CODE#и т.д. -
$arr— Массив данных, на основании которых будут заменены маски. Ключи массива должны строго совпадать с названиями полей в шаблоне. -
$server_name(bool) — Определяет, нужно ли добавлять в начало адреса протокол, домен и директорию сайта (SITE_DIR). Удобно включать (true) при генерации ссылок для почтовых рассылок, карты сайта или RSS-лент. -
$arrType(string) — Тип сущности.'E'для элементов инфоблока,'S'для разделов. Влияет на обработку специфических масок вроде#SECTION_CODE_PATH#.
Важные детали, о которых нельзя забывать
1. Полнота выборки данных
Если в вашем шаблоне детальной страницы задействован символьный код раздела (#SECTION_CODE#), то в массиве $elementData его не окажется просто так. Потребуется расширить select:
'select' => [
'ID',
'CODE',
'SECTION_CODE' => 'IBLOCK_SECTION.CODE' // Получаем код раздела через связь
]
Без этого плейсхолдер #SECTION_CODE# просто не будет заменен, и ссылка сформируется с "дыркой".
2. Выбор класса для запроса
Хотя \Bitrix\Iblock\ElementTable работает всегда, в современной разработке предпочтение отдают сгенерированным классам по API_CODE инфоблока (например, ElementCatalogTable). Это дает автодополнение в IDE, строгую типизацию и упрощает доступ к пользовательским свойствам. Но в универсальных компонентах или миграциях, где API_CODE может быть не задан, базовый ElementTable остается надежным выбором.
3. Производительность
Запрос с джойном к таблице b_iblock через алиас IBLOCK
выполняется быстро и не создает дополнительной нагрузки. Это самый правильный способ, исключающий лишние обращения к API настроек.
Резюме
Правильное построение ссылки на элемент в D7 — это комбинация нового подхода к выборке данных (связка IBLOCK.DETAIL_PAGE_URL) и старого проверенного метода \CIBlock::ReplaceDetailUrl
для обработки масок. Следуя этой схеме, вы получите рабочий и производительный код, полностью соответствующий идеологии Bitrix Framework.