Перейти к содержимому

Свойства-привязки - элемент, раздел и обратная выборка

Разбираем свойства типа привязка: чем они отличаются от списков, как выводить названия без лишних запросов и как искать по ним в обе стороны.

Решение

Смотрим, что лежит в свойстве привязки:

$res = CIBlockElement::GetList([], ['IBLOCK_ID' => 5, 'ID' => $elementId], false, false,
['ID', 'NAME', 'PROPERTY_BRAND', 'PROPERTY_RELATED']);
$row = $res->Fetch();
var_dump($row['PROPERTY_BRAND_VALUE']); // идентификатор элемента-бренда
var_dump($row['PROPERTY_RELATED_VALUE']); // массив, если свойство множественное

В привязке хранится идентификатор элемента, а не его название. Это и отличает её от списка: значения живут отдельным инфоблоком со своими свойствами, картинками и правами, а свойство лишь ссылается на них.

Выводим названия одним запросом на весь список:

$ids = array_filter(array_column($rows, 'PROPERTY_BRAND_VALUE'));
$names = [];
$res = CIBlockElement::GetList([], ['IBLOCK_ID' => 8, 'ID' => $ids], false, false, ['ID', 'NAME']);
while ($b = $res->Fetch()) {
$names[$b['ID']] = $b['NAME']; // один запрос вместо запроса на каждый товар
}

Запрос названия внутри цикла по товарам - самая частая причина медленной витрины. Собранный список идентификаторов забирают одним запросом, а дальше берут названия из готового массива.

Фильтруем выборку по значению привязки:

$filter = ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y', 'PROPERTY_BRAND' => $brandId];
$res = CIBlockElement::GetList(['SORT' => 'ASC'], $filter, false, ['nPageSize' => 20], ['ID', 'NAME']);
// фильтр принимает идентификатор; по названию бренда отбор здесь не работает

Фильтр по привязке работает только по идентификатору. Название сначала переводят в идентификатор отдельным запросом, и это же правило действует для адресов раздела с параметром бренда.

Находим разделы, где такие элементы есть:

$sections = [];
$res = CIBlockElement::GetList([], ['IBLOCK_ID' => 5, 'PROPERTY_BRAND' => $brandId, 'ACTIVE' => 'Y'],
false, false, ['ID', 'IBLOCK_SECTION_ID']);
while ($e = $res->Fetch()) {
$sections[$e['IBLOCK_SECTION_ID']] = true; // ключи массива снимают повторы
}

Обратная задача решается от элементов к разделам, а не наоборот. Прямого фильтра разделов по свойствам их элементов нет, и попытка собрать такой список средствами выборки разделов заканчивается ничем.

Привязка к разделу устроена так же, но ссылается на раздел:

$res = CIBlockSection::GetList([], ['IBLOCK_ID' => 5, 'ID' => $row['PROPERTY_LINE_VALUE']],
false, ['ID', 'NAME', 'SECTION_PAGE_URL']);
$line = $res->GetNext(); // GetNext сразу приводит поля к выводу
echo $line['NAME'];

Разница только в том, откуда берутся значения. Проверка на существование нужна обеим: удалённый элемент или раздел оставляет в свойстве идентификатор, которому уже ничего не соответствует.

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

Множественная привязка возвращает массив даже с одним значением. Код, который ждёт строку, на таком свойстве ломается молча: в вывод попадает слово «массив» вместо названия.

Типичные проблемы

В шаблоне выводится число вместо названия.

Свойство хранит идентификатор элемента. Название забирают отдельным запросом по этому идентификатору.

Витрина стала медленной после вывода бренда.

Название запрашивается внутри цикла по товарам. Идентификаторы собирают в список и делают один запрос.

Фильтр по названию бренда ничего не находит.

Фильтр по привязке принимает идентификатор. Название переводят в идентификатор отдельным запросом.

В карточке пустое место вместо привязки.

Элемент, на который она ссылалась, удалён или выключен. Идентификатор в свойстве при этом остаётся прежним.

Не удаётся отобрать разделы по свойству элементов.

Такого фильтра у разделов нет. Список собирают из разделов найденных элементов.

Частые вопросы

Чем привязка лучше списка?

У значения появляются свои свойства, картинка и страница. Список хранит только текст, и расширить его нечем.

Можно ли привязаться к элементу другого инфоблока?

Да, инфоблок-источник задаётся в настройках свойства. Без указания источника выбор идёт по всем инфоблокам сразу.

Как вывести список товаров бренда на его странице?

Выборкой товаров с фильтром по привязке, где значением стоит идентификатор текущего элемента. Это обычный список каталога с дополнительным условием.

Почему привязка не видна в умном фильтре?

Свойство не включено в настройки фильтрации у инфоблока. Умный фильтр показывает только отмеченные там свойства.

Смежное

Первоисточник