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

时间:2016-02-16 22:41:59

标签: php laravel eloquent laravel-5.2

我有一对多的多态关系,就像描述in documentation一样,除了我在投票表中有投票而不是照片和整数投票列。像那样:

-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();
    }]);
}

但有了这个,我无法订购,因为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 Model调用返回模型名称,还有一个用于模型表以使第二个示例有效?

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

1 个答案:

答案 0 :(得分: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');
}

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

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

我还使用了leftJoin而不是join,这样无论连接的票数多少,它都会返回所有父母。