Laravel 5.2查询范围内的多态关系

Dev*_*evK 7 php laravel eloquent laravel-5.2

我有一对多的多态关系,完全像文档中描述的那样,除了我在投票表中有投票而不是照片和整数投票列.像那样:

-votes
--id
--vote
--voteable_id
--voteable_type
Run Code Online (Sandbox Code Playgroud)

投票模型具有可投票的方法:

public function voteable()
{
    return $this->morphTo();
}
Run Code Online (Sandbox Code Playgroud)

但是对于我希望附加投票的模型(本例中的页面),我创建了一个VoteableTrait,它具有votes()morphMany方法和我试图开始工作的范围.范围将添加属于某个模型的所有投票的总和,并按总和对父模型进行排序.我试过的范围:

public function scopeWithVotesTrait($query)
{
    return $query->with(['votes' => function($q){
        $q->select(\DB::raw("SUM(vote) AS votes"), 'voteable_id')->first();
    }]);
}
Run Code Online (Sandbox Code Playgroud)

但是,由于Laravel执行2个不同的查询,一个用于父模型,一个用于投票,因此我无法订购.Page :: withVotesTrait() - > first()的结果将投票放在一个数组中:

{
"id": 1,
    "votes": [
    {
        "votes": "-1",
        "voteable_id": 1
    }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我的另一个想法是执行连接而不是 - > 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');
}
Run Code Online (Sandbox Code Playgroud)

但是如果我每次使用示波器时都必须手动输入$ model('App\ParentModel')和$ table('parent_models'),那么这就是将其置于特征中的目的.

那么在我的第一个范围示例中,有没有一种方法可以通过投票总和进行有效排序?或者是否有任何静态方法可以从Eloquent Model调用返回模型名称,还有一个用于模型表以使第二个示例有效?

任何其他想法如何制作一个范围,将所有投票的总和附加到父模型和它的订单?

Dev*_*evK 4

我已经让它与使用 join 的第二个示例一起使用。Eloquent\Model 有一个静态方法 getTable() ,它返回模型表名称,因此我可以动态地将其作为 $model 参数传递。我的 php 函数 get_class() 将为 $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');
}
Run Code Online (Sandbox Code Playgroud)

我还添加了 COALESCE,如果没有找到投票,这将使查询返回 0。这样 orderBy 总是正确的。

我还指定了 * 和parent_table.id 来选择语句。如果没有 *,查询将只返回我们在 select 语句中指定的内容。如果没有parent_table.id,查询将不会返回我们可能使用关系方法查询的任何模型(例如:Model::withVotesTrait()->with('some_other_child') 不会将 some_other_child 添加到结果中)。

我还使用 leftJoin 而不是 join,以便它始终返回所有父级,无论与其相关的投票数如何。