Hi,

I've written my own pagination but one last bit left and need help. I have the array wbelow:

Array
(
    [First] => First
    [<] => <
    [1] => 1
    [2] => 2
    [3] => 3
    [4] => 4
    [5] => 5
    [6] => 6
    [7] => 7
    [8] => 8
    [9] => 9
    [10] => 10
    [11] => 11
    [12] => 12
    [13] => 13
    [14] => 14
    [15] => 15
    [16] => 16
    [17] => 17
    [18] => 18
    [19] => 19
    [20] => 20
    [21] => 21
    [22] => 22
    [>] => >
    [Last] => Last
)

This is what I want to approach:

First < 1 2 3 4 5 6 7 8 9 10 ... > Last
First < ... 11 12 13 14 15 16 17 18 19 20 ... > Last
First < ... 21 22 > Last

What I mean is, when I am on number 10, it should start printing second line. When I am on number 20 the third line. Vice versa.

Note: I can do without dots if it is easier for you.

Thanks in advance

Recommended Answers

All 15 Replies

This is just an idea (not tested) of how would I do it (I am actually using a PEAR Pager package which is excellent for this task):

If your current page is $current then your first key is (floor($current/10)*10) +1 and the last key is first key + 9 (hopefuly there is simplest way to calculate this).

$first_key =  (floor($current/10) * 10) + 1;
$last_key = $first_key + 9;

Display the links to pages:

// link to the first page
$links = '<a href="page_1.php">First</a>';

// calculate previous page
$prev = $current > 1 ? ($current - 1) : 1;

// link to the previous page with the less than coded for html
$links .= "<a href=\"page_{$prev}.php\">&lt;</a>";

// three dots
$links .= ' ... ';

// links to the current set of pages
for($i = $first_key; $i <= $last_key; $i++) {

    if($i == $current) {

        // do not create a link since it is the current page
        $links .= "<span class=\"current-page\">$i</span> ";

    } else {

        // create a link to that page
        $links .= "<a href=\"page_{$i}.php\">$i </a>";
    }
}

//     // three dots
$links .= ' ... ';

// links to the next page and the last page
// ...
        $display_current = 10;
        $display_next = 10;

        echo $pagination['Links']['First'];
        echo '&nbsp;';
        echo $pagination['Links']['<'];
        echo '&nbsp;';

        for ($i = 1; $i <= $display_current; $i++)
        {
            if ($display_current >= $_GET['current_page'])
            {
                if (isset($pagination['Links'][$i]))
                {
                    echo $pagination['Links'][$i];
                    echo '&nbsp;';
                }
            }
            else
            {
                $i = $display_current;
                $display_current = $i + $display_next;
            }
        }

        echo $pagination['Links']['>'];
        echo '&nbsp;';
        echo $pagination['Links']['Last'];

This code works fine but without dots as I defined above. Would you please help he to add dots the way I described above?

Thanks

OK, I get it. The dots are there only when there are more sets of pages. And if you click on them they get you to the next / previous set of pages. Is that correct?

And also what do $display_current and $display_next represent? Do you have the total number of pages, too?

OK, I get it. The dots are there only when there are more sets of pages. And if you click on them they get you to the next / previous set of pages. Is that correct?

YES CORRECT

And also what do $display_current and $display_next represent? Do you have the total number of pages, too?

Since $pagination['Links'] has hundreds of records $display_current and $display_next represent allow me to display 10 records per page. I would love to optimise and reduce the lines but my brain stopped!

It is hard to say without seeing the complete code. The trouble is I am leaving now and wont be back before Sunday night. If you do not solve it by then I'll be happy to help.

One more question: do you read your recors from the database? If yes then you do not need to keep hundreds of links in an array, only 10 is enough sicnce you read only the number of record you wish to display at once using LIMIT SQL clause. See Pear Pager and Pager_Wrapper code it might help you: http://www.alberton.info/pear_pager_tutorials.html.

I'm using Codeigniter. I have a few libraries, models, views and controllers so the code has been seperated into different files.

Yes I'm using database. What I'm doing is that I get all the data from database in one ago and store it in cached array (for 5 minutes) to stop sending queries to database again based on selected page (limit, offset). I'm then reading data from cached array with (array_slice). All these are for caching and speeding up the whole pagination process.

I don't mind waiting so I tide it up to make it easier for you.

1)
This is the content of $pagination['Links'] array:

Array
(
    [First] => First
    [<] => <
    [1] => 1
    [2] => 2
    [3] => 3
    [4] => 4
    [5] => 5
    [6] => 6
    [7] => 7
    [8] => 8
    [9] => 9
    [10] => 10
    [11] => 11
    [12] => 12
    [13] => 13
    [14] => 14
    [15] => 15
    [16] => 16
    [17] => 17
    [18] => 18
    [19] => 19
    [20] => 20
    [21] => 21
    [22] => 22
    [>] => >
    [Last] => Last
)

2)
I want navigation part to be like this:

First < 1 2 3 4 5 6 7 8 9 10 ... > Last
First < ... 11 12 13 14 15 16 17 18 19 20 ... > Last
First < ... 21 22 > Last

