For a recent project I’ve been working I needed an easy-to-use Pagination class but after a scour around I couldn’t find anything that would do the job in the way I wanted to (Zend’s came close, as I’ve used it before, but it’s not lightweight enough for this project). I decided to write my own one instead.
The constructor takes a minimum of two arguments – an array of the whole set of data to be paginated, and the page of results to display. Optional arguments that can also be passed include an array of data to be included in the query string for each navigation link (most likely the $_GET predefined variable), the number of results to display per-page and how many links to include in the navigation (this value doesn’t affect the First/Last, Previous/Next navigation links):
This class will most probably not be of use if you are trying to paginate more that 1000 or so rows of data to paginate as doing it this way is bad practice (if pulling the data from a database you should be selecting your subset there, much more efficient).
As ever, let me know your thoughts!
<?php /** * Pagination Class * * Class that will take an array of data and split it into the subsection to be returned, based on the values passed */ class Pagination { public $data; // Original Data public $query_data; // Data on current query string public $page; // Current page of results to display public $pages; // Pages to include, dependant upon $page_range value public $page_count; // Total Number of Pages public $row_count; // Number of rows passed to class in Constructor public $first_page; // Show first page link public $last_page; // Show last page link public $previous_page; // Show previous page link public $next_page; // Show next page link public $range_start; // The page number to start the range link at public $page_range; // Show number of page links to show public $query_string; // Query string to use for the links public $subsection_of_data; /** * Contructor * @param array An array of data to be paginated * @param int Page of data to return as subsection * @param array An array of key/value-paired data for the query string for the Pagination navigation * @param int The number of results to show on one page * @param int Number of pages to display in the Pagination Navigation (Excluding First/Last, Previous/Next links) * @return boolean */ public function __construct($data, $page, $query_data = array(), $per_page = 25, $page_range = 5) { $this->data = $data; $this->query_data = $query_data; $this->subsection_of_data = array(); $this->pages = array(); $this->page = $page; $this->per_page = $per_page; $this->page_range = $page_range; $this->process_query_string(); $this->process_number_of_rows(); $this->process_page_count(); $this->process_first_page(); $this->process_last_page(); $this->process_previous_page(); $this->process_next_page(); $this->process_page_range(); $this->process_subsection_of_data(); } /** * Count total number of items * @return void */ public function process_number_of_rows() { $this->row_count = count($this->data); } /** * Count total number of pages on data based on $per_page variable * @return void */ public function process_page_count() { $this->page_count = floor($this->row_count / $this->per_page) + ($this->row_count % $this->per_page > 0 ? 1 : 0); // Number of Pages in Total } /** * Determining whether to include "First Page" link in navigation * @return void */ public function process_first_page() { $this->first_page = false; if ($this->page > 1) : $this->first_page = 1; endif; } /** * Determining whether to include "Last Page" link in navigation * @return void */ public function process_last_page() { $this->last_page = false; if ($this->page < $this->page_count) : $this->last_page = $this->page_count; endif; } /** * Determining whether to include "Previous Page" link in navigation * @return void */ public function process_previous_page() { $this->previous_page = false; if ($this->page > 1) : $this->previous_page = $this->page - 1; endif; } /** * Determining whether to include "Next Page" link in navigation * @return void */ public function process_next_page() { $this->next_page = false; if ($this->page < $this->page_count) : $this->next_page = $this->page + 1; endif; } /** * Determining what page links to include in "Page Range" navigation * @return void */ public function process_page_range() { $this->range_split = floor(($this->page_range - 1) / 2); $this->range_start = $this->page - $this->range_split; if ($this->range_start < 1) : $this->range_start = 1; endif; $i = $this->range_start; while ($i < ($this->range_start + $this->page_range)) : if ($i > 0 && $i <= $this->page_count) : $this->pages[] = $i; endif; $i++; endwhile; } /** * Process query string to use on navigation links (removing the currently selected page, if set) * @return void */ public function process_query_string() { $query_data = $this->query_data; if (isset($query_data['page'])) { unset($query_data['page']); } $this->query_string = http_build_query($query_data); } /** * Return set of data to display, based on Page Number and Per Page variable * @return void */ public function process_subsection_of_data() { $this->subsection_of_data = $this->data; $offset = $this->per_page * ($this->page - 1); $limit = $this->per_page; $this->subsection_of_data = array_slice($this->data, $offset, $limit); } /** * Render standard navigation (echoes immediately) * @return void */ public function render() { if ($this->page_count > 0): ?> <div class="pagination"> <?php if ($this->page_count > 1): ?> <div class="navigation"> <?php if ($this->first_page) : ?> <span class="item"><a href="?<?php echo $this->query_string; ?>&page=<?php echo $this->first_page; ?>">First</a></span> <?php endif; if ($this->previous_page) : ?> <span class="item"><a href="?<?php echo $this->query_string; ?>&page=<?php echo $this->previous_page; ?>">Previous</a></span> <?php endif; foreach ($this->pages as $page_number) : if ($page_number == $this->page) : ?> <span class="item range current"><?php echo $page_number; ?></span> <?php else : ?> <span class="item range"><a href="?<?php echo $this->query_string; ?>&page=<?php echo $page_number; ?>"><?php echo $page_number; ?></a></span> <?php endif; endforeach; if ($this->next_page) : ?> <span class="item"><a href="?<?php echo $this->query_string; ?>&page=<?php echo $this->next_page; ?>">Next</a></span> <?php endif; if ($this->last_page) : ?> <span class="item"><a href="?<?php echo $this->query_string; ?>&page=<?php echo $this->last_page; ?>">Last</a></span> <?php endif; ?> </div> <?php endif; ?> <span class="summary">Page <?php echo $this->page; ?> of <?php echo $this->page_count; ?></span> <div class="clear"></div> </div> <?php endif; } /** * Render naviation based on the specified template * @return void */ public function render_by_template($path) { if (file_exists($path)) { include($path); } else { echo 'Error: Pagination template cannot be found'; } } }
Example of use:
<?php $data = array('Apple', 'Banana', 'Blackberry', 'Blackcurrant', 'Cherry', 'Clementine', 'Elderberry', 'Fig', 'Grape', 'Gooseberry', 'Juniper', 'Kiwi'); $get_data = $_GET; $page = (int) $get_data['page']; $pagination = new Pagination($data, $page, $get_data, 5, 5); $pagination->render(); ?> <table><?php foreach ($pagination->subsection_of_data as $row) { ?> <tr> <td><?php echo $row; ?></td> </tr> } ?> </table><?php $pagination->render(); ?>