Как выбрать элементы инфоблока в Битрикс: GetList или D7 ORM?

Как выбрать элементы инфоблока в Битрикс: GetList или D7 ORM?

Вы открываете legacy-компонент с CIBlockElement::GetList, копируете arFilter из форума, а в профайлере сыпется 200 SQL-запросов на 200 элементов. В чате советуют "переписать на D7", но ElementTable::getList ругается на Unknown field PROPERTY_PRICE. Ниже - честное сравнение двух способов выборки элементов инфоблока в 1С-Битрикс: Управление сайтом: когда оставить старый GetList, когда переходить на D7 ORM и как убрать N+1 одним запросом.

CIBlockElement::GetList и Element{API_CODE}Table::getList решают одну задачу - достать элементы инфоблока из базы - но по-разному. Старый API живет в компонентах и тянет свойства через PROPERTY_* в arSelect. D7 ORM требует символьный код API и режим инфоблока 2.0, зато дает один SQL, кеш и автодополнение в IDE. Оба API можно держать в одном проекте.

Речь про коробочную CMS на вашем сервере, не про облачную CRM того же вендора. Если инфоблок еще не создан или без API-кода, сначала пройдите гайд по созданию инфоблока - без этого D7-ветка не заработает.

Выберите API выборки под задачу, а не под моду

Сравнительная таблица CIBlockElement::GetList и D7 ORM getList по критериям выбора API

CIBlockElement::GetList - классический метод старого ядра: вы передаете массивы arFilter, arSelect, arOrder и получаете CDBResult. Это как заказать блюдо по номеру в меню: синтаксис знакомый, примеров в сети море, штатные компоненты news.list и catalog.section уже на нем сидят.

D7 ORM getList - современный слой (Object-Relational Mapping, "объектно-реляционное отображение": PHP-класс описывает таблицу, а фреймворк собирает SQL). Для инфоблока класс называется ElementCatalogTable, если API-код инфоблока Catalog. Запрос выглядит как filter/select/order у ORM, результат - объекты с геттерами вместо плоского массива.

Делайте: для нового сервисного слоя (импорт, API, cron) берите D7, если инфоблок готов. Не делайте: не переписывайте рабочий компонент "ради моды" - выигрыш часто минимален, а риск регрессии высок.

Подготовьте инфоблок 2.0 и символьный код API

Инфографика: подготовка инфоблока 2.0 и символьного кода API для D7 ORM в Битрикс

D7 ORM для свойств элемента не работает "из коробки" через общий ElementTable - нужен именованный класс инфоблока. Три обязательных шага:

  1. Проверьте символьный код API в настройках инфоблока (поле API_CODE, латиница без пробелов, например Catalog). Если пусто - заполните по инструкции из гайда по созданию инфоблока.
  2. Включите режим инфоблока 2.0 - хранение свойств в отдельных таблицах. Без этого D7 не увидит PRICE, BRAND и другие пользовательские поля.
  3. Получите класс сущности в коде: через Iblock::wakeUp($iblockId)->getEntityDataClass() - это строка вроде \Bitrix\Iblock\Elements\ElementCatalogTable.

Старый GetList при этом продолжит работать на том же инфоблоке - режим 2.0 обратно совместим.

use Bitrix\Iblock\Iblock;

$iblockId = 5;
$dataClass = Iblock::wakeUp($iblockId)->getEntityDataClass();
// Например: \Bitrix\Iblock\Elements\ElementCatalogTable

Делайте: фиксируйте API-код до первого D7-запроса. Не делайте: не вызывайте Bitrix\Iblock\ElementTable::getList для свойств - этот класс знает только системные поля элемента, без PRICE и прочих.

Разберите CIBlockElement::GetList без ловушки N+1

Схема workflow: как избежать N+1 при CIBlockElement::GetList в Битрикс

Канонический вызов по официальной справке:

$res = CIBlockElement::GetList(
    ['SORT' => 'ASC'],
    ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y', 'PROPERTY_BRAND' => 12],
    false,
    ['nTopCount' => 50],
    ['ID', 'NAME', 'PROPERTY_PRICE', 'PROPERTY_BRAND']
);
while ($row = $res->GetNext()) {
    // $row['PROPERTY_PRICE_VALUE'], $row['NAME']
}

