UserTable и ElementTable — готовые
ORM-классы D7 для работы с пользователями и элементами инфоблоков
через единый интерфейс запросов. Разберём, чем выборка через ORM
отличается от старых CUser::GetList/
CIBlockElement::GetList и когда это действительно
удобнее.
Выборка пользователей через UserTable
<?php
use Bitrix\Main\UserTable;
$result = UserTable::getList([
'select' => ['ID', 'NAME', 'EMAIL', 'LAST_LOGIN'],
'filter' => ['ACTIVE' => 'Y', '>LAST_LOGIN' => '2026-01-01'],
'order' => ['LAST_LOGIN' => 'DESC'],
'limit' => 20,
]);
while ($user = $result->fetch()) {
echo $user['NAME'] . ' — ' . $user['EMAIL'] . PHP_EOL;
}
Синтаксис фильтра с префиксами (>, <,
%, !) заменяет ручное построение условий
SQL-подобным массивом — >LAST_LOGIN означает "больше
указанной даты", без необходимости писать отдельный SQL-фрагмент.
Выборка элементов инфоблока через ElementTable
<?php
use Bitrix\Iblock\ElementTable;
$result = ElementTable::getList([
'select' => ['ID', 'NAME', 'DETAIL_PAGE_URL'],
'filter' => ['IBLOCK_ID' => 14, 'ACTIVE' => 'Y'],
'order' => ['SORT' => 'ASC'],
'limit' => 10,
]);
while ($element = $result->fetch()) {
echo $element['NAME'] . PHP_EOL;
}
Важное отличие от CIBlockElement::GetList: ORM
по умолчанию не подгружает свойства элемента — их нужно явно
описать через связи, что при простой выборке полей самого элемента
(без свойств) избавляет от лишних JOIN-ов, которые
CIBlockElement в некоторых сценариях делает неявно.
Нужна помощь с Битрикс?
Получение объекта вместо массива
<?php
$user = UserTable::getByPrimary($userId)->fetchObject();
echo $user->getName();
echo $user->getEmail();
ORM D7 позволяет получать данные не только массивом через
fetch(), но и типизированным объектом через
fetchObject() — с автогенерированными геттерами
и сеттерами, что удобно в IDE за счёт автодополнения и меньшего
риска опечатки в имени поля.
Подсчёт количества без выборки данных
<?php
$count = UserTable::getCount(['ACTIVE' => 'Y']);
Отдельный метод для подсчёта не тянет сами записи — то же
соображение, что и с отключением подсчёта в
CIBlockElement::GetList, но здесь оно оформлено
явным отдельным методом, а не побочным параметром.
Работа со связями (runtime fields)
<?php
$result = ElementTable::getList([
'select' => ['ID', 'NAME', 'SECTION_NAME' => 'IBLOCK_SECTION.NAME'],
'filter' => ['IBLOCK_ID' => 14],
]);
ORM умеет выбирать связанные данные (например, название раздела)
одним запросом с JOIN, без ручного второго вызова
CIBlockSection::GetByID — это одно из главных
практических преимуществ ORM перед старым API на выборках,
требующих связанные сущности.
Когда старый API всё ещё уместен
Не всё в старом API инфоблоков перенесено в ORM один в один — работа
со свойствами элементов через ElementTable заметно
сложнее, чем привычный PROPERTY_VALUES в
CIBlockElement::Update. Для простых CRUD-операций
с элементами, где свойства — основная часть работы, старый API
часто остаётся более коротким кодом, а ORM обычно выигрывает
на сложных выборках со связями и фильтрами.
Частые ошибки
- Ожидание автоматической загрузки свойств. ElementTable, в отличие от CIBlockElement::GetList, не подтягивает свойства без явного описания связи.
- Использование getList для одной записи вместо getByPrimary. Лишний фильтр там, где есть специализированный метод под первичный ключ.
- Игнорирование runtime-полей при выборках со связями. Ручной повторный запрос там, где ORM могла бы сделать один JOIN.
Итог
UserTable и ElementTable дают единообразный
ORM-интерфейс поверх штатных сущностей Битрикса с удобным
SQL-подобным фильтром, подсчётом без выборки и связями через
runtime-поля. Для сложных выборок со связанными данными ORM обычно
короче и понятнее старого API, а для плотной работы со свойствами
элементов старый CIBlockElement зачастую остаётся
проще.
