Eloquent 与条件范围的关系
Eloquent Relationship with a conditional scope
我正在开发一款 Fantasy 体育应用程序。我正在使用的模型是 FantasyPlayer、PlayerGame、TeamGame
FantasyPlayer可以有很多PlayerGame,也可以有很多TeamGame
public function PlayerGame()
{
return $this->hasMany('App\Models\PlayerGame','player_id','player_id');
}
public function TeamGame()
{
return $this->hasMany('App\Models\FantasyData\TeamGame','team','fantasy_player_key');
}
当我加载数据时,我目前使用预先加载:
FantasyPlayer::with(['PlayerGame', 'TeamGame'])->take(1)->get();
加载两个关系然后再加载哪个关系变得很乏味。理想情况下,我想让模型处理这个逻辑。所以我可以做这样的事情:
FantasyPlayer::with(['FantasyGame'])->take(1)->get();
然后我的 FantasyGame 范围将根据位置的 FantasyPlayer 值包含我需要的 PlayerGame 或 TeamGame 记录。像这样的东西是我想要的......但它对我不起作用:
public function scopeFantasyGame($query)
{
if($this->position == "DEF"){
return $this->TeamGame();
}
else{
return $this->PlayerGame();
}
}
有谁知道我可以使用预先加载并让 FantasyGame return 基于 FantasyPlayer 位置属性的正确关系的方法吗?:
FantasyPlayer::with(['FantasyGame'])->take(1)->get();
#1
您不能根据结果元素有条件地预先加载关系,这是因为预先加载发生在您检索记录之前,这就是为什么这不起作用:
# FantasyPlayer.php
public function scopeFantasyGame($query)
{
if($this->position == "DEF") // <--- Laravel doens't retrieve the records yet,
{ // so this won't work
//
}
else
{
//
}
}
#2
Local Query scopes 用于约束查询,在您的情况下,您希望加载与此范围的关系,而不是它的一般用途,但确保您可以做到:
# FantasyPlayer.php
public function scopeFantasyGame($query)
{
return $query->with(['PlayerGame', 'TeamGame']);
}
然后像这样使用它:
# YourController.php
public function myFunction($query)
{
$fantasyPlayers = FantasyPlayer::fantasyGame()->get();
}
#3
但是,如果您想始终预加载关系,为什么要使用查询范围而不是告诉 laravel 默认加载您想要的关系?你可以在你的模型中指定它(检查 Eager Loading By Default of this section of the docs):
# FantasyPlayer.php
protected $with = ['PlayerGame', 'TeamGame'];
更新
如果您想要检索始终具有给定关系的元素,您有两条路径。对于第一个,您可以使用查询范围仅加载这些元素:
# FantasyPlayer.php
public function scopeHasFantasyGame($query)
{
return $query
->has('PlayerGame')
->has('TeamGame');
}
然后:
# YourController.php
public function myFunction($query)
{
$fantasyPlayers = FantasyPlayer::hasFantasyGame()->get();
}
第二个选项是检索元素,然后根据关系的存在过滤集合(使用 Map() 函数):
# YourController.php
public function myFunction($query)
{
$fantasyPlayers = FantasyPlayer::all()
->map(function ($fantasyPlayer) {
return $fantasyPlayer->PlayerGame()->exists()
&& $fantasyPlayer->TeamGame()->exists();
});
}
我正在开发一款 Fantasy 体育应用程序。我正在使用的模型是 FantasyPlayer、PlayerGame、TeamGame
FantasyPlayer可以有很多PlayerGame,也可以有很多TeamGame
public function PlayerGame()
{
return $this->hasMany('App\Models\PlayerGame','player_id','player_id');
}
public function TeamGame()
{
return $this->hasMany('App\Models\FantasyData\TeamGame','team','fantasy_player_key');
}
当我加载数据时,我目前使用预先加载:
FantasyPlayer::with(['PlayerGame', 'TeamGame'])->take(1)->get();
加载两个关系然后再加载哪个关系变得很乏味。理想情况下,我想让模型处理这个逻辑。所以我可以做这样的事情:
FantasyPlayer::with(['FantasyGame'])->take(1)->get();
然后我的 FantasyGame 范围将根据位置的 FantasyPlayer 值包含我需要的 PlayerGame 或 TeamGame 记录。像这样的东西是我想要的......但它对我不起作用:
public function scopeFantasyGame($query)
{
if($this->position == "DEF"){
return $this->TeamGame();
}
else{
return $this->PlayerGame();
}
}
有谁知道我可以使用预先加载并让 FantasyGame return 基于 FantasyPlayer 位置属性的正确关系的方法吗?:
FantasyPlayer::with(['FantasyGame'])->take(1)->get();
#1
您不能根据结果元素有条件地预先加载关系,这是因为预先加载发生在您检索记录之前,这就是为什么这不起作用:
# FantasyPlayer.php
public function scopeFantasyGame($query)
{
if($this->position == "DEF") // <--- Laravel doens't retrieve the records yet,
{ // so this won't work
//
}
else
{
//
}
}
#2
Local Query scopes 用于约束查询,在您的情况下,您希望加载与此范围的关系,而不是它的一般用途,但确保您可以做到:
# FantasyPlayer.php
public function scopeFantasyGame($query)
{
return $query->with(['PlayerGame', 'TeamGame']);
}
然后像这样使用它:
# YourController.php
public function myFunction($query)
{
$fantasyPlayers = FantasyPlayer::fantasyGame()->get();
}
#3
但是,如果您想始终预加载关系,为什么要使用查询范围而不是告诉 laravel 默认加载您想要的关系?你可以在你的模型中指定它(检查 Eager Loading By Default of this section of the docs):
# FantasyPlayer.php
protected $with = ['PlayerGame', 'TeamGame'];
更新
如果您想要检索始终具有给定关系的元素,您有两条路径。对于第一个,您可以使用查询范围仅加载这些元素:
# FantasyPlayer.php
public function scopeHasFantasyGame($query)
{
return $query
->has('PlayerGame')
->has('TeamGame');
}
然后:
# YourController.php
public function myFunction($query)
{
$fantasyPlayers = FantasyPlayer::hasFantasyGame()->get();
}
第二个选项是检索元素,然后根据关系的存在过滤集合(使用 Map() 函数):
# YourController.php
public function myFunction($query)
{
$fantasyPlayers = FantasyPlayer::all()
->map(function ($fantasyPlayer) {
return $fantasyPlayer->PlayerGame()->exists()
&& $fantasyPlayer->TeamGame()->exists();
});
}