3)
This is my code which has only dots part missing, everything else is fine:

        $display_current = 10;
        $display_next = 10;
        echo $pagination['Links']['First'];
        echo '&nbsp;';
        echo $pagination['Links']['<'];
        echo '&nbsp;';
        for ($i = 1; $i <= $display_current; $i++)
        {
            if ($display_current >= $_GET['current_page'])
            {
                if (isset($pagination['Links'][$i]))
                {
                    echo $pagination['Links'][$i];
                    echo '&nbsp;';
                }
            }
            else
            {
                $i = $display_current;
                $display_current = $i + $display_next;
            }
        }
        echo $pagination['Links']['>'];
        echo '&nbsp;';
        echo $pagination['Links']['Last'];

Note:
$display_current and $display_next allow me to display 10 records per page so I get exact output as I listed above, obvioulsy dots missing! If you think section 3 above is stupid then feel free to modify it. I sometimes write unnecessary lines.

Thanks again

Sorry but still do not understand few things:

  • where does each link point to? It should be echoed as a link (<a href="somepage">1</a>), but that is not the case in your code. Is it the same page and the value of the Links array is just a key of the big result array?
  • why do you not want to read only the number of records to be displayed on one page? What happens if you have 10000 records? Do you keep such big array in the memory? Where do you store the result (cached array) when user clicks on one of the libks and a new page with results is displayed?

The following is just a blind attempt since I have no information about what some variables keep (see comments in the code):

    $display_current = 10;
    $display_next = 10;
    echo $pagination['Links']['First'];
    echo ' ';
    echo $pagination['Links']['<'];
    echo ' ';

    // I am assuming that $display_current holds the first link in the 
    // currently displayed set of links and $display_next holds the
    // number of currently displayed links; 
    // if I am wrong tell me what values these variables contain

    // first three dots are displayed only when the current page is greater
    // than 10
    if($display_current > 10) {

        // display the three dots; but I have no clue where the link
        // should point (see questions in my previous post)
        echo ' ... ';
    }

    for ($i = 1; $i <= $display_current; $i++)
    {
        if ($display_current >= $_GET['current_page'])
        {
            if (isset($pagination['Links'][$i]))
            {
                echo $pagination['Links'][$i];
                echo ' ';
            }
        }
        else
        {
            $i = $display_current;
            $display_current = $i + $display_next;
        }
    }

    // calculate the number of the first link in the next set of pages
    $next_link = $display_current + $display_next + 1;

    // last three dots are displayed only when there are still any pages left
    // (the element for the $next_link exists)
    if(isset($pagination['Links'][$next_link])) {

        // display the three dots; but I have no clue where the link
        // should point (see questions in my previous post)
        echo ' ... ';
    }

    echo $pagination['Links']['>'];
    echo ' ';
    echo $pagination['Links']['Last'];

I also do not understand the logic of the for loop. Why do you change the counter $i? It messes up the logic of the for loop.

I'll get back to you when I'm back. Little busy...

OK, no problem. Meanwhile I was a bit curious how this could be done and came up with the code below. It uses test data in an array (which I assume you cache in a file or in include script). There is a show_links() function in the code that might interest you to see how I implemented it. The code is commented so have a look and see if it helps you. Mind you, I tested the code but I can not promise it is bugs free.

// *** Test data ***

// test array containing the results
$test_results = array();

// generate some test data
for($test = 1; $test <= 4348; $test++) {

    $test_results[$test] = "This is test result No. $test";
}

// *** End of test data ***

// check if current page is in $_GET array; if not, set it to the first page
if(isset($_GET['current_page'])) {

    $current_page = (int) $_GET['current_page'];

} else {

    $current_page = 1;
}

// how many results to display in one page
$results_per_page = 10;

// how many links to display in one page
$links_per_page = 10;

// how many items in the result
$total_results = count($test_results);

// how many total pages needed to display all the results
$total_pages = floor($total_results / $results_per_page) + 1;

/**
 * Show the links based on the current page and other parameters
 *
 * @param   int current page No.
 * @param   int number of result displayed on one page
 * @param   int number of links displayed on one page
 * @param   int number of all pages
 */
