ORM в инфоблоках, получение информации об элементах инфоблока на D7

Просмотров: 6103

Задача: собрать полные данные об элементах инфоблока, применяя ORM/D7, который пришел на смену устаревшему CIBlockElement::GetList.

Метод CIBlockElement::GetList в позволяет получить практически все данные об элементе: стандартные поля, свойства, цены и другие сведения.

Однако его заменила ORM-методология, где ElementTable::getList не предоставляет готового доступа ко всем данным. Для сбора полной информации, данные нужно подгружать по частям, включая использование классов Bitrix\Iblock\PropertyTable, Bitrix\Iblock\PropertyEnumerationTable и других.

Но, есть способ получить всю нужную информацию, подключив только класс Bitrix\Iblock\Iblock и используя инфоблок как сущность, то есть, фактически превращая его в виртуальный класс.

Видео пример использования ORM D7 в инфоблоках показал в одной из серий видеокурса:
Свой компонент: список объявлений пользователя

Включение ORM в инфоблоках

Для работы с ORM достаточно задать API-идентификатор в настройках инфоблока:

Получение полной информации об элементах инфоблока с использованием ORM

Пример кода c использованием ORM инфоблока:

getEntityDataClass();

// 1. Один запрос на получение всех элементов со свойствами
$getElements = $iblockClass::getList([
    'select' => [
        '*',
        'URL' => 'IBLOCK.DETAIL_PAGE_URL',
        'ATT_PREFS',                        // свойство строка (без алиаса с _)
        'MORE_PHOTO.FILE',                  // свойство файл
        'ATT_PROCESSOR.ITEM',               // свойство список
        'ATT_RELATED.ELEMENT',              // свойство привязка к элементам
        'ATT_RELATED.SECTION',              // свойство привязка к разделам
    ],
])->fetchAll();

// Собираем ID для запросов
$elementIds = [];
$sectionIds = [];
$fileIds    = [];
foreach ($getElements as $el) {
    $elementIds[] = $el['ID'];
    if (!empty($el['IBLOCK_SECTION_ID'])) {
        $sectionIds[] = $el['IBLOCK_SECTION_ID'];
    }
    if (!empty($el['DETAIL_PICTURE'])) {
        $fileIds[] = $el['DETAIL_PICTURE'];
    }
}
$sectionIds = array_unique($sectionIds);
$fileIds    = array_unique($fileIds);

// 2. Один запрос — все цены для всех элементов
$pricesResult = PriceTable::getList([
    'filter' => ['=PRODUCT_ID' => $elementIds],
    'select' => ['*'],
])->fetchAll();
$pricesByProduct = [];
foreach ($pricesResult as $price) {
    $pricesByProduct[$price['PRODUCT_ID']][] = $price;
}

// 3. Один запрос — все разделы
$sections = [];
if (!empty($sectionIds)) {
    $sectionsResult = SectionTable::getList([
        'filter' => ['ID' => $sectionIds],
        'select' => ['*'],
    ])->fetchAll();
    foreach ($sectionsResult as $section) {
        $sections[$section['ID']] = $section;
    }
}

// 4. Один запрос — остатки по всем товарам
$quantities = [];
$productsResult = ProductTable::getList([
    'filter' => ['ID' => $elementIds],
    'select' => ['ID', 'QUANTITY'],
])->fetchAll();
foreach ($productsResult as $product) {
    $quantities[$product['ID']] = $product['QUANTITY'];
}

// 5. Один запрос — пути ко всем файлам (вместо CFile::GetPath в цикле)
$filePaths = [];
if (!empty($fileIds)) {
    $filesResult = FileTable::getList([
        'filter' => ['ID' => $fileIds],
        'select' => ['ID', 'SUBDIR', 'FILE_NAME'],
    ])->fetchAll();
    foreach ($filesResult as $file) {
        $filePaths[$file['ID']] = '/upload/' . $file['SUBDIR'] . '/' . $file['FILE_NAME'];
    }
}

// 6. Обработка элементов (без доп. запросов к БД)
foreach ($getElements as $resElement) {
    $id = $resElement['ID'];

    // URL из шаблона
    $resElement['URL'] = CIBlock::ReplaceDetailUrl(
        $resElement['URL'],
        $resElement,
        true,
        'E'
    );

    // Путь к детальной картинке (из подготовленного массива)
    $resElement['DETAIL_PICTURE_SRC'] = $filePaths[$resElement['DETAIL_PICTURE']] ?? '';

    // Цены (из подготовленного массива)
    $resElement['PRICES'] = $pricesByProduct[$id] ?? [];

    // Раздел (из подготовленного массива)
    $resElement['SECTION'] = $sections[$resElement['IBLOCK_SECTION_ID']] ?? [];

    // Остатки (из подготовленного массива)
    $resElement['QUANTITY'] = $quantities[$id] ?? null;

    // SEO-свойства (ElementValues всё ещё делает запросы к b_iblock_iprop,
    // но это уже оптимизируется через внутренний кеш Bitrix)
    $ipropValues = new \Bitrix\Iblock\InheritedProperty\ElementValues(
        $resElement['IBLOCK_ID'],
        $resElement['ID']
    );
    $resElement['IPROPERTY_VALUES'] = $ipropValues->getValues();

    var_dump($resElement);
}

Метод Iblock::wakeUp получает ORM-класс инфоблока, задав его ID, после чего доступен метод getList.

В запросе getList можно использовать алиасы для свойств, чтобы ключи в массиве были удобнее для использования и не выглядели громоздкими.

В цикле перебора каждого элемента дополняем информацию: получаем URL элемента, путь к детальной картинке и данные о ценах.

Метод ::getList сгенерированного ORM класса инфоблока, как и в обычных классах D7 принимает параметры:

