Отношения между сущностями - это фундаментальный аспект в проектировании баз данных и разработке программных приложений. В Bitrix существует несколько типов отношений между сущностями, такие как OneToOne, OneToMany и ManyToMany.
Давайте подробнее разберемся, что они представляют и как их использовать.
Отношение 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
- номер профиля в SteamCREATED_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 подразумевает, что каждый элемент одной сущности может быть связан с несколькими элементами в другой сущности. Например, один пользователь может иметь несколько групп.
Возьмем пример кода выше, но, добавим пользователю привязку к группам.
В таблице \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 предполагает, что каждый элемент одной сущности может быть связан с несколькими элементами другой сущности, и наоборот. Это отношение обычно реализуется через промежуточную таблицу, которая хранит пары идентификаторов связанных элементов.
Пример промежуточной таблицы 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 минут ожидания)