Skip to content

Instantly share code, notes, and snippets.

@bramus
Last active February 2, 2023 16:01
Show Gist options
  • Save bramus/5d8f2e0269e57dff5136 to your computer and use it in GitHub Desktop.
Save bramus/5d8f2e0269e57dff5136 to your computer and use it in GitHub Desktop.
Pagination Sequence Generator
<?php
/**
* Generate a sequence of numbers for use in a pagination system, the clever way.
* @author Bramus Van Damme <[email protected]>
*
* The algorithm always returns the same amount of items in the sequence,
* indepdendent of the position of the current page.
*
* Example rows generated:
* (adjusted to indicate the current page between [] + leading 0s added)
*
* [01]-02-03-04-05-06-07-08-..-73-74
* 01-[02]-03-04-05-06-07-08-..-73-74
* 01-02-[03]-04-05-06-07-08-..-73-74
* 01-02-03-[04]-05-06-07-08-..-73-74
* 01-02-03-04-[05]-06-07-08-..-73-74
* 01-02-03-04-05-[06]-07-08-..-73-74
* 01-02-..-05-06-[07]-08-09-..-73-74
* 01-02-..-06-07-[08]-09-10-..-73-74
* 01-02-..-07-08-[09]-10-11-..-73-74
* ...
* 01-02-..-65-66-[67]-68-69-..-73-74
* 01-02-..-66-67-[68]-69-70-..-73-74
* 01-02-..-67-68-[69]-70-71-72-73-74
* 01-02-..-67-68-69-[70]-71-72-73-74
* 01-02-..-67-68-69-70-[71]-72-73-74
* 01-02-..-67-68-69-70-71-[72]-73-74
* 01-02-..-67-68-69-70-71-72-[73]-74
* 01-02-..-67-68-69-70-71-72-73-[74]
*
*/
function generatePaginationSequence($curPage, $numPages, $numberOfPagesAtEdges = 2, $numberOfPagesAroundCurrent = 2, $glue = '..', $indicateActive = false) {
// Define the number of items we would generate in a normal scenario
// (viz. lots of pages, current page in the middle):
//
// numItemsInSequence = the current page + the number of items surrounding
// the current page (left and right) + the number of items at the edges
// of the generated sequence (left and right) + the glue in between the
// different parts generated
//
// The goal is to enforce all sequences generated to have this amount
// of items. By default this magic number would be 11, as seen/counted
// in this sequence: 1-02-..-11-12-[13]-14-15-..-88-74
$numItemsInSequence = 1 + ($numberOfPagesAroundCurrent * 2) + ($numberOfPagesAtEdges * 2) + 2;
// Fix: curPage cannot be greater than numPages.
$curPage = min($curPage, $numPages);
// If we have less than $numItemsInSequence pages in total, there is no need to
// start calculating but just return the full sequence, starting at 1
if ($numPages <= $numItemsInSequence) {
$finalSequence = range(1, $numPages);
}
// We have more pages than $numItemsInSequence, start calculating
else {
// If we have no forced amount of items on the edges, then the
// sequence must start from the current page number instead of 1
$start = ($numberOfPagesAtEdges > 0) ? 1 : $curPage;
// Parts of the sequence we'll be generating
$sequence = array(
'leftEdge' => null,
'glueLeftCenter' => null,
'centerPiece' => null,
'glueCenterRight' => null,
'rightEdge' => null
);
// If the current page is nearby the left edge (viz. curPage is
// less than half of $numItemsInSequence away from left edge):
// Don't generate a Center Piece, but extend the left part as
// the left part would otherwise overlap the center piece.
if ($curPage < ($numItemsInSequence/2)) {
$sequence['leftEdge'] = range(1, ceil($numItemsInSequence/2) + $numberOfPagesAroundCurrent);
$sequence['centerPiece'] = array($glue);
if ($numberOfPagesAtEdges > 0) $sequence['rightEdge'] = range($numPages-($numberOfPagesAtEdges-1), $numPages);
}
// If the current page is nearby the right edge (viz. curPage is
// less than half of $numItemsInSequence away from right edge):
// Don't generate a center piece but extend the right part as
// the right part would otherwise overlap the center piece.
else if ($curPage > $numPages - ($numItemsInSequence/2)) {
if ($numberOfPagesAtEdges > 0) $sequence['leftEdge'] = range($start, $numberOfPagesAtEdges);
$sequence['centerPiece'] = array($glue);
$sequence['rightEdge'] = range(min($numPages - floor($numItemsInSequence/2) - $numberOfPagesAroundCurrent, $curPage - $numberOfPagesAroundCurrent), $numPages);
}
// The current page falls somewhere in the middle:
// Generate ranges normally
else {
// Center Piece
$sequence['centerPiece'] = range($curPage - $numberOfPagesAroundCurrent, $curPage + $numberOfPagesAroundCurrent);
// Left/Right Edges (only if we requested)
if ($numberOfPagesAtEdges > 0) $sequence['leftEdge'] = range($start,$numberOfPagesAtEdges);
if ($numberOfPagesAtEdges > 0) $sequence['rightEdge'] = range($numPages-($numberOfPagesAtEdges-1), $numPages);
// The glue we'll use to stick left, center, and right together
// Special case: If the gap between left and center is only one
// unit, don't add '...' but add that number instead
$sequence['glueLeftCenter'] = ($sequence['centerPiece'][0] == ($numberOfPagesAtEdges+2)) ? array($numberOfPagesAtEdges+1) : array($glue);
$sequence['glueCenterRight'] = array($glue);
}
// Join all (non-empty) parts of sequence into the final sequence
$finalSequence = array();
foreach($sequence as $k => $v) {
if ($v !== null) {
$finalSequence = array_merge($finalSequence, $v);
}
}
}
// Return the final sequence
if ($indicateActive) {
return array_replace($finalSequence, array(array_search($curPage, $finalSequence) => '[' . $curPage. ']'));
} else {
return $finalSequence;
}
}
// EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment