Мне нужно определить одно отношение через другое отношение в Laravel, чтобы оба отношения могли быть загружены оптимальным образом.
Например, у меня есть таблицы item
и attr
с промежуточной таблицей attr_item
. В Yii2 я могу определить одно отношение через другое, используя метод via
:
class Item extends ActiveRecord
{
public function getAttrItems()
{
return $this->hasMany(AttrItem::class, ['item_id' => 'id']);
}
public function getAttrs()
{
return $this-hasMany(Attr::class, ['id' => 'attr_id'])->via('attrItems');
}
}
Поэтому, когда я вызываю $item = Item::find()->with('attrs')->where(['id' => 1])->one()
, Yii2 выполняет два дополнительных запроса: к таблице attr_item
с условием item_id = 1
и ктаблица attr
с идентификаторами, найденными в предыдущем запросе. Что-то вроде:
SELECT * FROM "item" WHERE "id"=1
SELECT * FROM "attr_item" WHERE "item_id"=1
SELECT * FROM "attr" WHERE "id" IN (1, 2, 3)
После этого у меня два заполненных отношения: $item->attrs
и $item->attrItems
.
Но я не нашел такой же функциональности в Laravel. Я могу определить $this->hasManyThrough(Attr::class, AttrItem::class, 'item_id', 'id', 'id', 'attr_id')
или $this->belongsToMany(Attr::class, 'attr_item', 'item_id', 'attr_id', 'id', 'id')
в Item
классе, но он делает только один запрос к БД, например:
select
"attr".*,
"attr_item"."item_id" as "pivot_item_id",
"attr_item"."attr_id" as "pivot_attr_id"
from
"attr"
inner join "attr_item" on "attr"."id" = "attr_item"."attr_id"
where
"attr_item"."item_id" = '1';
И, конечно, он не гидратирует отношение attrItems
, потому что нетинформация о промежуточных отношениях. Я могу с готовностью загрузить оба отношения attrs
и attrItems
, но в этом случае промежуточная таблица attr_item
будет использоваться дважды, и это плохо для производительности.