Как в D7 получить правильный URL детальной страницы элемента инфоблока

Содержание

При переходе на новое ядро 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 — это старый добрый инструмент из старого ядра, который идеально справляется с заменой плейсхолдеров. Он принимает четыре аргумента:

  1. $url — Строка-шаблон из поля DETAIL_PAGE_URL инфоблока. Может содержать маски #ID#, #CODE#, #SECTION_CODE# и т.д.

  2. $arr — Массив данных, на основании которых будут заменены маски. Ключи массива должны строго совпадать с названиями полей в шаблоне.

  3. $server_name (bool) — Определяет, нужно ли добавлять в начало адреса протокол, домен и директорию сайта (SITE_DIR). Удобно включать (true) при генерации ссылок для почтовых рассылок, карты сайта или RSS-лент.

  4. $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.



Комментарии
Оставить комментарий
Form comments
Еще больше о нас и нашей деятельности
Послушать подкасты в аудиоформате: Wave, Podcasts.apple, Яндекс, Звук

Ещё больше крутых статей — в нашем Telegram-канале. Подписывайтесь, чтобы быть в курсе всех событий!