我有一些关系(我希望可以正确解释)并且需要通过本质上是远距离的关系对输出进行排序。
我有一个数据透视表,其中包含许多关系的详细信息,包括我想要排序的关系。
- user.php的
public function players()
{
return $this->belongsToMany('App\Models\Player', 'league_player_user')->withPivot('position_id');
}
- Player.php
public function position()
{
return $this->belongsToMany('App\Models\Position', 'league_player_user');
}
我会非常渴望加载这种关系;
$user = User::with('players')->where('id', Auth::user()->id)->first();
所以,我想我想做这样的事情(不起作用)。
$user = User::with(['players' => function($q){
$q->orderBy('position.sort_id', 'asc');
}])->where('id', Auth::user()->id)->first();
关键表结构看起来有点像这样;
league_player_user.
...league_id
...player_id
...user_id
...position_id
Positions表包含sort_id
希望这是足够的信息,如果需要请提供更多信息。非常感谢。
答案 0 :(得分:1)
好的,所以你试图让一个用户,但他们的玩家(用户bTM玩家)已经按位置填充和排序(其中bT位置为枢轴)。
在这种情况下,您无法在不进行修改的情况下使用Laravel的内置关系方法,因为Laravel并不是为了处理其他关系的数据透视表上的关系而构建的。幸运的是,ORM具有足够的灵活性,可以让您通过手册'加入。
所以直接回答你的问题,这里是你需要的代码类型(你真的非常接近!):
$user = User::with(['players' => function ($q) {
$q->join('position', 'league_player_user.position_id', '=', 'position.id')
->orderBy('position.sort_id', 'asc');
}])->where('id', Auth::user()->id)->first();
然而,在我看来,由于以下几个原因,这不是很好的代码:
Auth::user()
方便时)league_player_user
并将其放在......无论在哪里(您的控制器?)User
某种其他方式(例如Auth::user()
或User::find(1)
或其他任何方式),您将无法获得球员正确订购因此,我可以建议,为了使您的查询更简单,您不要急于加载玩家。因此,您需要预先做的就是:
$user = Auth::user();
现在,关于User
类中的关系(players()方法),您可以进行特殊订购工作:
public function players()
{
return $this->belongsToMany('App\Models\Player', 'league_player_user')
->withPivot('position_id')
->join('position', 'league_player_user.position_id', '=', 'position.id')
->orderBy('position.sort_id');
}
这样,只要您拨打$user->players
,就会得到正确的订单。
我必须补充说,以这种方式这样做可能不会让你急于加载玩家,因为Laravel因为Laravel的方式而急于加载(即在ORM链中使用->with()
)急切的加载查询 - 一个用于主要查询(即用户),一个用于关系(即玩家),但它执行此查询以获得所有结果,因此可能无法使用特殊订购系统。你必须看看你是否真的关心加载球员的热情。在您的情况下(您获得单一授权用户),在我看来,急切加载并不重要。
编辑以添加有关预先加载的说明:
我认为急切加载可能不起作用的理由是,Laravel中的热切加载是这样的:说你有类别和产品:Category
hM Product
,Product
bT Category
。要使用$category = Category::find(1)
获取类别,Laravel会将其转换为查询,如下所示:SELECT * FROM `categories` WHERE `id` = '1'
。如果您随后致电$category->products
,Laravel将发出SELECT * FROM `products` WHERE `category_id` = '1'
。这是明智的。但如果你有以下代码,那就更糟了:
<?php $categories = Category::all(); ?>
<ul>
@foreach ($categories as $category)
<li>Category {{{ $category->name }}} contains {{{ $category->products->count() }}} products.</li>
@endforeach
</ul>
在这种情况下,您有以下疑问:
SELECT * FROM `categories`;
SELECT * FROM `products` WHERE `category_id` = '1';
SELECT * FROM `products` WHERE `category_id` = '2';
SELECT * FROM `products` WHERE `category_id` = '3';
... as many categories as you had
但是,如果您要将第一行更改为:
<?php $categories = Category::with('products')->get(); ?>
现在您只有两个问题:
SELECT * FROM `categories`;
SELECT * FROM `products` WHERE `category_id` IN ('1', '2', '3', ...);
然后,在调用第二个查询后,Laravel将根据您知道的类别ID为您创建各种集合。
然而,这是简单的关系案例。在您的情况下,products()
方法不仅仅是return $this->hasMany('Product');
,还包括一个数据透视表和一个手动连接等,而第二个查询可能是一个急切的加载,只是无法正确应对并做到这一点。
正如我所说,我不确定这是如何运作的,这对我来说只是一个红旗。一定要试一试,看看你得到了什么 - 你可能会发现它对你有用。