Связи
Weaver ORM определяет все метаданные связей внутри класса-маппера сущности через RelationMap. На свойствах сущностей нет атрибутов, нет рефлексии во время выполнения. Связи всегда загружаются явно — Weaver никогда не выполняет скрытые запросы за вашей спиной.
Обзор
Владеющая и обратная стороны
Каждая связь имеет одну владеющую сторону и одну обратную сторону.
- Владеющая сторона хранит внешний ключ в своей таблице (или в сводной таблице для many-to-many). Он а управляет сохранением связи.
- Обратная сторона объявляется с
mappedBy, указывающим на владеющую сторону. Изменения, внесённые только на обратной стороне, не записываются в базу данных.
Правила размещения внешних ключей
| Тип связи | Расположение FK | Метод маппера |
|---|---|---|
| Один-к-одному | В таблице «другой» сущности | hasOne |
| Один-ко-многим | В таблице «многих» сущностей | hasMany |
| Многие-к-одному | В таблице этой сущности | belongsTo |
| Многие-ко-многим | Выделенная сводная таблица | belongsToMany |
| Полиморфный один-к-одному | В таблице морфируемой сущности | morphOne |
| Полиморфный один-ко-многим | В таблице морфируемой сущности | morphMany |
Объявление связей
Связи регистрируются внутри метода relations(RelationMap $map) маппера:
protected function relations(RelationMap $map): void
{
$map->hasOne('profile', Profile::class)
->foreignKey('user_id')
->localKey('id');
$map->hasMany('posts', Post::class)
->foreignKey('user_id')
->localKey('id')
->orderBy('created_at', 'DESC');
}
HasOne
HasOne представляет связь один-к-одному, где внешний ключ находится в таблице другой сущности. User имеет один Profile; таблица profiles содержит user_id.
// src/Entity/User.php
final class User
{
public function __construct(
public readonly int $id,
public readonly string $email,
public readonly string $name,
public ?Profile $profile = null,
) {}
}
// src/Entity/Profile.php
final class Profile
{
public function __construct(
public readonly int $id,
public readonly int $userId,
public readonly string $bio,
public ?User $user = null,
) {}
}
Маппер (владеющая сторона — ProfileMapper; UserMapper хранит обратную):
// src/Mapper/UserMapper.php
protected function relations(RelationMap $map): void
{
$map->hasOne('profile', Profile::class)
->foreignKey('user_id') // колонка в таблице profiles
->localKey('id') // колонка в таблице users (PK)
->mappedBy('user'); // имя обратного свойства в Profile
}