function show_links($current_page, $results_per_page, $links_per_page, $total_pages) {

    // name of this script for constructing links
    $scriptname = $_SERVER['PHP_SELF'];

    // calculate first page in the page set
    // NOTE: you can maybe find a better algoritm for this,  nevertheless
    // this one seems to work OK
    if($current_page % $links_per_page == 0 and $current_page > 9) {

        // if current page is 10, 20, 30 etc
        $first_page = $current_page - $links_per_page + 1;

    } else {

        $first_page = floor($current_page / $links_per_page) * $links_per_page + 1;
    }

    // calculate last page in the page set
    $last_page = $first_page + $links_per_page - 1;

    if($last_page > $total_pages) {

        $last_page = $total_pages;
    }

    // I wrapped links in paragraph tags, you can also use div instead
    echo '<p>';

    // 'First' is displayed as a link only if current page is not already 1
    // you can also choose not to display it at all
    if($current_page > 1) {

        echo "<a href=\"$scriptname?current_page=1\">First</a> ";

    } else {

        echo "First ";
    }

    // '<' is displayed as a link only if current page is not already 1
    // you can also choose not to display it at all
    if($current_page > 1) {

        $prev_page = $current_page - 1;

        echo "<a href=\"$scriptname?current_page=$prev_page\">&lt;</a> ";

    } else {

        echo "&lt; ";
    }

    // '...' is displayed as link only if there is another set of links before
    if($current_page > $links_per_page) {

        $prev_first_page = $first_page - $links_per_page;

        echo "<a href=\"$scriptname?current_page=$prev_first_page\">...</a> ";

    } else {

        echo "... ";
    }

    // display links
    for($page = $first_page; $page <= $last_page; $page++) {

        // if you reach the last page exit the loop
        if($page > $total_pages) {

            break;
        }

        if($page == $current_page) {

            // current page is not a link and is surrounded with square
            // brackets (just my idea :-)
            echo "<strong>[$page]</strong> ";

        } else {

            // other pages are links to the same page
            echo "<a href=\"$scriptname?current_page=$page\">$page</a> ";
        }
    }

    // '...' is displayed as link only if there is another set of links after
    if($first_page < $total_pages - $links_per_page) {

        $next_first_page = $first_page + $links_per_page;

        echo "<a href=\"$scriptname?current_page=$next_first_page\">...</a> ";

    } else {

        echo "... ";
    }

    // 'Last' is displayed as a link only if current page less than total pages
    // you can also choose not to display it at all
    if($current_page < $total_pages) {

        $next_page = $current_page + 1;

        echo "<a href=\"$scriptname?current_page=$next_page\">&gt;</a> ";

        echo "<a href=\"$scriptname?current_page=$total_pages\">Last</a> ";

    } else {

        echo "&gt; ";

        echo "Last";
    }

    echo '</p>';
} // end of show_links() function

// *** display test data and pagination links

// compute first and last key for table
$first_key = ($current_page - 1) * $results_per_page + 1;
$last_key = $first_key + $results_per_page - 1;
if($last_key > $total_results) {

    $last_key = $total_results;
}

// show results table
echo "<p>Showing page $current_page (results $first_key to $last_key)</p>";

echo '<table>';

for($key = $first_key; $key <= $last_key; $key++) {

    echo "<tr><td>$key</td><td>{$test_results[$key]}</td></tr>";
}

echo '</table>';

// this is how you use the function to display links
show_links($current_page, $results_per_page, $links_per_page, $total_pages);

Since my boss has given me an urgent to be finished before everything else, I'll have to hold on to this 2 or 3 days. Meanwhile, let me explain how and why I store data.

I have a table with 2.000.000+/- records in it. My query returnes average 20.000 records. I store it in cache (Click Here) for 5 minutes so every page request done in 5 minutes reads records from cache, no query sent to database.

I know that we normally send queries to database with LIMIT and OFFSET parts (takes about 2 minutes) but in this case same logis is applied against cache with array_slice(array, OFFSET, LENGTH) function (takes less than half a second).

I'll let you know about the outcome of your code. Just give me a little time please.

Thanks

OK, no worries, just finish your work first and get back once you have time. I am pretty busy at the moment, too.

Broj1 thanks for the controbutions. Helped me to modify my code.

SOLVED.

PAGINATION CODE:

        $navigation[] = $links['First'];    //Get first link
        $navigation[] = $links['<'];     //Get previous link

        $segment = $links_per_page;         //Initiate variable
        $counter = 1;                       //Initiate variable

        for ($i = 1; $i <= $segment; $i++)               //Iterate throough links by segment
        {
            if ($segment >= $current_page)              //If current page is still in segment's range
            {
                if (isset($links[$i]))                  //If the link exist
                {
                    $navigation[] = $links[$i];         //Show the link
                }

                if ($counter <= ($total_segments-1) && $i == $segment)       //If there more navigation segments
                {
                    $navigation[] = anchor(site_url($base_url . '/' . ($i+1)), '...', array('title' => 'Next segment'));
                }
            }
            else                                        //If current page isn't in segment's range
            {
                $counter++;

                if ($counter > 1 && $counter < $total_segments)              //If there is previous navigation segment
                {
                    $navigation[] = anchor(site_url($base_url . '/' . ($segment)), '...', array('title' => 'Previous segment'));
                }

                $i = $segment;                          //Cursor focuses on next segment's first index
                $segment = $i + $links_per_page;        //Jump to next segment
            }
        }

        $navigation[] = $links['>'];                    //Get next link
        $navigation[] = $links['Last'];                 //Get last link

PAGINATION OUTPUT:

First < 1 2 3 4 5 6 7 8 9 10 ... > Last
First < ... 11 12 13 14 15 16 17 18 19 20 ... > Last
First < ... 21 22 > Last

Update to last part:

            else
            {
                $i = $segment;
                $segment = $i + $links_per_page;

                if ($counter < $total_segments)
                {
                    $navigation['...'] = anchor(site_url($base_url . '/' . ($counter * $links_per_page)), '...', array('title' => 'Previous segment'));
                }

                $counter++;
            }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.