Как создать элемент инфоблока в D7 ORM, если ElementTable::add заблокирован?

Вы уже настроили 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 и почему он не создает элемент

Сравнение API записи элемента инфоблока: ElementTable, legacy Add и D7 entity

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: чтение есть, запись упирается в стену

Workflow: чтение через ElementTable работает, запись требует другой API

На практике цепочка такая: настроили 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

Чеклист подготовки инфоблока перед созданием элемента в D7
  1. Подключите модуль: Loader::includeModule('iblock').
  2. Зафиксируйте числовой IBLOCK_ID и символьный API_CODE в настройках инфоблока.
  3. Убедитесь, что у свойств заполнен CODE - по нему строятся setBrand() и PROPERTY_VALUES.
  4. Для ветки D7 entity проверьте, что класс Element{ApiCode}Table существует (инфоблок 2.0, см. архитектуру ORM).
  5. Выберите ветку записи до написания цикла импорта (таблица в следующем разделе).

Результат: вы заранее знаете, будет ли 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

  1. Соберите массив: IBLOCK_ID, NAME, ACTIVE, IBLOCK_SECTION_ID или IBLOCK_SECTION.
  2. Добавьте PROPERTY_VALUES по CODE свойства: строка, число, ID перечисления для списка, CFile::MakeFileArray для файла.
  3. Вызовите $id = $el->Add($fields); при !$id читайте $el->LAST_ERROR.
  4. Для тысяч строк используйте Add($fields, false, false) и плановую переиндексацию по доке CIBlockElement::Add.
  5. Проверьте элемент в админке и одним 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().

  1. Получите entity: ElementCatalogTable::class (подставьте свой ApiCode).
  2. $element = ElementCatalogTable::createObject(); $element->setName('SKU-101');
  3. Одиночное свойство: $element->setArtnumber('SKU-101') или new PropertyValue('значение').
  4. Множественное: $element->addToGallery(new PropertyValue($fileId)).
  5. $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)

  1. Элемент виден в списке админки с нужным NAME и разделом.
  2. Свойства заполнены в карточке элемента.
  3. Element{ApiCode}Table::getList с тем же select, что в B111, возвращает значения.
  4. При импорте нет дублей по уникальному CODE или ARTNUMBER.
  5. Если нужен поиск по сайту - учтите отличие 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 без создания элемента.

Обсудить вашу задачу

Было полезно?

Поставьте лайк, если статья помогла разобраться.

Поделиться статьёй

Отправьте тому, кому это пригодится.

Telegram ↗ MAX ↗ ВКонтакте ↗ Одноклассники ↗
Все статьи ↗

Как настроить регистрацию и личный кабинет покупателя на 1С-Битрикс?

Структура шаблонов сайта в Битриксе и поиск header footer

Как настроить скидки и промокоды на 1С-Битрикс: правила корзины и купоны