按他们获得的点数排序评论,Laravel 5.2 多态关系
Posted
技术标签:
【中文标题】按他们获得的点数排序评论,Laravel 5.2 多态关系【英文标题】:Order comments by amount of points they got, Laravel 5.2 polymorphic relationship 【发布时间】:2016-08-18 08:51:17 【问题描述】:我有 3 个表画廊、评论和投票,我的投票表是多态的,因为投票可以添加到画廊或评论中,它们看起来像这样:
评论:
id
user_id
gallery_id
content
投票:
id
user_id
votable_type
votable_id
status
状态可以是“赞成”或“反对”。每个评论都可以被赞成或反对。 cmets 拥有的点数是根据 count('upvote') - count('downvote') 计算的。 votable_type 可以是 'App\Gallery' 或 'App\Comment'
我想获取所有的 cmets 并按点数对它们进行排序,最高点数的评论位于顶部。
我该怎么做?到目前为止,我有这个简单的代码,但它没有按点数计算选票或对 cmets 进行排序:
Comment::with('votes')->with('owner')
->where('gallery_id', $gallery->id)
->paginate(5);
【问题讨论】:
【参考方案1】:您可以在集合上使用sortBy
方法,不幸的是,在这种情况下您不能使用标准分页:
Comment::with('votes')->with('owner')
->where('gallery_id', $gallery->id)
->sortBy(function($comment,$key)
return $comment->votes->count();
);
这将返回一个集合,其中包含按投票数排序的所有 cmets。
【讨论】:
【参考方案2】:我认为您可以使用查询构建器使用带有分组和排序的连接来完成此操作,但我相信半年后当您审查代码时查询会相当困难且不容易消化。
一个更简单的选择是在 Comment
模型上创建一个返回点数的方法,类似于以下内容:
public function getPointsAttribute()
$points = 0;
foreach ($this->votes AS $vote)
$points = $vote->status == 'upvote' ? $votes + 1 : $votes - 1;
return $points;
然后在从数据库中取出Comments
的集合后对其进行排序:
Comment::where('gallery_id', $gallery->id)->get()->sortBy('points');
您可以使用forPage()
对集合进行分页,请参阅docs。
【讨论】:
尝试在集合上使用forPage()
方法。
我还会考虑简化 Votes
模型,也许使用有符号整数 vote
字段来代替字符串 status
字段。然后它的值可以是 -1 或 1。
调用 getPointsAttribute 时出现错误:ErrorException in Votable.php line 40: Undefined variable: votes.
知道为什么吗?我的投票功能如下所示:public function votes() return $this->morphMany(Vote::class, 'votable');
不知道,看起来不错。像这样调试它:'dd(Comment::find(1)->votes())' 看看你是否得到了一个查询构建器实例。
如果我用括号添加 votes() 那么它就可以工作。我不得不像这样重写 getPointsAttribute:$upvotes = $this->votes()->where('status', 'upvote')->count(); $downvotes = $this->votes()->where('status', 'downvote')->count(); $points = $upvotes - $downvotes;
奇怪的是它在类中不起作用。在控制器中,我这样做了$comment = Comment::where('id',$request->comment)->first();
,然后dd($comment->votes);
这次没有在选票上使用括号,它奏效了,它给了我所有选票的清单。但在 Votable 类中使用 $this->votes 失败。【参考方案3】:
我想通了,这就是诀窍:
$comments = Comment::with('votes')->with('owner')
->where('gallery_id', $gallery->id)
->leftJoin('votes', 'votes.votable_id', '=', 'comments.id')
->selectRaw(
'comments.*, count(case votes.status when "upvote" then 1 else null end) - count(case votes.status when "downvote" then 1 else null end) as points'
)
->where('votes.votable_type','App\Comment')
->groupBy('comments.id')
->orderBy('points', 'desc')
->paginate(5);
【讨论】:
这不会让最近的帖子获得任何可见性,例如here's reddit 如何进行这种排序以上是关于按他们获得的点数排序评论,Laravel 5.2 多态关系的主要内容,如果未能解决你的问题,请参考以下文章
如何改进我的查询以防止“PHP 致命错误:允许的内存大小”(laravel 5.2 中的排序和分页)