Типичная ошибка на практике: импорт из CSV подставил в свойство текст «В наличии», Update отработал без ошибок, а фильтр в каталоге не работает — карточка пустая. Знакомо? В списочных свойствах 1С-Битрикс: Управление сайтом в элемент записывается не подпись из файла, а числовой ID варианта из справочника. Ниже разберем CIBlockPropertyEnum::GetList, D7 PropertyEnumerationTable и чек-лист, который спасает от пустых списков и дублей перед выкладкой на прод.
CIBlockPropertyEnum - это классический API 1С-Битрикс (с версии 3.1.3) для работы с вариантами свойств типа "Список" в таблице b_iblock_property_enum: GetList и GetByID читают справочник, Add/Update/Delete меняют его, а в элемент передается числовой ID варианта, не текст VALUE. Сегодня: подключите модуль iblock, получите enum ID по IBLOCK_ID+CODE, постройте карту XML_ID для CSV и запишите ID через SetPropertyValuesEx - не строку из файла.
Речь про CMS на вашем хостинге, не про облачный Bitrix24. Списочное свойство (тип L) хранит у элемента ссылку на строку справочника enum: в админке "В наличии", в коде - числовой ID.
На стейдже колонка CSV называлась VALUE, скрипт писал "В наличии" в PROPERTY_VALUES. Update без ошибок, карточка пустая, фильтр молчит. После GetList с IBLOCK_ID, CODE и XML_ID всё встало за один проход.
Уточните, что такое списочное свойство и CIBlockPropertyEnum
Списочное свойство - это поле элемента с фиксированным набором вариантов ("В наличии", "Под заказ", "Красный"). Варианты живут в справочнике b_iblock_property_enum, а CIBlockPropertyEnum - класс для чтения и правки этого справочника с 2005 года (API 3.1.3). Когда нужно: импорт, фильтры, генерация select на сайте. Когда не нужно: правка одного текстового поля или UF-поля пользователя - там другие классы.
Разберите, когда нужен CIBlockPropertyEnum
Класс нужен, когда вы читаете или меняете справочник вариантов "Список": форма, фильтр каталога, импорт CSV или 1С. У свойства есть PROPERTY_ID; у каждого варианта - ID enum, VALUE (текст) и XML_ID (внешний код). Три разных "ID" путают чаще всего:
| Что называют "ID" | Где лежит | Зачем нужен |
|---|---|---|
| PROPERTY_ID | b_iblock_property | Фильтр GetList: "все варианты этого свойства" |
| ID enum (в GetList) | b_iblock_property_enum | Запись в PROPERTY_VALUES и SetPropertyValuesEx |
| VALUE | Текст варианта | Показ в select и админке, не для записи в элемент |
Сделайте: перед любым GetList зафиксируйте IBLOCK_ID и символьный CODE свойства. Не делайте: не фильтруйте только по VALUE - в другом инфоблоке может быть такой же текст, и вы получите чужой enum ID.
Получите варианты через CIBlockPropertyEnum::GetList
GetList читает справочник по фильтрам IBLOCK_ID, CODE, PROPERTY_ID, XML_ID, VALUE. Без Loader::includeModule('iblock') список пустой.
- Подключите модуль:
\Bitrix\Main\Loader::includeModule('iblock'). - Задайте фильтр с непустым IBLOCK_ID и CODE свойства (или PROPERTY_ID, если CODE неудобен).
- Отсортируйте по SORT или VALUE:
['SORT' => 'ASC', 'VALUE' => 'ASC']. - Обойдите результат через
while ($row = $rs->GetNext())и соберите массив ID => VALUE; на стейдже сверьте, что ID только из вашего инфоблока.
$rs = CIBlockPropertyEnum::GetList(
['SORT' => 'ASC'],
['IBLOCK_ID' => 5, 'CODE' => 'AVAILABILITY']
);
$enums = [];
while ($row = $rs->GetNext()) {
$enums[$row['ID']] = $row['VALUE'];
}
В реальном проекте часто ломается импорт, когда в фильтре GetList пустой IBLOCK_ID: тянутся варианты из соседних инфоблоков с тем же VALUE — «два Красный» с разными enum ID. Всегда фильтруйте IBLOCK_ID + CODE.
Найдите enum по GetByID и XML_ID для обмена
GetByID отдает поля варианта по enum ID - для отладки. Для CSV и 1С надежнее XML_ID: стабилен между средами, VALUE может отличаться регистром.
CSV/XML_ID → GetList (IBLOCK_ID + CODE + XML_ID) → enum ID → SetPropertyValuesEx → проверка GetByID
Соберите за один GetList карты BY_ID и BY_XML_ID - не дергайте базу на каждой строке импорта.
$rs = CIBlockPropertyEnum::GetList(
[],
['IBLOCK_ID' => 5, 'CODE' => 'COLOR', 'XML_ID' => 'red']
);
if ($row = $rs->GetNext()) {
$enumId = (int)$row['ID']; // этот ID пойдет в элемент
}
Сделайте: заведите XML_ID у каждого варианта до первого импорта. Не делайте: не матчите CSV только по VALUE - "В наличии" и "в наличии" дадут разный результат или пустоту.
Запишите enum ID в элемент, а не текст VALUE
SetPropertyValuesEx для "Списка" принимает только ID варианта. Текст вместо ENUM_ID может записаться без привязки - метод вернет true, значение пропадет при чтении.
CIBlockElement::SetPropertyValuesEx(
$elementId,
$iblockId,
['AVAILABILITY' => $enumId] // число, не "В наличии"
);
В Update и PROPERTY_VALUES те же правила: код свойства в верхнем регистре, значение - enum ID. Логируйте ID и VALUE после записи и проверьте карточку в админке - true от Update еще не гарантия. Полный разбор Update - в гайде как обновить элемент инфоблока через CIBlockElement::Update; здесь только справочник enum.
Добавьте и измените варианты через Add, Update, Delete
Если варианта нет - Add с PROPERTY_ID, VALUE, XML_ID; Update/Delete - по enum ID, не по PROPERTY_ID свойства.
- Найдите PROPERTY_ID через CIBlockProperty::GetList.
- Add с VALUE и XML_ID, привяжите enum ID через SetPropertyValuesEx.
- Rename VALUE через Update — привязки не рвутся; Delete только если вариант не используется в элементах.
Выберите между legacy GetList и D7 PropertyEnumerationTable
С 14.0.0 есть D7 PropertyEnumerationTable для той же таблицы: join с PROPERTY, кеш, validateXmlId.
| Критерий | CIBlockPropertyEnum | PropertyEnumerationTable (D7) |
|---|---|---|
| Стиль API | Legacy, CDBResult, GetNext | ORM, fetchAll, Query |
| Фильтр по инфоблоку | IBLOCK_ID + CODE в arFilter | PROPERTY.IBLOCK_ID + PROPERTY.CODE |
| Когда брать | Старый модуль, админские скрипты, примеры в доке | Новый модуль, агенты, REST, кешируемые выборки |
| CRUD | Add/Update/Delete из коробки | add/update/delete через DataManager |
use Bitrix\Iblock\PropertyEnumerationTable;
$rows = PropertyEnumerationTable::getList([
'filter' => [
'PROPERTY.IBLOCK_ID' => 5,
'PROPERTY.CODE' => 'COLOR',
],
'select' => ['ID', 'VALUE', 'XML_ID'],
'order' => ['SORT' => 'ASC'],
'cache' => ['ttl' => 3600],
])->fetchAll();
Мигрировать весь проект не обязательно - достаточно helper с картой XML_ID⇄ID на GetList или PropertyEnumerationTable.
Проверьте типичные сбои по чек-листу до деплоя
Перед выкладкой прогоните пять проверок - они закрывают типичные тикеты с форума и Habr Q&A по ciblockpropertyenum getlist.
- Модуль iblock подключен? Без Loader::includeModule GetList молчит.
- IBLOCK_ID в фильтре не пустой? Иначе дубли VALUE из чужих инфоблоков.
- В PROPERTY_VALUES число enum ID, не строка VALUE? Сверьте с GetByID.
- CODE свойства в верхнем регистре в SetPropertyValuesEx и Update совпадает с админкой?
- XML_ID в CSV есть в справочнике? Пустой GetList по XML_ID - сигнал добавить вариант через Add.
Пустой GetList при верном CODE - проверьте тип свойства (L, не строка). Поле ID в строке GetList - то, что пишете в элемент, не PROPERTY_ID.
С импортом каталога поможем - обсудить задачу. Кейсы по Битрикс - в портфолио.
Автор: Максим Мольков, разработчик 1С-Битрикс.
Источники: документация CIBlockPropertyEnum, PropertyEnumerationTable D7, SetPropertyValuesEx.
Частые вопросы
Как получить все значения списочного свойства в Битрикс?
Вызовите CIBlockPropertyEnum::GetList с сортировкой SORT и фильтром IBLOCK_ID плюс CODE (или PROPERTY_ID). Обойдите CDBResult через GetNext и соберите массив. В D7 то же дает PropertyEnumerationTable::getList с фильтром PROPERTY.IBLOCK_ID и PROPERTY.CODE.
Что передавать в PROPERTY_VALUES для списка - текст или ID?
Только числовой ID варианта enum из b_iblock_property_enum, не текст VALUE. Сначала найдите ID через GetList по XML_ID или VALUE, затем передайте его в SetPropertyValuesEx или в PROPERTY_VALUES при Update.
Почему GetList возвращает два одинаковых VALUE?
Чаще всего в фильтре пустой или неверный IBLOCK_ID - подтягиваются варианты из других инфоблоков с тем же текстом. Добавьте IBLOCK_ID и CODE, пересоберите карту enum.
Как найти enum по XML_ID для импорта из CSV?
Фильтр GetList: IBLOCK_ID, CODE свойства и XML_ID из файла. В D7 - PropertyEnumerationTable::getList с теми же условиями через связь PROPERTY. Полученный ID кладите в PROPERTY_VALUES, не строку из колонки VALUE.
CIBlockPropertyEnum или PropertyEnumerationTable - что выбрать?
Legacy CIBlockPropertyEnum::GetList проще в старых скриптах и совпадает с примерами dev.1c-bitrix.ru. PropertyEnumerationTable удобен в новых модулях: ORM, join, кеш TTL. Оба читают одну таблицу; для записи в элемент в любом случае нужен enum ID.
Чем PROPERTY_ID отличается от ID в результате GetList?
PROPERTY_ID - это ID самого свойства в b_iblock_property (поле свойства "Цвет" или "Наличие"). ID в строке GetList - это ID варианта enum ("Красный", "В наличии"). В элемент записывается второй ID, не PROPERTY_ID.