Last active
February 2, 2023 16:01
-
-
Save bramus/5d8f2e0269e57dff5136 to your computer and use it in GitHub Desktop.
Pagination Sequence Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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