Блог Горошко Андрея 1C-Битрикс Сила связей в D7 ORM: JOIN’ы и ReferenceField на практике

Сила связей в D7 ORM: JOIN’ы и ReferenceField на практике

Средний рейтинг
Еще нет оценок

Мы уже умеем выбирать данные из одной таблицы с помощью getList. Но настоящая мощь ORM проявляется, когда нужно в одном запросе получить связанные данные из нескольких таблиц (сделать JOIN). В D7 ORM за это отвечает ReferenceField.

ReferenceField создается «на лету» в runtime-параметре запроса. Он описывает, как одна сущность связана с другой.

Задача: Получить список элементов инфоблока и имена их создателей

В таблице элементов (b_iblock_element) есть поле CREATED_BY, которое хранит ID пользователя. Нам нужно, используя этот ID, «подтянуть» имя и фамилию пользователя из таблицы пользователей (b_user).

Подготовка:

use Bitrix\Main\Loader;
use Bitrix\Iblock\ElementTable;
use Bitrix\Main\Entity; // Не забываем импортировать!

Loader::includeModule('iblock');

Решение с помощью ReferenceField:

$result = ElementTable::getList([
    'select' => [
        'ID',
        'NAME',
        'AUTHOR_NAME' => 'USER.NAME',
        'AUTHOR_LAST_NAME' => 'USER.LAST_NAME'
    ],
    'filter' => ['=IBLOCK_ID' => 5],
    'runtime' => [
        // Описываем связь
        new Entity\ReferenceField(
            'USER', // 1. Псевдоним для связи
            \Bitrix\Main\UserTable::class, // 2. Класс сущности, с которой связываемся
            ['=this.CREATED_BY' => 'ref.ID'] // 3. Условие связи (JOIN ON)
        )
    ]
]);

while ($row = $result->fetch()) {
    echo "{$row['NAME']} (Автор: {$row['AUTHOR_NAME']} {$row['AUTHOR_LAST_NAME']})<br>";
}

Разбор ReferenceField:

  1. ‘USER’: Это псевдоним (алиас), который мы придумываем для нашей связи. Мы будем использовать его в select.
  2. \Bitrix\Main\UserTable::class: Указываем, к какой ORM-сущности мы «присоединяемся».
  3. [‘=this.CREATED_BY’ => ‘ref.ID’]: Это условие JOIN.
    • this — это наша основная сущность (ElementTable). this.CREATED_BY — это поле в ней.
    • ref — это сущность, к которой мы присоединяемся (UserTable). ref.ID — это поле в ней.
    • В итоге это транслируется в SQL … ON ElementTable.CREATED_BY = UserTable.ID.

Пример 2: Связь элемента с Highload-блоком

Предположим, у нас есть свойство элемента типа «Привязка к элементам highload-блоков» (UserType hlblock). Нам нужно получить элемент и значение поля из привязанного элемента HL-блока.

  1. Сначала получаем DataClass для HL-блока (как в статье про HL-блоки). Допустим, он называется MyColorTable.
  2. Свойство привязки имеет код COLOR. В базе данных оно хранится как PROPERTY_COLOR.

// ... получение $entityDataClass для HL-блока ...
$colorEntityClass = $entityDataClass; // Например, \MyColorTable::class

$result = ElementTable::getList([
    'select' => [
        'ID',
        'NAME',
        'COLOR_NAME' => 'COLOR_REF.UF_NAME' // UF_NAME - поле в HL-блоке
    ],
    'filter' => ['=IBLOCK_ID' => 5],
    'runtime' => [
        new Entity\ReferenceField(
            'COLOR_REF',
            $colorEntityClass,
            ['=this.PROPERTY_COLOR.VALUE' => 'ref.ID'] // Условие по значению свойства
        )
    ]
]);
  • Обратите внимание на this.PROPERTY_COLOR.VALUE. ORM понимает такой синтаксис и автоматически строит JOIN к таблице значений свойств.

Совмещение с ExpressionField

ReferenceField отлично работает в паре с ExpressionField для выполнения агрегатных функций.

Задача: Посчитать, сколько элементов создал каждый пользователь.

$result = \Bitrix\Main\UserTable::getList([
    'select' => ['ID', 'LOGIN', 'ELEMENTS_COUNT'],
    'filter' => ['=ACTIVE' => 'Y'],
    'runtime' => [
        // Сначала описываем связь "один ко многим"
        new Entity\ReferenceField(
            'ELEMENTS',
            \Bitrix\Iblock\ElementTable::class,
            ['=this.ID' => 'ref.CREATED_BY']
        ),
        // Затем используем эту связь для подсчета
        new Entity\ExpressionField(
            'ELEMENTS_COUNT',
            'COUNT(%s)',
            ['ELEMENTS.ID']
        )
    ]
]);

while ($row = $result->fetch()) {
    echo "Пользователь {$row['LOGIN']} создал {$row['ELEMENTS_COUNT']} элементов.<br>";
}

Вывод:
ReferenceField — это мощнейший инструмент, который открывает доступ к сложным реляционным запросам прямо из PHP, сохраняя код чистым и объектно-ориентированным. Освоив runtime поля, вы сможете решать практически любые задачи по выборке данных, избегая «сырых» SQL-запросов и множественных циклов в коде.

D7 ORM, ReferenceField, JOIN, Bitrix ORM, связи таблиц, runtime, ExpressionField, сложные запросы.

Мой рейтинг:

Добавить комментарий

Related Post

Создание своей ORM-сущности в Битрикс: DataManager и getMap с нуляСоздание своей ORM-сущности в Битрикс: DataManager и getMap с нуля

Средний рейтинг Еще нет оценок D7 ORM позволяет работать не только со стандартными сущностями (ElementTable, UserTable), но и описывать свои собственные для любых таблиц в базе данных. Это позволяет получить все преимущества

Свойства элементов Битрикс: Работа со Списком, Файлом и ПривязкойСвойства элементов Битрикс: Работа со Списком, Файлом и Привязкой

Средний рейтинг Еще нет оценок При добавлении или обновлении элементов через API (CIBlockElement::Add/Update) работа с простыми свойствами (строка, число) интуитивно понятна. Однако сложные типы, такие как «Список», «Файл» и «Привязка

Управление разделами инфоблоков в Битрикс: CIBlockSection::GetList, Add, UpdateУправление разделами инфоблоков в Битрикс: CIBlockSection::GetList, Add, Update

Средний рейтинг Еще нет оценок Разделы инфоблоков — это основа для построения каталогов, иерархических списков и любой другой вложенной структуры на сайте. Для работы с ними в старом API Битрикс