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