← Назад к справке

Ядро

D7 ORM, Query и Join

Рабочая справка по D7 ORM в Bitrix Framework: Table-классы, getList, Query, runtime-поля, ReferenceField и Join.

D7 ORM удобен, когда нужно читать и изменять данные через Table-классы. Для простых выборок часто хватает getList(), для сложных связей удобнее использовать Query и runtime-поля.

D7 ORM

ORM в D7 строится вокруг Table-классов, которые описывают таблицу и её поля.

Что такое Table-класс

Table-класс обычно наследуется от DataManager и описывает имя таблицы и карту полей.

<?php

namespace test\Example\Model;

use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields;

class ExampleTable extends DataManager
{
    /**
     * Возвращает имя таблицы.
     */
    public static function getTableName(): string
    {
        return 'b_test_example_item';
    }

    /**
     * Возвращает карту полей.
     */
    public static function getMap(): array
    {
        return [
            new Fields\IntegerField('ID', [
                'primary' => true,
                'autocomplete' => true,
            ]),
            new Fields\StringField('TITLE', [
                'required' => true,
            ]),
            new Fields\IntegerField('CRM_ENTITY_ID'),
        ];
    }
}

getList

getList() — основной способ получить список записей из ORM-таблицы.

<?php

use test\Example\Model\ExampleTable;

/**
 * Получает элементы по ID CRM-сущности.
 */
function fetchItemsByCrmEntityId(int $crm_entity_id): array
{
    $items = [];

    $item_result = ExampleTable::getList([
        'select' => [
            'ID',
            'TITLE',
            'CRM_ENTITY_ID',
        ],
        'filter' => [
            '=CRM_ENTITY_ID' => $crm_entity_id,
        ],
        'order' => [
            'ID' => 'ASC',
        ],
        'limit' => 100,
    ]);

    while ($item = $item_result->fetch()) {
        $items[] = $item;
    }

    return $items;
}

$items = fetchItemsByCrmEntityId($crm_entity_id);

print_r($items);

add, update, delete

<?php

use test\Example\Model\ExampleTable;

/**
 * Добавляет элемент.
 */
function addExampleItem(string $title, int $crm_entity_id): array
{
    $result = ExampleTable::add([
        'TITLE' => $title,
        'CRM_ENTITY_ID' => $crm_entity_id,
    ]);

    return [
        'is_success' => $result->isSuccess(),
        'item_id' => (int) $result->getId(),
        'error_messages' => $result->getErrorMessages(),
    ];
}

/**
 * Изменяет название элемента.
 */
function updateExampleItemTitle(int $item_id, string $title): array
{
    $result = ExampleTable::update($item_id, [
        'TITLE' => $title,
    ]);

    return [
        'is_success' => $result->isSuccess(),
        'error_messages' => $result->getErrorMessages(),
    ];
}

/**
 * Удаляет элемент.
 */
function deleteExampleItem(int $item_id): array
{
    $result = ExampleTable::delete($item_id);

    return [
        'is_success' => $result->isSuccess(),
        'error_messages' => $result->getErrorMessages(),
    ];
}

Query

Query удобен, когда нужно собрать выборку пошагово.

Когда нужен Query

  • нужно собрать сложную выборку постепенно;
  • нужно добавить runtime-поля;
  • нужно посмотреть итоговый SQL;
  • нужно настроить join или выражение.

setSelect, setFilter, setOrder

<?php

use Bitrix\Main\ORM\Query\Query;
use test\Example\Model\ExampleTable;

/**
 * Получает элементы через объект Query.
 */
function fetchItemsWithQuery(int $crm_entity_id): array
{
    $query = new Query(ExampleTable::getEntity());

    $query->setSelect([
        'ID',
        'TITLE',
        'CRM_ENTITY_ID',
    ]);

    $query->setFilter([
        '=CRM_ENTITY_ID' => $crm_entity_id,
    ]);

    $query->setOrder([
        'ID' => 'ASC',
    ]);

    $query->setLimit(100);

    return $query->exec()->fetchAll();
}

$items = fetchItemsWithQuery($crm_entity_id);

print_r($items);

Посмотреть SQL

При отладке сложных ORM-запросов удобно вывести итоговый SQL.

<?php

use Bitrix\Main\ORM\Query\Query;
use test\Example\Model\ExampleTable;

/**
 * Возвращает SQL ORM-запроса.
 */
function fetchItemsQuerySql(int $crm_entity_id): string
{
    $query = new Query(ExampleTable::getEntity());

    $query
        ->setSelect([
            'ID',
            'TITLE',
        ])
        ->setFilter([
            '=CRM_ENTITY_ID' => $crm_entity_id,
        ]);

    return $query->getQuery();
}

$sql = fetchItemsQuerySql($crm_entity_id);

echo $sql;

Join

Связи в ORM можно описывать через runtime-поля и ReferenceField.

ReferenceField

Пример: у своей таблицы есть CRM_ENTITY_ID, а нужно подтянуть данные пользователя из UserTable.

<?php

use Bitrix\Main\UserTable;
use Bitrix\Main\ORM\Fields\Relations\Reference;
use Bitrix\Main\ORM\Query\Join;
use test\Example\Model\ExampleTable;

/**
 * Получает элементы с ответственным пользователем.
 */
function fetchItemsWithUser(): array
{
    return ExampleTable::getList([
        'select' => [
            'ID',
            'TITLE',
            'USER_ID',
            'USER_NAME' => 'USER.NAME',
            'USER_LAST_NAME' => 'USER.LAST_NAME',
        ],
        'runtime' => [
            new Reference(
                'USER',
                UserTable::class,
                Join::on('this.USER_ID', 'ref.ID')
            ),
        ],
        'order' => [
            'ID' => 'ASC',
        ],
        'limit' => 100,
    ])->fetchAll();
}

$items = fetchItemsWithUser();

print_r($items);

Join::on

Join::on() делает условие связи читаемее: слева поле текущей таблицы, справа поле связанной таблицы.

new Reference(
    'USER',
    UserTable::class,
    Join::on('this.USER_ID', 'ref.ID')
);

join_type

Если нужен не левый join, можно указать тип соединения.

new Reference(
    'USER',
    UserTable::class,
    Join::on('this.USER_ID', 'ref.ID'),
    [
        'join_type' => 'inner',
    ]
);

Источники