<?php /** * Generate a sequence of numbers for use in a pagination system, the clever way. * @author Bramus Van Damme <bramus@bram.us> * * 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