На практике типичная ошибка - наследовать news.list с GetNextElement() без PROPERTY_* в arSelect. В реальном проекте с каталогом из 200 SKU профайлер покажет 200+ SQL-запросов: в цикле вызывают GetNextElement() и GetProperties(), и на каждый элемент уходит отдельный запрос. Исправление: перечислите нужные PROPERTY_* прямо в arSelect и используйте GetNext(), либо соберите ID в первом проходе и сделайте один GetList с фильтром по ID.

Второй подводный камень - лишние поля в arSelect. Каждое PROPERTY_* может добавить JOIN. Держите список узким: только то, что реально выводите на странице.

Делайте: arNavStartParams с nTopCount или постраничкой, CHECK_PERMISSIONS => N только в доверенном серверном коде. Не делайте: не тяните DETAIL_TEXT и все свойства "на всякий случай".

Настройте D7 getList с кешем и отладкой SQL

Эквивалент выборки каталога на ORM:

$dataClass = \Bitrix\Iblock\Iblock::wakeUp(5)->getEntityDataClass();

$rows = $dataClass::getList([
    'select' => ['ID', 'NAME', 'PRICE_' => 'PRICE.VALUE', 'BRAND_' => 'BRAND.VALUE'],
    'filter' => ['=ACTIVE' => 'Y', '=BRAND.VALUE' => 12],
    'order' => ['SORT' => 'ASC'],
    'limit' => 50,
    'cache' => ['ttl' => 3600, 'cache_joins' => true],
])->fetchCollection();

foreach ($rows as $item) {
  echo $item->getName();
  echo $item->getPrice()?->getValue();
}

Алиасы PRICE_ => PRICE.VALUE дают плоское поле в fetchAll и объект в fetchCollection. Для сложных типов свойств (файл, привязка к элементу) используйте fetchCollection и геттеры - fetchAll "ломает" вложенность при связях один-ко-многим.

Отладка: после getList вызовите getLastQuery() у Connection - увидите реальный SQL и сравните с legacy-вариантом.

Делайте: cache с ttl для редко меняющихся выборок. Не делайте: не копируйте arFilter один в один - синтаксис другой (=ACTIVE, =PRICE.VALUE).

Сравните legacy и D7 по таблице и чек-листу

Критерий CIBlockElement::GetList Element{CODE}Table::getList
Синтаксис Массивы arFilter, arSelect filter, select, order, limit
Свойства в выборке PROPERTY_* в arSelect, JOIN на каждое поле Алиасы PRICE_ => PRICE.VALUE из prop-таблицы 2.0
Риск N+1 Высокий при GetNextElement + GetProperties Ниже: один запрос + fetchCollection
IDE и автодополнение Строковые ключи массива Типизированные геттеры getPrice()
Отладка SQL Профайлер, лог MySQL getLastQuery() сразу после запроса
Где оставить Штатные компоненты, DETAIL_PAGE_URL, нет API-кода Новые сервисы, импорт, REST, агрегации

Соответствие параметров: arFilter IBLOCK_ID + ACTIVE → filter =IBLOCK_ID и =ACTIVE; arSelect PROPERTY_PRICE → select PRICE_ => PRICE.VALUE; arOrder SORT ASC → order SORT ASC; arNavStartParams nTopCount → limit.

Итоговый вердикт: если правите только шаблон news.list и инфоблок без API-кода - оставьте GetList, но уберите N+1 через arSelect. Если пишете новый модуль на инфоблоке 2.0 - берите D7 ORM и проверяйте SQL через getLastQuery. После выборки для изменения полей смотрите гайд по CIBlockElement::Update.

Исправьте N+1: пошаговый workflow

Схема миграции legacy-цикла без "большого взрыва":

Профайлер → узкий arSelect → один GetList → (опционально) D7 getList → getLastQuery → выкат
  1. Снимите базовую линию в профайлере Битрикс: сколько SQL на странице каталога сейчас.
  2. Найдите цикл с GetNextElement() или GetProperties() внутри while - это главный кандидат.
  3. Перечислите свойства в arSelect (PROPERTY_PRICE, PROPERTY_BRAND) и перейдите на GetNext().
  4. Сравните SQL до и после - цель один запрос на список, а не на элемент.
  5. Если инфоблок 2.0 готов - перепишите тот же фильтр на D7 getList с cache ttl.
  6. Проверьте фронт: цены, картинки, фильтр по бренду совпадают с legacy.
  7. Зафиксируйте правило в код-ревью: запрет GetProperties() внутри цикла списка.

