There's an array of pages,
$pages = array(
1,
2,
3,
...
100,
101
);
And there's a variable $current_page
. All I'm trying to do is pagination in digg-like style, so that it would look like this,
< 4 5 6 7 .... 15 16 17 18 >
The first thing that comes to mind is to get last and previous array values from specific position that equals to $current_page
.
So I started with a basic for
loop, but the problem is that amount of pages could be very large, so I don't think that's an efficient thing to do. Is there any another proper way of doing this? (maybe via native array_*
functions)?
The following function builds StackOverflow like pagination. The objectives are:
While the following function displays the complete pager, we are primarily interested in how to calculate the surrounding pages a and b as a function of current page, pager size and page count.
function so_like_pager($current_page, $page_count, $pager_size = 4) {
if ($current_page <= $pager_size) {
// the pager for first 4 pages starts from 1
$a = 1;
$b = min(1 + $pager_size, $page_count);
} else {
// the pager for remaining pages ends at current page + 2
// and starts so that 4 links are shown
$b = min($current_page + ($pager_size >> 1), $page_count);
$a = $b - $pager_size;
}
// return array("show_from" => $a, "show_upto" => $b);
echo '<p>';
if ($current_page !== 1) {
echo '<a href="' . so_like_pager_page(1) . '">' . 1 . '</a> ';
} else {
echo '<b>' . 1 . '</b> ';
}
if ($a > 1 + 1) {
echo '<span>...</span> ';
}
for ($i = $a; $i <= $b; $i++) {
if ($i !== 1 && $i !== $page_count) {
if ($current_page !== $i) {
echo '<a href="' . so_like_pager_page($i) . '">' . $i . '</a> ';
} else {
echo '<b>' . $i . '</b> ';
}
}
}
if ($b < $page_count - 1) {
echo '<span>...</span> ';
}
if ($current_page !== $page_count) {
echo '<a href="' . so_like_pager_page($page_count) . '">' . $page_count . '</a> ';
} else {
echo '<b>' . $page_count . '</b> ';
}
echo '</p>';
}
function so_like_pager_page($page) {
return 'page-' . $page . '/';
}
Tests:
so_like_pager(1, 100);
so_like_pager(2, 100);
so_like_pager(3, 100);
so_like_pager(4, 100);
so_like_pager(5, 100);
so_like_pager(6, 100);
so_like_pager(50, 100);
so_like_pager(99, 100);
so_like_pager(100, 100);
Output:
PS: Note: I ported this function from ASP classic to PHP in a hurry and did not test against edge cases.
You can use PHP's end
function to get the last entry of an array.
<?php
$a = array( 1, 2, 3, 4, 5, 10 );
echo end($a);
You can also use array_slice
, or array_splice
to cut an array, or array_pop
, which removes the last element and returns what was removed.
Maybe you can try end. Should be more efficient than looping.
function get_surrounding_pages(array $pages, $current, $amount = 2) {
$pages_idx = array_flip($pages);
if (!isset($pages_idx[$current])) {
return false;
}
$offset = max(0, $pages_idx[$current] - $amount);
$limit = $amount + 1 + ($pages_idx[$current] - $offset);
return array_slice($pages, $offset, $limit);
}
$pages = range(1, 1000);
$current = 42;
get_surrounding_pages($pages, $current, 4);
// array(38, 39, 40, 41, 42, 43, 44, 45, 46)
// this will work even if your number of pages is not continuous (eg: 1, 2, 6).
$pages = array(1, 2, 5, 6, 42, 234, 1048);
$current = 6;
get_surrounding_pages($pages, $current, 2);
// array(2, 5, 6, 42, 234)
// also works if you reach the boundaries
$pages = range(1, 10);
$current = 2;
get_surrounding_pages($pages, $current, 2);
// array(1, 2, 3, 4)
$current = 9;
get_surrounding_pages($pages, $current, 2);
// array(7, 8, 9, 10)
// returns false if you ask a page that doesn't exists
$pages = range(1, 10);
$current = 42;
get_surrounding_pages($pages, $current, 2);
// false