opheliadesign's avatar

Find the pagination page where an item will be placed or exists

Hi everyone,

I am making a forum very similar to this one (it's my inspiration). When a user posts a reply to a thread I'd like to direct them to the end of the list of paginated replies with their reply's anchor (same behavior as this forum). I'd also like to return the user to the correct page when they edit one of their replies.

How can I figure out which page a new reply will be posted on (?page=x) and how can I return to the correct page after a reply has been edited? Or, from the main post listing, which page the latest reply is on?

Here is my current ForumPost model (minus a few unrelated things) -

<?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()
    {
        $reply = $this->replies()->orderBy('created_at', 'desc')->first();
        if ($reply) {
            return $reply;
        } else {
            return null;
        }
    }

}

@JeffreyWay I know that you build this forum on your own, any tips? I'm not looking to distribute this code, just using it for a client.

Thanks!

0 likes
6 replies
opheliadesign's avatar

Anyone have any suggestions? Is there a method in pagination that might be able to handle this?

olimorris's avatar

Hmmmmm. Some outline thoughts...

Okay, so firstly you'd need to workout the order of the single reply in your total results. Say we have 10 results in your replies table (all have id's from 1 to 10) and we want to workout what page id 7 would be on. We could use the following:

SELECT x.id, 
       x.position,
       x.body
  FROM (SELECT r.id,
               r.body,
               @rownum := @rownum + 1 AS position
          FROM Replies r
          JOIN (SELECT @rownum := 0) s
      ORDER BY r.id) x
 WHERE x.id = '7'

Calling the returned result $rowOrder, the row with id 7 would of course have a value of 7. i.e. it is the seventh row in your query.

Using the number of rows you want on each paginated page ($paginated = 2 for example). You could use the following formula to workout the page number of id 7:

$pageNumber = CEIL($rowOrder / $paginated)

This would workout id 7 would be on page 4 of 5. Dividing an order of 7 by 2 returns 3.5 and rounding that up with CEIL would bring you to 4, which would be our page.

Apologies, unstructured thoughts at a late hour.

opheliadesign's avatar

@olimorris Very late hour! Thanks for the suggestion. Another thing that I would like to do is also have a link to the proper page on the forum index, also like what we have here at Laracasts. If you look at the URL for the most recent post (Updated 2 minutes ago), the link includes the page for that post. I'd think that you would want this lookup to be as minimalistic as possible so you aren't slowing everything down, so there has to be a simple way to accomplish this.

And I know one person that knows how to do this for sure, @JeffreyWay pleaseeee? With a cherry on top? I have a feeling that this knowledge will be extremely helpful in the future for other things as well.

opheliadesign's avatar

I came up with this, one method call and it returns the desired page number - thoughts? My only concern is performance - the index will have 20 posts per page, so this will be executed 20 times on each index page.

@JeffreyWay, I already love you but I'd love you even more if you could share your secret. ;)

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

Please or to participate in this conversation.