【问题标题】:Laravel 5 - Finding the pagination page for a modelLaravel 5 - 查找模型的分页页面
【发布时间】:2015-05-23 05:05:19
【问题描述】:

我正在构建一个基本论坛(受laracasts.com/discuss 启发)。当用户回复某个话题时:

  • 我想用他们的回复锚点将他们引导到分页回复列表的末尾(与 Laracast 的行为相同)。
  • 我还想在用户编辑其中一个回复时将其返回到正确的页面。

如何确定新回复将发布在哪个页面 (?page=x) 以及在编辑回复后如何返回正确的页面?或者,从主帖子列表中,最新回复在哪个页面上?

这是我目前的ForumPost 模型(减去一些不相关的东西)-

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

/**
 * Class ForumPost
 *
 * Forum Posts table
 *
 * @package App
 */
class ForumPost extends Model {
    /**
     * Post has many Replies
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function replies()
    {
        return $this->hasMany('App\ForumReply');
    }

    /**
     * Get the latest reply for a post
     * @return null
     */
    public function latestReply()
    {
        return $this->replies()->orderBy('created_at', 'desc')->first();
    }

}

更新

看看这个,让我知道你的想法。它的工作方式有点奇怪,但它会为给定的回复 ID 返回正确的页面,这只是一种方法:

public function getReplyPage($replyId = null, $paginate = 2)
    {
        $id = $replyId ? $replyId : $this->latestReply()->id;
        $count = $this->replies()->where('id', '<', $id)->count();

        $page = 1; // Starting with one page

        // Counter - when we reach the number provided in $paginate, we start a new page
        $offset = 0;

        for ($i = 0; $i < $count; $i++) {

            $offset++;
            if ($offset == $paginate) {
                $page++;
                $offset = 0;
            }
        }


        return $page;
    }

【问题讨论】:

  • 评论您的更新:$count % $paginate 将返回 $count/$paginate 的剩余 ($offset),因此 11%2 = 1,这将为您提供偏移量。可以使用floor($count / $paginate).. 来检查 pageno。可能会有一点改进。
  • 是的,谢谢.. 那是深夜编码,涉及到一点点酒;)我认为感谢@MirroredFate,我走在正确的轨道上,但我仍然想知道伟大的 Jeffrey Way 是如何完成的这。从那以后,我发现其他一些人试图在没有太多运气的情况下解决这个问题。主要想知道实现这一点的最有效方法实际上是什么,不确定对我的列表中的每个 Post 对象运行这些查询会产生什么样的性能影响

标签: php laravel laravel-5 laravel-pagination


【解决方案1】:

基本上,您使用的是两个值:首先,回复的索引与帖子的所有回复相关,其次是页面上的回复数。

例如,您可能有一个 id 为 301 的回复。但是,它是特定帖子的第 21 条回复。您需要通过某种方式来确定这是第 21 次回复。这实际上相对简单:您只需计算与该帖子相关但 ID 较小的回复的数量。

//get the number of replies before the one you're looking for
public function getReplyIndex($replyId)
{
    $count = $this->replies()->where('id', '<', $replyId)->count();
    return $count;
}

该方法应该返回您正在查找的回复的索引 - 当然,假设您的回复使用的是自动增量 ID。

第二个难题是确定您需要哪个页面。这是使用integer division 完成的。基本上你只是正常除数,但不要使用余数。如果您正在查看第 21 条回复,并且您对一页有 10 条回复,则您知道它应该在第三页(第 1 页:1-10、第 2 页:11-20、第 3 页:21-30)。这意味着您需要将您的回复索引除以您的每页回复数,然后加 1。这将给我们 21/10+1,使用整数除法,我们得到 3。耶!

//divides where we are by the number of replies on a page and adds 1
public function getPageNumber($index, $repliesPerPage)
{
    $pageNumber = (int) ($index/$repliesPerPage+1);
    return $pageNumber;
}

好的,现在您只需拉出该页面。这只需要一种方法,您可以在其中指定所需的页码以及对页面的回复数。然后该方法可以计算偏移量和限制,并检索您需要的记录。

public function getPageOfReplies($pageNumber, $repliesPerPage)
{
    $pageOfReplies = $this->replies()->offset($pageNumber*$repliesPerPage)->limit($repliesPerPage)->get();
    return $pageOfReplies;
}

不过,我们可以构建一个方法来获取最终回复的索引。

public function getLastReplyIndex()
{
    $count = $this->replies()->count();
    return $count;
}

太棒了!现在我们拥有了我们需要的所有构建块。我们可以构建一些简单的方法,使用我们更通用的方法来轻松检索我们需要的数据。

