Laravel 5 — Поиск страницы пагинации для модели

Я работаю над созданием основного форума (вдохновленный 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;
}

3

Решение

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

Например, у вас может быть ответ с идентификатором 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. Yay!

//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 модель, которая должна иметь отношение один-ко-многим с вашими ответами.

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

5

Другие решения

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

По вопросам рекламы [email protected]