Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Laravel 5 - Поиск страницы разбиения на страницы для модели

Автор вопроса: NightMICUОтветов: 2

Я работаю над созданием базового форума (на основе laracasts.com/discuss). Когда пользователь публикует ответ в теме:

  • Я хотел бы направить их в конец списка ответов с разбивкой на страницы с якорем их ответа (такое же поведение, как у Laracasts).
  • Я также хотел бы вернуть пользователя на правильную страницу, когда он редактирует один из своих ответов.

Как узнать, на какой странице будет опубликован новый ответ (?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();
    }

}

ОБНОВЛЕНИЕ

Взгляните на это и дайте мне знать, что вы думаете. Это немного странно в том, как это работает, но возвращает правильную страницу для данного идентификатора ответа, и это всего лишь один метод:

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 вернет остаток ($ offset) от $count/$paginate, поэтому 11%2 = 1 даст вам смещение. Pageno можно проверить с помощью floor($count / $paginate). Возможно, это небольшое улучшение. Luceos 21.03.2015
  • Ага, спасибо... это было кодирование поздно ночью с небольшим количеством вина;) Я думаю, что я на правильном пути благодаря @MirroredFate, но мне все еще интересно, как великий Джеффри Уэй добился этого. С тех пор я нашел несколько других людей, пытающихся понять это без особой удачи. В основном интересно, какой самый эффективный способ сделать это на самом деле, не уверен, какой удар по производительности там выполняет эти запросы для каждого отдельного объекта Post в моем списке. NightMICU 21.03.2015

phplaravellaravel-5laravel-pagination

Ответы

Ответ 1 · рейтинг 9 · MirroredFate

По сути, вы работаете с двумя значениями: во-первых, каков индекс ответа по отношению ко всем ответам на сообщение, а во-вторых, количество ответов на странице.

Например, у вас может быть ответ с идентификатором 301. Однако это 21-й ответ на конкретную публикацию. Вам нужно каким-то образом выяснить, что это 21-й ответ. На самом деле это относительно просто: вы просто подсчитываете, сколько ответов связано с этим сообщением, но имеет меньшие идентификаторы.

//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;
}

Этот метод должен возвращать индекс ответа, который вы ищете, при условии, конечно, что ваши ответы используют идентификаторы с автоинкрементом.

Вторая часть головоломки - выяснить, какая страница вам нужна. Это делается с помощью целочисленного деления. В основном вы просто делите число как обычно, но не используете остаток. Если вы смотрите на 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 · NightMICU

Вот что я придумал. Если у кого-то есть какие-либо предложения по улучшению этого, ПОЖАЛУЙСТА, дайте мне знать. Мне действительно интересно, есть ли другой способ Laravel сделать это, и я был бы очень признателен, если бы Джеффри Уэй поделился своим секретом, поскольку он делает именно это в 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;
    }

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы