假设我的模型Post
有多个Comments
。
我也发现了一些评论:
$comment = Comment::find(12);
接下来,我想根据updated_at
列找到下一个和之前的评论。
例如:
文章:
╔════╦══════════════╦══════╗
║ ID ║ Name ║ Smtn ║
╠════╬══════════════╬══════╣
║ 1 ║ First Post ║ 5636 ║
║ 2 ║ Second Post ║ 148 ║
╚════╩══════════════╩══════╝
评论:
╔════╦══════════════╦═════════╦════════════╗
║ ID ║ Comment ║ post_id ║ updated_at ║
╠════╬══════════════╬═════════╣════════════╣
║ 1 ║ First Comm ║ 1 ║ 123 ║
║ 2 ║ Second Post ║ 2 ║ 124 ║
║ 3 ║ Third Post ║ 1 ║ 126 ║
║ 4 ║ Fourth Post ║ 2 ║ 125 ║
║ 5 ║ Fifth Post ║ 1 ║ 128 ║
║ 6 ║ Sixsth Post ║ 1 ║ 127 ║
╚════╩══════════════╩═════════╩════════════╝
我的评论是id为3的那个:
$comment = Comment::find(3);
如何定义previous()
和next()
以获取updated_at
列的评论并获取上一个和下一个的评论?在这种情况下:
一个:
║ 1 ║ First Comm ║ 1 ║ 123 ║
下一步:
║ 6 ║ Sixsth Post ║ 1 ║ 127 ║
updated_at
是数据库中的DATETIME(带时区)字段。我懒得写出确切的代码。
答案 0 :(得分:1)
在答案中看到这样做会得到正确的结果,但不建议这样做。
代码将获得与帖子相关的所有注释,应用顺序以及通过PHP数组操作的位置,然后为您提供过滤的注释。实际上在->comments
之后,一切都是PHP。
如果评论的编号从数百到数千或更多,取决于您的硬件,这将非常糟糕。
要解决这个问题,你应该这样做;
$subjectComment = Comment::whereId($commentId)->with('post')->first();
$post = $subjectComment->post;
$previousComment = $post->comments()
->where('updated_at', '<=', $subjectComment->updated_at)
->where($subjectComment->getKeyName(), '!=', $subjectComment->getKey())
->latest('updated_at')
->first();
$nextComment = $post->comments()
->where('updated_at', '>', $subjectComment->updated_at)
->oldest('updated_at')
->first();
注意区别?没有?这是一个简短的解释;
将关系用作模型的属性,例如$ post-&gt; comments
此语法在某些情况下具有某些优点,在其他情况下具有缺点。这就是Eloquent在幕后所做的事情;
将关系用作模型的函数,例如$ post-&gt; comments()
此语法返回查询而不是模型,您可以进一步自定义以满足您的需要。该查询类似于;
Comment::whereHas('post', function ($q) use ($postId) {
$instance = new Post;
$q->where($instance->getQualifiedKeyName(), $postId);
});
两种陈述都没有区别。两者都会在相同的时间内完成同样的事情。唯一的区别是可读性。
答案 1 :(得分:0)
我看起来并不高兴,但我没有看到更好的方法来做到这一点,这对我来说很有意义。如果您有任何想法,请回复。
可能存在拼写错误,因为我的代码有点复杂,而且我的模型有不同的名称。如果您发现任何错误,请报告。
//get current comment with id 12
$comment = Comment::->find(12);
//get parent post
$post = $comment->post;
//get all comments of this post
$comments = $post->comments->orderBy('updated_at',ASC)->get();
//some helper variables because I don't know the better way
$prev = null; // the previous comment
$next = null; // the next comment
$counter=0; //helper counter
//iterate through all comments
foreach ($comments as $commentIterated) {
//if this is my comment increase the counter
if($commentIterated->id == $comment->id) {
$counter++;
} elseif ($counter == 1) { //if counter is increased only once increase it again and save current comment as the next one (since in previous iteration we concluded that that was our comment and hence increased the counter first time)
$next = $commentIterated;
$counter++;
} elseif ($counter == 0){ //if counter is not increased current comment is previous one, but this will be rewritten in next iteration if we don't find our comment again
$prev = $commentIterated;
}
$comments->shift(); // Laravel helper method to remove the current element () from the collection so we are left with rest of collection and current instance is again first object in collection which is the next object in this iteration
}
return view('my_view', compact('comment','prev','next'));
专家的快速提问:
将替换此
//get parent post
$post = $comment->post;
//get all comments of this post
$comments = $post->comments->orderBy('updated_at',ASC)->get();
用这个
//get all comments of this post
$comments = $comment->post->comments->orderBy('updated_at',ASC)->get();
让事情变得更快?我不确定此方法链接在后台如何工作。有没有一种简单的方法可以在Laravel / PHP中对这些查询进行基准测试?
答案 2 :(得分:0)
这应该比你现在所做的更干净。只需选择1个相关评论,其中第一个updated_at低于或高于$ comment
$previous = $post->comments->orderBy('updated_at', 'DESC')->take(1)->where('updated_at', '<', $comment->updated_at)->first();
$next = $post->comments->orderBy('updated_at', 'ASC')->where('updated_at', '>', $comment->updated_at)->first();