← К документации

Ядро

D7 ORM, Query и Join

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

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

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

Примеры внутреннего PHP API предназначены для коробки с подключённым ядром. Прямое чтение таблиц здесь — административная диагностика: оно само по себе не проверяет доступ пользователя к найденным объектам. Не публикуйте такой код как открытый HTTP-обработчик.

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('USER_ID'),
        ];
    }
}

getList

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

<?php

use test\Example\Model\ExampleTable;

function fetchItemsByCrmEntityId(int $crm_entity_id): array {
    $items = [];

    $item_result = ExampleTable::getList([
        'select' => [
            'ID',
            'TITLE',
            'USER_ID',
        ],
        'filter' => [
            '=USER_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,
        'USER_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;

function fetchItemsWithQuery(int $crm_entity_id): array {
    $query = new Query(ExampleTable::getEntity());

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

    $query->setFilter([
        '=USER_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;

function fetchItemsQuerySql(int $crm_entity_id): string {
    $query = new Query(ExampleTable::getEntity());

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

    return $query->getQuery();
}

$sql = fetchItemsQuerySql($crm_entity_id);

echo $sql;

Join

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

ReferenceField

Пример: у своей таблицы есть USER_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',
    ]
);

Источники