Laravel 5.2 多态关系的查询范围
Laravel 5.2 query scope on polymorphic relationship
我有一个一对多的多态关系,与描述的完全一样 in documentation,除了我有投票而不是照片和投票中的整数投票列 table。像那样:
-votes
--id
--vote
--voteable_id
--voteable_type
投票模型有可投票的方法:
public function voteable()
{
return $this->morphTo();
}
但是对于我想要附加投票的模型(本例中的页面),我创建了一个 VoteableTrait,它具有 votes() morphMany 方法和我正在尝试开始工作的范围。范围将添加属于某个模型的所有投票的总和,并按总和对父模型进行排序。我尝试过的范围:
public function scopeWithVotesTrait($query)
{
return $query->with(['votes' => function($q){
$q->select(\DB::raw("SUM(vote) AS votes"), 'voteable_id')->first();
}]);
}
但是有了这个我不能 orderBy 因为 Laravel 执行 2 个不同的查询,一个用于父模型,一个用于投票。 Page::withVotesTrait()->first() 的结果将投票放入数组中:
{
"id": 1,
"votes": [
{
"votes": "-1",
"voteable_id": 1
}
]
}
我的另一个想法是执行连接而不是像这样的 ->with():
public function scopeWithVotesTrait($query, $model, $table)
{
return $query->join('votes', function($join) use($model, $table)
{
$join->on('votes.voteable_id', '=', $table . '.id')
->where('votes.voteable_type', '=', $model);
})->select('*', \DB::raw('sum(vote) as votes'))
->orderBy('votes')->groupBy($table . '.id');
}
但是,如果我每次使用示波器时都必须手动输入 $model ('App\ParentModel') 和 $table ('parent_models'),这样就超出了目的把它放在一个特征中。
那么在我的第一个范围示例中,有没有一种方法可以有效地按票数总和排序?或者是否有任何静态方法可以从 Eloquent 模型中调用,该方法将 return 模型名称和一个用于模型 table 的方法来使第二个示例工作?
关于如何制作将所有投票的总和附加到父模型并按其排序的作用域,还有其他想法吗?
我已经使用 join 将其与第二个示例一起使用。
Eloquent\Model 有一个静态方法 getTable() returns 模型 table 名称,所以我可以将它作为 $model 参数动态传递。我 php 函数 get_class() 将 return 带有 $model 参数的父模型类名的命名空间。
我想实现的正确查询:
public function scopeWithVotesTrait($query)
{
return $query->leftJoin('votes', function($join) use($model, $table)
{
$join->on('votes.voteable_id', '=', $table . '.id')
->where('votes.voteable_type', '=', $model);
})->addSelect('*', $table . '.id', \DB::raw('COALESCE(SUM(vote),0) as votes'))
->groupBy($table . '.id')->orderBy('votes');
}
我还添加了 COALESCE,如果没有找到投票,它将使查询 return 0。这样 orderBy 总是正确的。
我还指定了 * 和 parent_table.id 到 select 语句。如果没有 *,查询只会 return 我们在 select 语句中指定的任何内容。如果没有 parent_table.id,查询将不会 return 我们可能使用关系方法查询的任何模型(例如:Model::withVotesTrait()->with('some_other_child') 不会添加 some_other_child 到结果)。
我还使用了 leftJoin 而不是 join,因此它总是 return 所有父级,无论连接到它的票数如何。
我有一个一对多的多态关系,与描述的完全一样 in documentation,除了我有投票而不是照片和投票中的整数投票列 table。像那样:
-votes
--id
--vote
--voteable_id
--voteable_type
投票模型有可投票的方法:
public function voteable()
{
return $this->morphTo();
}
但是对于我想要附加投票的模型(本例中的页面),我创建了一个 VoteableTrait,它具有 votes() morphMany 方法和我正在尝试开始工作的范围。范围将添加属于某个模型的所有投票的总和,并按总和对父模型进行排序。我尝试过的范围:
public function scopeWithVotesTrait($query)
{
return $query->with(['votes' => function($q){
$q->select(\DB::raw("SUM(vote) AS votes"), 'voteable_id')->first();
}]);
}
但是有了这个我不能 orderBy 因为 Laravel 执行 2 个不同的查询,一个用于父模型,一个用于投票。 Page::withVotesTrait()->first() 的结果将投票放入数组中:
{
"id": 1,
"votes": [
{
"votes": "-1",
"voteable_id": 1
}
]
}
我的另一个想法是执行连接而不是像这样的 ->with():
public function scopeWithVotesTrait($query, $model, $table)
{
return $query->join('votes', function($join) use($model, $table)
{
$join->on('votes.voteable_id', '=', $table . '.id')
->where('votes.voteable_type', '=', $model);
})->select('*', \DB::raw('sum(vote) as votes'))
->orderBy('votes')->groupBy($table . '.id');
}
但是,如果我每次使用示波器时都必须手动输入 $model ('App\ParentModel') 和 $table ('parent_models'),这样就超出了目的把它放在一个特征中。
那么在我的第一个范围示例中,有没有一种方法可以有效地按票数总和排序?或者是否有任何静态方法可以从 Eloquent 模型中调用,该方法将 return 模型名称和一个用于模型 table 的方法来使第二个示例工作?
关于如何制作将所有投票的总和附加到父模型并按其排序的作用域,还有其他想法吗?
我已经使用 join 将其与第二个示例一起使用。 Eloquent\Model 有一个静态方法 getTable() returns 模型 table 名称,所以我可以将它作为 $model 参数动态传递。我 php 函数 get_class() 将 return 带有 $model 参数的父模型类名的命名空间。
我想实现的正确查询:
public function scopeWithVotesTrait($query)
{
return $query->leftJoin('votes', function($join) use($model, $table)
{
$join->on('votes.voteable_id', '=', $table . '.id')
->where('votes.voteable_type', '=', $model);
})->addSelect('*', $table . '.id', \DB::raw('COALESCE(SUM(vote),0) as votes'))
->groupBy($table . '.id')->orderBy('votes');
}
我还添加了 COALESCE,如果没有找到投票,它将使查询 return 0。这样 orderBy 总是正确的。
我还指定了 * 和 parent_table.id 到 select 语句。如果没有 *,查询只会 return 我们在 select 语句中指定的任何内容。如果没有 parent_table.id,查询将不会 return 我们可能使用关系方法查询的任何模型(例如:Model::withVotesTrait()->with('some_other_child') 不会添加 some_other_child 到结果)。
我还使用了 leftJoin 而不是 join,因此它总是 return 所有父级,无论连接到它的票数如何。