Инфоблок через ORM - API_CODE, класс элементов, свойства
Работаем с элементами инфоблока через слой данных: символьный код для API, класс сущности, чтение и запись свойств, множественные значения.
Что нужно знать заранее
Для работы объектами инфоблоку нужен символьный код для программного интерфейса. Без него сущность не собирается, и обращение к классу элементов заканчивается ошибкой об отсутствующем классе.
Базовый класс элементов напрямую не используют ни в одном сценарии. Он видит только общие поля всех инфоблоков, а свойства и связи живут в собранной сущности конкретного инфоблока.
В карту сущности попадают только свойства с заполненным символьным кодом свойства. Свойство без кода видно в админке и в старом интерфейсе, но объектам оно недоступно совсем.
Шаги
- Заполнить инфоблоку символьный код для программного интерфейса прямо в его настройках в админке.
- Проверить, что у всех нужных свойств инфоблока заполнены символьные коды латиницей.
- Сбросить кэш сайта после правки кода, чтобы сущность инфоблока собралась заново.
- Получить класс сущности по идентификатору инфоблока и дальше работать только через него.
- Для множественных свойств использовать добавление значения, а не присваивание всего набора.
Решение
Задаём инфоблоку код для программного интерфейса:
\Bitrix\Main\Loader::includeModule('iblock');$iblock = new \CIBlock();$iblock->Update($iblockId, ['API_CODE' => 'News']); // латиница, с большой буквы// имя класса собирается из этого кода: ElementNewsTable// после правки сбрасывают кэш: сущность собирается зановоКод задают один раз и больше не трогают. Он попадает в имя класса сущности, и переименование ломает весь код, который уже обращается к элементам этого инфоблока.
Берём класс сущности по идентификатору:
$entity = \Bitrix\Iblock\Iblock::wakeUp($iblockId)->getEntityDataClass();$rows = $entity::getList(['select' => ['ID', 'NAME'], 'filter' => ['=ACTIVE' => 'Y']])->fetchAll();// так код не зависит от имени класса и переживает переименование кода инфоблокаОбращение по идентификатору удобнее прямого имени класса. Идентификатор берут из настроек проекта, и один и тот же код работает на стенде и на боевом сайте, где номера инфоблоков различаются.
Читаем свойства объектами:
$element = \Bitrix\Iblock\Elements\ElementNewsTable::getList([ 'select' => ['ID', 'NAME', 'AUTHOR'], // свойство перечисляем явно 'filter' => ['=ID' => $id],])->fetchObject();echo $element->getAuthor()->getValue(); // значение свойства приходит объектомЗначение свойства приходит не строкой, а объектом значения. Это позволяет добраться и до самого значения, и до описания, но требует привычки: прямое сравнение объекта со строкой не работает.
Фильтруем по значению списочного свойства:
$rows = \Bitrix\Iblock\Elements\ElementNewsTable::getList([ 'select' => ['ID', 'NAME'], 'filter' => ['=SECTION_TYPE.VALUE' => 'Анонс'], // фильтр идёт по значению варианта])->fetchAll();// сравнение с текстом вместо значения варианта не даёт ни одной строкиСписочное свойство хранит идентификатор варианта, а не его текст. Фильтр по значению варианта - штатный способ, а попытка сравнить с подписью варианта возвращает пустую выборку.
Пишем множественное свойство:
$element = \Bitrix\Iblock\Elements\ElementNewsTable::getByPrimary($id)->fetchObject();$element->addToTags($valueId); // добавление значения, а не присваивание$element->save();// присваивание у множественного свойства затирает уже сохранённые значенияМножественные значения добавляют по одному, отдельными вызовами добавления. Присваивание работает у одиночных свойств, а у множественных оно ведёт себя иначе и легко стирает то, что уже сохранено.
Типичные проблемы
Ошибка об отсутствующем классе элементов.
У инфоблока не заполнен символьный код для программного интерфейса или не подключён модуль. Код задают в настройках инфоблока, а модуль подключают в начале скрипта.
Свойство не видно у объекта элемента.
У свойства не заполнен символьный код, и в карту сущности оно не попало. Код заполняют у самого свойства, после чего обязательно сбрасывают кэш сайта.
Фильтр по списочному свойству ничего не находит.
Сравнение идёт с подписью варианта вместо его сохранённого значения. Списочное свойство хранит выбранный вариант, и фильтруют именно по значению этого варианта.
После записи множественного свойства старые значения исчезли.
Значение присвоено целиком вместо добавления к уже существующему набору. У множественных свойств пользуются добавлением значения, а не присваиванием набора.
Класс элементов перестал существовать после правки настроек.
Символьный код инфоблока изменили, и имя класса сущности после этого стало другим. Обращение по идентификатору инфоблока такой правки не боится и продолжает работать.
Частые вопросы
Обязателен ли переход на объекты?
Нет, старый интерфейс выборок продолжает работать и никуда не денется. Объекты берут для нового кода, где важны типы значений и работа со связями.
Где взять имя класса элементов?
Оно складывается из символьного кода инфоблока по известному правилу. Надёжнее не писать имя руками, а получать класс по идентификатору инфоблока.
Что делать со свойствами без кода?
Заполнить код и сбросить кэш: только после этого свойство появится у объектов. Данные при заполнении кода не теряются.
Работают ли права доступа при таких выборках?
Права инфоблока в объектной выборке не применяются автоматически. Проверку прав пишут своим кодом или берут выборку старого интерфейса.
Можно ли смешивать оба интерфейса?
Да, они работают с одними и теми же данными. В одном участке кода лучше держаться одного стиля, иначе читать такой код тяжело.
Смежное
-
Выборки из инфоблоков - оглавление подтемы
-
Выборки из инфоблоков: GetList, ORM и разделы - устройство выборок целиком
-
Кэширование своей выборки: ключ, теги, сброс - кэш вокруг таких выборок
-
Объекты ORM: выборка объектами, ленивая загрузка, сохранение - тот же стиль на своих таблицах
-
Свойства инфоблока: чтение, запись и фильтрация по значению - свойства в старом интерфейсе
-
Свойство не сохраняется: разбор причин - когда запись не доходит до базы
-
Инфоблоки - устройство инфоблоков целиком
-
Сложный фильтр выборки: ИЛИ, вложенные условия, подзапросы - условия и подзапросы в тех же классах
-
Запись в инфоблок через ORM - что дописывать после сохранения объекта