Блог Горошко Андрея 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

Как работать с DateTime и Date объектами в D7 для корректной обработки датКак работать с DateTime и Date объектами в D7 для корректной обработки дат

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

Обновление количества товара на складе в BitrixОбновление количества товара на складе в Bitrix

Средний рейтинг Еще нет оценок Обновление количества товара на складе в Bitrix можно сделать так В коде ниже происходит следующее: Мой рейтинг:

Всплывающие окна в Битрикс: Создание и управление с помощью BX.PopupWindowВсплывающие окна в Битрикс: Создание и управление с помощью BX.PopupWindow

Средний рейтинг Еще нет оценок Всплывающие (модальные) окна — неотъемлемая часть современного интерфейса. Битрикс предоставляет мощный и гибкий JS-класс BX.PopupWindow для их создания и управления. Шаг 1: Базовое создание окна Для создания