$res = \Запрос\К нужному классу::getList([
    'order' => // массив- сортировка
    'select' => // массив- выбираемые поля
    'filter' => // массив- фильтр
    'group' =>  // массив- группировка, order должен быть пустой
    'limit' => // число- ограничение выбираемого кол-ва
    'offset' => // число- смещение первого столбца в результате
    'count_total' => // число- дает возможность получить кол-во элементов через метод getCount()
    'runtime' =>  // массив полей сущности, создающихся динамически
    'data_doubling' => // булево (ум. false) - получение одинаковых записей
    'cache' => array( // массив-  кеширование запроса запроса
        'ttl' => 1000,
        'cache_joins' => true
    ),
]);

Получение множественных значений свойств элементов инфоблока через ORM

Если вы попытаетесь получить множественные свойства элемента, используя описанный выше метод, в результате массив будет содержать дублирующиеся элементы в зависимости от количества множественных значений у каждого элемента.

Чтобы этого избежать, можно переработать результирующий массив для обработки множественных свойств каждого элемента.

Ниже приведен упрощенный вариант с двумя множественными свойствами, из которых нам нужны только значения:

use Bitrix\Main\Loader;
use Bitrix\Iblock\Iblock;

Loader::includeModule('iblock');

$IBLOCK_ID = 2;
$iblockClass = Iblock::wakeUp($IBLOCK_ID)->getEntityDataClass();

$getElements = $iblockClass::getList([
    'select' => [
        'NAME',
        'ID',
        'BRAND_REF',    // Множественное свойство
        'MATERIAL',      // Множественное свойство
    ],
]);

$elements = [];
while ($element = $getElements->Fetch()) {
    $id = $element['ID'];

    // Если элемент еще не добавлен в массив, добавляем его
    if (!isset($elements[$id])) {
        $elements[$id] = [
            'NAME' => $element['NAME'],
            'ID' => $id,
            // Подготавливаем ключи для свойств
            'BRAND_REF_VALUE' => [],
            'MATERIAL_VALUE' => []
        ];
        // Здесь можно выполнить дополнительные обработки, из примера выше
    }

    // Добавляем значения множественных свойств только если отсутствуют
    if (
        !empty($element['BRAND_REF_VALUE']) &&
        !in_array($element['BRAND_REF_VALUE'], $elements[$id]['BRAND_REF_VALUE'])
    ) {
        $elements[$id]['BRAND_REF_VALUE'][] = $element['BRAND_REF_VALUE'];
    }
    if (!empty($element['MATERIAL_VALUE']) &&
        !in_array($element['MATERIAL_VALUE'], $elements[$id]['MATERIAL_VALUE'])
    ) {
        $elements[$id]['MATERIAL_VALUE'][] = $element['MATERIAL_VALUE'];
    }
}

foreach ($elements as $element) {
    // Распечатываем полученную информацию
    var_dump($element);
}
  • Создается запрос getList, который выбирает элементы из информационного блока, указав необходимые поля: NAME, ID и два множественных свойства BRAND_REF и MATERIAL.
  • Если элемент еще не добавлен в массив $elements, он добавляется с инициализацией массива для множественных значений.
  • Если множественные значения свойств присутствуют, они добавляются в соответствующие массивы BRAND_REF_VALUE и MATERIAL_VALUE. Добавление происходит без повторов значений.

Почему стоит использовать ORM вместо старого метода CIBlockElement::GetList

Использование ORM для работы с инфоблоками, вместо старого метода CIBlockElement::GetList, имеет ряд значительных преимуществ.

Во-первых, ORM обеспечивает структурированный и читаемый код, что особенно важно в крупных проектах с большим объемом данных и сложной логикой. ORM позволяет работать с объектами и свойствами инфоблока, как с сущностями базы данных, что упрощает манипуляции с данными и делает код более поддерживаемым.

Во-вторых, ORM интегрируется с современными механизмами кеширования и оптимизации запросов, благодаря чему уменьшается нагрузка на базу данных и ускоряется выполнение скриптов. Это делает ORM особенно ценным инструментом для масштабируемых и производительных приложений, требующих гибкости и скорости.

Стоимость разработки на 1С-Битрикс:

Индивидуальная разработка магазина

от 450 000 руб. от 5-ти недель

Разработка магазина на 1С-Битрикс с нуля. Дизайн, сборка и оптимизация производительности под конкретный проект и требования. Реализация любого функционала без ограничений готовых решений.

Интернет-магазин на готовом решении

от 100 000 руб. от 7-ми дней

Вариант для тех, кто не хочет тратить много средств на индивидуальный проект, и не имеет серьезных требований к сайту. Магазин, быстро запускается на базе одного из 200-та готовых решений.

Мобильное приложение

от 450 000 руб. от 5-ти недель

Разработка кроссплатформенного мобильного приложения, которое не уступает нативным решениям как в производительности, так и пользовательском опыте. Публикуется в AppStore, GooglePlay и RuStore

Сайт компании

от 250 000 руб. от 2-х недель

Корпоративный сайт с информационными разделами, каталогом товаров или услуг. Включает формы обратной связи карточек каталога, любое количество статичных и динамичных разделов.

Инфоресурс

от 250 000 руб. от 4-х недель

Информационный ресурс любой сложности. Сайт для СМИ, городской портал или многопользовательская доска объявлений. Внутренние форумы, блоги- по необходимости.

3D‑моделирование, визуализация

от 25 000 руб. от 3-х дней

По вашим фото, чертежам или описанию создадим 3D‑модели и отрендерим набор изображений для каталога товаров: общий вид, крупные планы и технические ракурсы или 360°‑обзор товара.