Вы уже настроили ElementTable::getList и видите свойства в выборке, как в гайде по чтению B111, а для импорта скопировали CRUD с ElementTable::add и PROPERTY_VALUES. Цикл отрабатывает, но isSuccess() каждый раз false, в логе текст про CIBlockElement::Add, а свойства даже не начинают сохраняться. Ниже — почему add на «голом» ElementTable заблокирован в ядре CMS. И какие две рабочие ветки записи выбрать, чтобы элемент появился в админке и в том же getList.
Запрос elementtable add в 1С-Битрикс: Управление сайтом означает программное создание элемента инфоблока. Статический Bitrix\Iblock\ElementTable::add с версии 15.0.7 заблокирован и не пишет свойства. Для записи используют CIBlockElement::Add с PROPERTY_VALUES либо Element{ApiCode}Table::createObject(), PropertyValue и save(). Сегодня воспроизведите ошибку add, зафиксируйте getErrorMessages() и переключитесь на legacy Add или D7 entity по чеклисту ниже.
Речь только про коробочную CMS «Управление сайтом» на вашем хостинге, не про облачный CRM-портал. D7 ORM для инфоблоков устроен так: ElementTable удобен для чтения «шапки» элемента, а запись со свойствами вынесена в отдельные API. Старые статьи в выдаче всё ещё показывают рабочий ElementTable::add с PROPERTY_VALUES — это расходится с актуальной документацией.
Что такое ElementTable::add и почему он не создает элемент
ElementTable - общий ORM-класс таблицы b_iblock_element. Методы add, update и delete на нем с 15.0.7 намеренно возвращают ошибку ELEMENT_ENTITY_MESS_ADD_BLOCKED: ядро не хочет, чтобы свойства и индексы обходили единый путь сохранения.
Нужно: понять, что отказ - не баг вашего кода, а политика API. Не нужно: откатывать чтение на CIBlockElement::GetList только из-за блокировки add.
Делайте: один раз вызовите add с IBLOCK_ID и NAME и сохраните текст из AddResult::getErrorMessages(). Не делайте: отладку PROPERTY_VALUES на ElementTable - ключ до сохранения свойств не доходит.
use Bitrix\Main\Loader;
use Bitrix\Iblock\ElementTable;
Loader::includeModule('iblock');
$result = ElementTable::add([
'IBLOCK_ID' => 5,
'NAME' => 'test',
]);
if (!$result->isSuccess()) {
print_r($result->getErrorMessages());
}
Разберите боль после B111: чтение есть, запись упирается в стену
На практике цепочка такая: настроили Element{ApiCode}Table::getList, импорт пишете через ElementTable::add по примеру из блога. В админке пусто, в логе только напоминание про CIBlockElement::Add. Типичная ошибка — час отладки PROPERTY_VALUES, хотя ключ до сохранения свойств на ElementTable не доходит.
Делайте: держите чтение на D7 entity из B111. Не делайте: смешивать getList с ApiCodeTable и add на ElementTable - это разные уровни API.
Схема после настройки выборки:
Чтение (B111) Element{ApiCode}Table::getList → запись ветка A: CIBlockElement::Add + PROPERTY_VALUES (B90) → запись ветка B: createObject()->save() → проверка тем же getList
Подготовьте инфоблок: IBLOCK_ID, API_CODE и модуль iblock
- Подключите модуль: Loader::includeModule('iblock').
- Зафиксируйте числовой IBLOCK_ID и символьный API_CODE в настройках инфоблока.
- Убедитесь, что у свойств заполнен CODE - по нему строятся setBrand() и PROPERTY_VALUES.
- Для ветки D7 entity проверьте, что класс Element{ApiCode}Table существует (инфоблок 2.0, см. архитектуру ORM).
- Выберите ветку записи до написания цикла импорта (таблица в следующем разделе).
Результат: вы заранее знаете, будет ли createObject или только legacy Add.
Выберите ветку: CIBlockElement::Add или Element{ApiCode}Table
В реальном проекте выбор часто диктует не «мода D7», а наличие API_CODE и объём импорта.
| Критерий | CIBlockElement::Add (B90) | Element{ApiCode}Table::createObject() |
|---|---|---|
| Свойства | Ключ PROPERTY_VALUES в массиве полей | setCode(), PropertyValue, addToCode() |
| API_CODE | Не обязателен | Обязателен для compiled entity |
| Массовый импорт | Add($fields, false, false) без переиндексации поиска | save() на каждом объекте; поиск сайта - отдельно |
| Ошибки | $el->LAST_ERROR после false | $result->getErrorMessages() после save() |
Полный разбор полей Add и файлов - в статье B90. Сравнение GetList legacy и D7 - B60, без дублирования здесь.
Итоговый вердикт: разовый скрипт импорта без API_CODE - CIBlockElement::Add. Проект уже на Element{ApiCode}Table в B111 - пишите через createObject()->save(), чтобы формат свойств совпадал с getList.
Создайте элемент через CIBlockElement::Add и PROPERTY_VALUES
- Соберите массив: IBLOCK_ID, NAME, ACTIVE, IBLOCK_SECTION_ID или IBLOCK_SECTION.
- Добавьте PROPERTY_VALUES по CODE свойства: строка, число, ID перечисления для списка, CFile::MakeFileArray для файла.
- Вызовите $id = $el->Add($fields); при !$id читайте $el->LAST_ERROR.
- Для тысяч строк используйте Add($fields, false, false) и плановую переиндексацию по доке CIBlockElement::Add.
- Проверьте элемент в админке и одним getList из B111.
$el = new CIBlockElement();
$id = $el->Add([
'IBLOCK_ID' => 5,
'NAME' => 'SKU-100',
'PROPERTY_VALUES' => [
'ARTNUMBER' => 'SKU-100',
'BRAND' => 12, // ID значения списка, не текст
],
]);
if (!$id) {
echo $el->LAST_ERROR;
}
Не делайте: передавать в список текст вместо ID enum - свойство останется пустым без явной ошибки.
Сохраните элемент через Element{ApiCode}Table::createObject()
По курсу 43, урок 12868: createObject(), сеттеры полей, PropertyValue для свойств, save().
- Получите entity: ElementCatalogTable::class (подставьте свой ApiCode).
- $element = ElementCatalogTable::createObject(); $element->setName('SKU-101');
- Одиночное свойство: $element->setArtnumber('SKU-101') или new PropertyValue('значение').
- Множественное: $element->addToGallery(new PropertyValue($fileId)).
- $result = $element->save(); при ошибке - getErrorMessages().
use Bitrix\Iblock\Elements\ElementCatalogTable;
use Bitrix\Iblock\ORM\PropertyValue;
$element = ElementCatalogTable::createObject()
->setName('SKU-101')
->setArtnumber('SKU-101');
$result = $element->save();
if (!$result->isSuccess()) {
print_r($result->getErrorMessages());
}
Делайте: те же CODE, что в select B111. Результат: fetch() после создания показывает те же алиасы свойств.
Проверьте события OnBeforeIBlockElementAdd и права
И legacy Add, и D7 save() проходят через события инфоблока. Обработчик OnBeforeIBlockElementAdd может вернуть false и отменить создание без понятного LAST_ERROR.
Делайте: временно отключите свои обработчики при отладке импорта. Делайте: проверьте права на инфоблок и раздел. Не делайте: списывать отказ add на ElementTable на workflow, пока не прочитали getErrorMessages() - там будет текст блокировки.
Проверьте результат: админка и getList (B111)
- Элемент виден в списке админки с нужным NAME и разделом.
- Свойства заполнены в карточке элемента.
- Element{ApiCode}Table::getList с тем же select, что в B111, возвращает значения.
- При импорте нет дублей по уникальному CODE или ARTNUMBER.
- Если нужен поиск по сайту - учтите отличие save() и Add с bUpdateSearch (см. практику в community-обзорах ORM vs Add).
Если после правок импорт все еще "молчит", пришлите сценарий через форму контактов - разберем ветку API и обработчики. Похожие кейсы по инфоблокам - в портфолио.
Автор: Максим Мольков, разработчик 1С-Битрикс.
Источники: ElementTable::add, CIBlockElement::Add, курс 43 урок 12868, архитектура инфоблоков ORM на docs.1c-bitrix.ru.
Частые вопросы
Чем ElementTable::add отличается от CIBlockElement::Add?
ElementTable::add заблокирован и всегда возвращает ошибку с просьбой использовать CIBlockElement::Add. Рабочие варианты: CIBlockElement::Add с PROPERTY_VALUES или Element{ApiCode}Table::createObject()->save() для D7 без "голого" ElementTable.
Как передать property_values в D7 ORM?
Не через ElementTable::add. На сгенерированной entity задайте свойство методом setCode(), объектом PropertyValue или addToCode() для множественных. В legacy ветке ключ PROPERTY_VALUES остается только в массиве для CIBlockElement::Add.
Почему add вернул false без текста ошибки?
Для ElementTable::add вызывайте getErrorMessages() у AddResult. Для CIBlockElement::Add после false смотрите свойство LAST_ERROR у экземпляра класса. Пустой вывод часто значит, что смотрели не тот объект результата.
Нужен ли инфоблок 2.0 для elementtable add?
Для заблокированного ElementTable::add версия хранения не меняет отказ. Для D7 createObject нужен API_CODE и compiled Element{ApiCode}Table. CIBlockElement::Add работает и на классическом хранении свойств.
Как добавить элемент в несколько разделов?
В CIBlockElement::Add передайте IBLOCK_SECTION массивом ID разделов. В D7 entity свяжите элемент с разделами по правилам курса 43 (связь с SectionTable). Один IBLOCK_SECTION_ID - только один раздел.
Срабатывает ли OnBeforeIBlockElementAdd при save() через ORM?
Да, сохранение через Element{ApiCode}Table::save() и через CIBlockElement::Add вызывает те же события инфоблока. Отмена в OnBefore даст false или неуспешный Result без создания элемента.
Было полезно?
Поставьте лайк, если статья помогла разобраться.
Поделиться статьёй
Отправьте тому, кому это пригодится.
Можно поделиться и фрагментом: выделите текст статьи.