Односторонние и двусторонние отношения сущностей в Bitrix
Назад

Односторонние и двусторонние отношения сущностей в Bitrix

Отношения между сущностями - это фундаментальный аспект в проектировании баз данных и разработке программных приложений. В Bitrix существует несколько типов отношений между сущностями, такие как OneToOne, OneToMany и ManyToMany.

Давайте подробнее разберемся, что они представляют и как их использовать.

OneToOne (1:1)

Отношение OneToOne подразумевает, что каждый элемент одной сущности имеет ровно один элемент в другой сущности, и наоборот. Это означает, что связь между сущностями уникальна и однозначна. В Bitrix это может быть полезно, например, при связывании пользователей с их профилями.

Для демонстрации функционала, сделаем функционал привязки пользователя к его профилю в Steam.

Для начала требуется создать таблицу привязки пользователя к Steam sl_user_steam:

              <?php
namespace App\Tables;

use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields\DatetimeField;
use Bitrix\Main\ORM\Fields\IntegerField;
use Bitrix\Main\ORM\Fields\Relations\Reference;
use Bitrix\Main\ORM\Fields\StringField;
use Bitrix\Main\ORM\Query\Join;
use Bitrix\Main\Type\DateTime;

class UserSteamTable extends DataManager
{
    public static function getTableName()
    {
        return 'sl_user_steam';
    }

    public static function getMap()
    {
        return [
            new IntegerField(
                'ID',
                [
                    'primary' => true,
                    'autocomplete' => true,
                ]
            ),
            new IntegerField(
		'USER_ID',
		[
                    'required' => true,
                ]
	    ),
            new Reference(
                'USER',
                \Bitrix\Main\UserTable::class,
                Join::on('this.USER_ID', 'ref.ID')
            ),
	    new StringField(
                'STEAM_ID',
                [
                    'required' => true,
                ]
            ),
	    new DatetimeField(
                'CREATED_AT',
                [
                    'default_value' => new \Bitrix\Main\Type\DateTime(),
                ]
            ),
        ];
    }
}
         

В таблице будут созданы следующие колонки: 

ID - первичный ключ
USER_ID - первичный ключ пользователя в таблице \Bitrix\Main\UserTable.
STEAM_ID - номер профиля в Steam
CREATED_AT - дата и время создания записи в таблице (в параметре указано стандартное значение актуальной даты и времени - не обязательно для заполнения с использованием add D7).

Помимо колонок перечисленных выше, имеется запись new Reference - это и есть привязка элемента сущности к модели таблицы пользователей в Битрикс - \Bitrix\Main\UserTable.

В join указывается два параметра:
this.USER_ID - это поле, к чему будет привязано отношение из данной таблицы
ref.ID- это поле, на которое будет происходить связь в таблице UserTable.
Если оба поля совпадают по значению - это и будет наша связь.

Далее, создаем таблицу (например в командной строке в “Административной панели”):

              
$connection = \Bitrix\Main\Application::getConnection(); $entity = \App\Tables\UserSteamTable::getEntity(); if (!$connection->isTableExists(\App\Tables\UserSteamTable::getTableName())) { $entity->createDbTable(); echo "Таблица успешно создана!"; }

После успешного создания таблицы, создайте несколько строк с тестовыми данными, например:

              $array = [
    [
        'USER_ID' => 1,
        'STEAM_ID' => '76561197960287930',
    ],
    [
        'USER_ID' => 2,
        'STEAM_ID' => '76561197960287555',
    ],
];

$result = \App\Tables\UserSteamTable::addMulti($array);
if($result->isSuccess()) {
    echo "Тестовые данные созданы!";
}
         

Теперь можем воспользоваться тестовыми данными и, например, вывести json из данных с OneToOne связью.

              $query = \App\Tables\UserSteamTable::getList([
    'select' => [
        '*', 
        'USER', // обязательно указываем reference в селекте
    ],
]);

$result = [];

while($item = $query->fetchObject()) {
    // Функция вывода отношений через fetchObject используется вида: get|Название reference|
    $user = $item->getUser();
	
    // Как только мы получили объект пользователя $user
    // мы можем использовать функционал таблицы \Bitrix\Main\UserTable
    // либо методами ООП, либо, как массив
    $result[] = [
	'steam_id' => $item['STEAM_ID'],
	'user' => [
	    'id' => $user->getId(),
	    'name' => $user->getName(),
	    'email' => $user['EMAIL'],
	],
    ];
}

$json = json_encode($result, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);

print_r($json);
         

Результат выполнения кода:

              [
    {
        "steam_id": "76561197960287930",
        "user": {
            "id": 1,
            "name": "Гендальф",
            "email": "dev@skillline.ru"
        }
    },
    {
        "steam_id": "76561197960287555",
        "user": {
            "id": 2,
            "name": "Анонимный пользователь",
            "email": "anonymous_wdJw1hI5y@example.com"
        }
    }
]
         

OneToMany (1:N)

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

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

В таблице \Bitrix\Main\UserTable уже присутствует отношение OneToMany:

              (new OneToMany('GROUPS', UserGroupTable::class, 'USER'))
				->configureJoinType(Join::TYPE_INNER),
         

Для его использования, добавляем его в select, так же попробуем использовать фильтрацию через отношения сущностей:

              $query = \App\Tables\UserSteamTable::getList([
    'select' => [
        '*', 
        'USER',
        'USER.GROUPS', // указываем через точку с указанием родителя
    ],
    'filter' => [
        'USER.GROUPS.GROUP_ID' => [1], // фильтрация пользователей по группе с ID 1
    ]
]);

$result = [];

while($item = $query->fetchObject()) {
    $user = $item->getUser();

    // получаем группы пользователя и используем функцию getAll() для получения всех групп
    // т.к. отношение ОдинКоМногим
    $groups = $user ? $user->getGroups()->getAll() : [];
	
    $groupsIdList = [];
    foreach($groups as $group) {
        // b_user_group -> GROUP_ID
        $groupsIdList[] = $group->getGroupId();
    }

    $result[] = [
        'steam_id' => $item['STEAM_ID'],
        'user' => [
            'id' => $user->getId(),
	    'name' => $user->getName(),
	    'email' => $user['EMAIL'],
	    'groups' => $groupsIdList,
	],
    ];
}

$json = json_encode($result, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);

print_r($json);
         

В результате выполнения кода:

              [
    {
        "steam_id": "76561197960287930",
        "user": {
            "id": 1,
            "name": "Гендальф",
            "email": "dev@skillline.ru",
            "groups": [
                1
            ]
        }
    }
]
         

ManyToMany (N:M)

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

Пример промежуточной таблицы CategoryProductTable:

              class CategoryProductTable extends DataManager
{
    public static function getMap()
    {
        return [
            new IntegerField('ID', [
                'primary' => true,
                'autocomplete' => true,
            ]),
            new IntegerField('PRODUCT_ID'),
            new IntegerField('CATEGORY_ID'),
        ];
    }
}
         

В таблице с товарами - указывается отношение ManyToMany с таблицей CategoryProductTable и в таблице с категориями аналогично.

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

Заключение

Отношения OneToOne, OneToMany и ManyToMany являются мощными инструментами для моделирования связей между сущностями в Bitrix.

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

Отправить запрос

Напишите нам и мы свяжемся с вами сразу после ознакомления с запросом (в рабочее время ~10 минут ожидания)

Россия, г. Калининград, ул.Уральская, 18, этаж 4, оф. 4, оф. 6