让我们从获取单个回复所在的整个回复页面的方法开始(随意更改名称(我假设每页有 10 个回复)):

public function getPageThatReplyIsOn($replyId)
{
    $repliesPerPage = 10;
    $index = $this->getReplyIndex($replyId);
    $pageNumber = $this->getPageNumber($index, $repliesPerPage);
    return $this->getPageOfReplies($pageNumber, $repliesPerPage);
}

为了更好地衡量,我们可以创建一个获取最终回复页面的方法。

public function getFinalReplyPage()
{
    $repliesPerPage = 10;
    $index = $this->getLastReplyIndex();
    $pageNumber = $this->getPageNumber($index, $repliesPerPage);
    return $this->getPageOfReplies($pageNumber, $repliesPerPage);
}

您可以构建各种其他方法来使用我们的构建块方法并在页面之间跳转、在回复之后或之前获取页面等。

几个注意事项

这些都在您的ForumPost 模型中,它应该与您的回复具有一对多的关系。

这些方法多种多样,旨在提供广泛的功能。不要害怕通读它们并单独测试它们以确切了解它们在做什么。它们都不是很长,所以应该不难做到。

【讨论】:

  • 您能举个例子吗?一个问题是在用户编辑回复后返回到回复所在的页面 - 例如,回复是第 2 页(共 2 页)的第一个条目。如果有人从第 1 页删除回复,正在编辑的回复现在将在页面上1 而不是第 2 页。所以我需要在保存新回复或编辑过的回复后立即获取正确的页面。
  • 感谢您的示例,除了确定特定回复位于哪个页面的问题之外,我很喜欢它。有什么想法吗?感谢您的帮助,我必须回家,但我会在几个小时后再次检查。 :)
  • 另外,另一个关键元素 - 我需要从主要帖子索引中知道回复所在的页面(如 laracasts.com 上所示)。因此,我必须有一种方法来动态获取回复的确切页面,以便创建、更新和索引。
  • 哇,这么多功能!我已经阅读了您的答案几次,但仍在尝试将它们拼凑在一起。一种方法getReplyOffset() 丢失了,或者可能使用了错误的名称 - 找不到真正匹配的任何内容..
  • @NightMICU 太酷了。函数中的问题是在执行方程式之前要转换索引...我将方程式括在括号中,现在它可以按预期工作。
【解决方案2】:

这是我想出的。如果有人对此有任何改进建议,请告诉我。我真的想知道是否有更多的 Laravel 方法可以做到这一点,我非常感谢 Jeffrey Way 分享他的秘密,因为他正在 Laracasts 做同样的事情。

/**
     * Get Reply Page
     * 
     * Returns the page number where a reply resides as it relates to pagination
     * 
     * @param null $replyId Optional ID for specific reply
     * @param bool $pageLink If True, return a GET parameter ?page=x
     * @param int $paginate Number of posts per page
     * @return int|null|string // Int for only the page number, null if no replies, String if $pageLink == true
     */
    public function getReplyPage($replyId = null, $pageLink = false, $paginate = 20)
    {
        // Find the page for a specific reply if provided, otherwise find the most 
        // recent post's ID. If there are no replies, return null and exit.
        if (!$replyId) {
            $latestReply = $this->latestReply();
            if ($latestReply) {
                $replyId = $latestReply->id;
            } else {
                return null;
            }
        }

        // Find the number of replies to this Post prior to the one in question
        $count = $this->replies()->where('id', '<', $replyId)->count();

        $page = CEIL($count / $paginate +1);

        // Return either the integer or URL parameter
        return $pageLink ? "?page=$page" : $page;
    }

【讨论】:

  • 从概念层面来看,我认为模型没有理由返回链接——当然,除非它是用于跟踪一堆链接的表的模型。此外,自动分配每个参数是危险的领域。定义一个严格的接口,一切都必须遵循,你以后会感谢自己的。最后,在这种情况下没有理由使用 for 循环。对于这类问题,你有整数除法。
  • 欣赏这些想法。它远非完美(for 循环是深夜思考,当然除法是更好的解决方案)。我最关心的是知道回复驻留在哪个页面上,以便我可以直接获得该回复的链接 - 这就是我将其包含在方法中的原因。它有助于减少实现该目标的内联代码量。
猜你喜欢
  • 2017-05-15
  • 2015-09-02
  • 2016-06-13
  • 2016-10-09
  • 2017-11-30
  • 2017-01-29
  • 2015-04-19
  • 1970-01-01
  • 2019-03-22
相关资源
最近更新 更多