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

Свойства инфоблока - чтение, запись и фильтрация по значению

Выбираем элементы по значению свойства, пишем множественные значения и меняем код свойства, не потеряв данные.

Решение

Смотрим свойства инфоблока с их типами:

$props = CIBlockProperty::GetList(['SORT' => 'ASC'], ['IBLOCK_ID' => $iblockId]);
// пустой символьный код у свойства закрывает ему дорогу в объектную выборку
while ($prop = $props->Fetch()) {
printf("%-20s %-4s множ=%s значений=%s\n",
$prop['CODE'], $prop['PROPERTY_TYPE'],
$prop['MULTIPLE'], $prop['LINK_IBLOCK_ID'] ?: '-');
}

Тип приходит буквой: S строка, N число, L список, F файл, E привязка к элементам, G привязка к разделам. Флаг множественности от типа не зависит и задаётся отдельно, поэтому множественной бывает и строка, и файл, и привязка.

Фильтруем элементы по свойству:

$res = CIBlockElement::GetList(
['SORT' => 'ASC'],
[
'IBLOCK_ID' => $iblockId,
'PROPERTY_MATERIAL' => 'хлопок', // строка сравнивается со значением
'PROPERTY_COLOR' => $colorEnumId, // список - с идентификатором значения
],
false, false,
['ID', 'NAME', 'PROPERTY_MATERIAL', 'PROPERTY_COLOR']
);

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

Записываем множественное значение:

CIBlockElement::SetPropertyValuesEx($elementId, $iblockId, [
'TAGS' => ['новинка', 'хит', 'распродажа'], // массив: свойство множественное
'COLOR' => $colorEnumId, // одиночное: скаляр
]);
// переданные свойства перезаписываются целиком, не перечисленные остаются как были

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

Меняем код свойства:

$property = new CIBlockProperty();
$property->Update($propertyId, ['CODE' => 'MATERIAL_NEW']);
// значения свойства при смене кода остаются на месте, теряются только ссылки в коде
CIBlock::CleanCache($iblockId); // иначе компоненты возьмут старую карту свойств
// тот же фильтр по свойству лежит в основе отбора разделов каталога

Код - только идентификатор для кода и шаблонов, значения при его смене не теряются. А вот тип и способ хранения менять нельзя: значения лежат в разных форматах, и штатного переноса между ними нет.

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

Смена типа свойства делается только пересозданием. Заводят новое свойство нужного типа, переносят значения своим скриптом, затем отключают старое, а не удаляют его сразу. Отключённое свойство продолжает хранить значения, и откат остаётся возможным до тех пор, пока его не удалили насовсем.

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

Фильтр по свойству возвращает пустоту.

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

Из нескольких значений сохранилось последнее.

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

После смены кода свойства шаблон перестал его находить.

Не сброшен кеш инфоблока. Компоненты держат карту свойств в кеше и продолжают спрашивать прежний код.

Свойство типа «привязка» фильтруется, а выводится числом.

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

Сортировка по свойству не работает.

Сортировать можно по PROPERTY_КОД только при отдельном способе хранения. На общей таблице значений сортировка по свойству требует своего запроса.

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

Как отфильтровать по множественному свойству с отрицанием?

Через префикс восклицательного знака: !PROPERTY_TAGS. На множественном свойстве это означает «нет ни одного такого значения», а не «есть значение, отличное от указанного».

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

Штатным GetList нет: фильтр по свойству требует конкретного инфоблока. Делают два запроса и объединяют результат либо переходят на ORM с явными сущностями свойств.

Как задать порядок значений у свойства-списка?

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

Почему значение по умолчанию нельзя убрать?

У свойства-списка значение по умолчанию задаётся отметкой у самого значения справочника. Снимают отметку у значения, а не правят свойство.

Смежное

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