Нужна помощь с аудитом тормозящего каталога на Битрикс - обсудим задачу и разберем конкретный инфоблок.

Что сделать после выбора API

  1. Убедитесь, что API-код заполнен (см. B28).
  2. Выберите ветку по таблице выше - legacy или D7.
  3. Прогоните страницу через профайлер и getLastQuery.
  4. Для записи изменений в элемент откройте гайд по Update (B40).
  5. Добавьте обработчик событий, если выборка триггерит побочную логику.
  6. Зафиксируйте выбранный API в README модуля, чтобы команда не смешивала GetList и D7 в одном цикле.
Автор: Максим Мольков, разработчик 1С-Битрикс.
Источники: CIBlockElement::GetList, документация D7, архитектура инфоблоков 2.0, форум 1С-Битрикс (getList и свойства).

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

Чем CIBlockElement::GetList отличается от D7 getList?

GetList - legacy-метод с массивами arFilter/arSelect, живет в компонентах. D7 getList у класса Element{API_CODE}Table дает ORM-синтаксис, кеш и типизированные объекты, но требует API-код и инфоблок 2.0 для свойств.

Нужен ли символьный код API для D7?

Да. Без API_CODE класс ElementTable не знает ваши свойства PRICE, BRAND и т.д. Заполните поле в админке и получите класс через Iblock::wakeUp()->getEntityDataClass().

Работает ли старый GetList на инфоблоке 2.0?

Да, режим 2.0 обратно совместим. Можно держать компонент на GetList, а новый сервисный код писать на D7 параллельно.

Как включить кеш в D7 ORM для инфоблока?

Передайте в getList параметр cache: ['ttl' => 3600, 'cache_joins' => true]. ttl - время жизни в секундах; cache_joins кеширует JOIN по связям.

Когда оставить GetList вместо миграции на D7?

Оставьте, если правите только шаблон штатного компонента, нужен DETAIL_PAGE_URL из выборки, нет API-кода или сроки не позволяют тестировать ORM. Уберите хотя бы N+1 через arSelect.

Как отфильтровать элементы по свойству в GetList?

В arFilter добавьте PROPERTY_CODE => значение, например 'PROPERTY_BRAND' => 12. Для диапазона цен используйте PROPERTY_PRICE от и до. В D7 эквивалент: '=BRAND.VALUE' => 12 в filter.

fetchCollection или fetchAll - что выбрать?

Для списка с файлами, множественными свойствами и привязками берите fetchCollection и геттеры getPrice()->getValue(). fetchAll удобен для плоских полей без вложенных связей один-ко-многим.

Читайте также

Интеграции с 1С и API
949 6 мин.

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

Пошаговая настройка регистрации на сайте битрикс: Главный модуль, main.register, system.auth.form и sale.personal.section с историей заказов и 152-ФЗ.
Интеграции с 1С и API
676 15 мин.

Что такое компонент в Битриксе и как он работает

Каждый разработчик, впервые столкнувшийся с Битриксом, проходит через своеобразный обряд посвящения. Вначале кажется, что это просто CMS, где можно поправить HTML в визуальном редакторе или дописать пару строк CSS. Но однажды наступает момент, когда нужно изменить логику вывода новостей, отфильтровать товары по хитрому свойству или добавить на страницу нечто совершенно новое. И тут он впервые слышит это слово — «компонент». Для многих этот момент становится стеной. Система, казавшаяся понятной, вдруг превращается в черный ящик, полный непонятных файлов и странных переменных. Но стоит лишь раз заглянуть под капот, как эта стена рассыпается, превращаясь в набор удивительно логичных и мощных строительных блоков. Понимание компонентов — это тот самый щелчок, после которого разработка на Битрикс из мучения превращается в творчество.

Эта статья — ваш проводник в мир компонентов «1С-Битрикс». Мы не будем сыпать сухими терминами из документации. Вместо этого мы совершим путешествие: от философии, заложенной в эту архитектуру, до мельчайших деталей её работы. Мы разберем компонент на атомы — его файлы, логику, шаблон, параметры — и соберем обратно, чтобы вы не просто знали, что это, но и глубоко понимали, почему это работает именно так. Это знание — ключ к эффективной и профессиональной разработке на Битрикс.

Интеграции с 1С и API
605 2 мин.

Установка Composer в 1С-Битрикс

Установка Composer в проекте на 1С-Битрикс требует учета особенностей платформы, чтобы обеспечить корректную работу и интеграцию с системой.