Pagination is a very common task for a PHP developer. With the power of OOP coding style, it is nature to have a reusable pagination class, which we can use it for various projects. Because for an advanced developer, we should never repeat the same coding process.(Don't Repeat Yourself). In this tutorial, I will go through the process of writing your very own PHP paginator class.
During a normal PHP coding task, pagination is always associated with a database (MySql in most cases). However in this tutorial, we are going to separate pagination from data source in order to achieve the goal of a reusable pagination class. So you do not have to worry about the data source (database) part. All of our concerns will be the pagination numbers as well as navigation.
Firstly, let me show you the completed class, and then I will explain it in details:
class Paginator {
public $itemsPerPage;
public $range;
public $currentPage;
public $total;
public $textNav;
public $itemSelect;
private $_navigation;
private $_link;
private $_pageNumHtml;
private $_itemHtml;
/**
* Constructor
*/
public function __construct()
{
//set default values
$this->itemsPerPage = 5;
$this->range = 5;
$this->currentPage = 1;
$this->total = 0;
$this->textNav = false;
$this->itemSelect = array(5,25,50,100,'All');
//private values
$this->_navigation = array(
'next'=>'Next',
'pre' =>'Pre',
'ipp' =>'Item per page'
);
$this->_link = filter_var($_SERVER['PHP_SELF'], FILTER_SANITIZE_STRING);
$this->_pageNumHtml = '';
$this->_itemHtml = '';
}
/**
* paginate main function
*
* @author The-Di-Lab <thedilab@gmail.com>
* @access public
* @return type
*/
public function paginate()
{
//get current page
if(isset($_GET['current'])){
$this->currentPage = $_GET['current'];
}
//get item per page
if(isset($_GET['item'])){
$this->itemsPerPage = $_GET['item'];
}
//get page numbers
$this->_pageNumHtml = $this->_getPageNumbers();
//get item per page select box
$this->_itemHtml = $this->_getItemSelect();
}
/**
* return pagination numbers in a format of UL list
*
* @author The-Di-Lab <thedilab@gmail.com>
* @access public
* @param type $parameter
* @return string
*/
public function pageNumbers()
{
if(empty($this->_pageNumHtml)){
exit('Please call function paginate() first.');
}
return $this->_pageNumHtml;
}
/**
* return jump menu in a format of select box
*
* @author The-Di-Lab <thedilab@gmail.com>
* @access public
* @return string
*/
public function itemsPerPage()
{
if(empty($this->_itemHtml)){
exit('Please call function paginate() first.');
}
return $this->_itemHtml;
}
/**
* return page numbers html formats
*
* @author The-Di-Lab <thedilab@gmail.com>
* @access public
* @return string
*/
private function _getPageNumbers()
{
$html = '<ul>';
//previous link button
if($this->textNav&&($this->currentPage>1)){
echo '<li><a href="'.$this->_link .'?current='.($this->currentPage-1).'"';
echo '>'.$this->_navigation['pre'].'</a></li>';
}
//do ranged pagination only when total pages is greater than the range
if($this->total > $this->range){
$start = ($this->currentPage <= $this->range)?1:($this->currentPage - $this->range);
$end = ($this->total - $this->currentPage >= $this->range)?($this->currentPage+$this->range): $this->total;
}else{
$start = 1;
$end = $this->total;
}
//loop through page numbers
for($i = $start; $i <= $end; $i++){
echo '<li><a href="'.$this->_link .'?current='.$i.'"';
if($i==$this->currentPage) echo "class='current'";
echo '>'.$i.'</a></li>';
}
//next link button
if($this->textNav&&($this->currentPage<$this->total)){
echo '<li><a href="'.$this->_link .'?current='.($this->currentPage+1).'"';
echo '>'.$this->_navigation['next'].'</a></li>';
}
$html .= '</ul>';
return $html;
}
/**
* return item select box
*
* @author The-Di-Lab <thedilab@gmail.com>
* @access public
* @return string
*/
private function _getItemSelect()
{
$items = '';
$ippArray = $this->itemSelect;
foreach($ippArray as $ippOpt){
$items .= ($ippOpt == $this->itemsPerPage) ? "<option selected value=\"$ippOpt\">$ippOpt</option>\n":"<option value=\"$ippOpt\">$ippOpt</option>\n";
}
return "<span class=\"paginate\">".$this->_navigation['ipp']."</span>
<select class=\"paginate\" onchange=\"window.location='$this->_link?current=1&item='+this[this.selectedIndex].value;return false\">$items</select>\n";
}
}
The class name is "Paginator". Firstly let us take a look at its member variables:
public $itemsPerPage;
public $range;
public $currentPage;
public $total;
public $textNav;
private $_navigation;
private $_link;
private $_pageNumHtml;
private $_itemHtml;
All the variables are initialized in the class constructor. Take a look at it to have an idea of their default values:
public function __construct()
{
//set default values
$this->itemsPerPage = 5;
$this->range = 5;
$this->currentPage = 1;
$this->total = 0;
$this->textNav = false;
$this->itemSelect = array(5,25,50,100,'All');
//private values
$this->_navigation = array(
'next'=>'Next',
'pre' =>'Pre',
'ipp' =>'Item per page'
);
$this->_link = filter_var($_SERVER['PHP_SELF'], FILTER_SANITIZE_STRING);
$this->_pageNumHtml = '';
$this->_itemHtml = '';
}
First public function is paginate(), this function is the main function used to process the pagination:
public function paginate()
{
//get current page
if(isset($_GET['current'])){ //1
$this->currentPage = $_GET['current'];
}
//get item per page
if(isset($_GET['item'])){ //2
$this->itemsPerPage = $_GET['item'];
}
//get page numbers
$this->_pageNumHtml = $this->_getPageNumbers(); //3
//get item per page select box
$this->_itemHtml = $this->_getItemSelect(); //4
}
We use $_GET['current'] to get the current page number from URL and set it to $currentPage if it is set.
We use $_GET['item'] to get number of items per page from URL and set it to $itemsPerPage if it is set.
We call a private function $_getPageNumbers() to process the pagination numbers and store it to variable $_pageNumHtml.
We call a private function $_getItemSelect() to process the items per page select box and store it to variable $_itemHtml.
As we have seen from last function, two private functions ($_getPageNumbers() and $_getItemSelect()) are actually doing the job of generating the pagination html content. So let us take a look at these two functions:
private function _getPageNumbers()
{
$html = '<ul>';
//previous link button
if($this->textNav&&($this->currentPage>1)){ //*********1
echo '<li><a href="'.$this->_link .'?current='.($this->currentPage-1).'"';
echo '>'.$this->_navigation['pre'].'</a></li>';
}
//do ranged pagination only when total pages is greater than the range
if($this->total > $this->range){ //*********2
$start = ($this->currentPage <= $this->range)?1:($this->currentPage - $this->range);
$end = ($this->total - $this->currentPage >= $this->range)?($this->currentPage+$this->range): $this->total;
}else{
$start = 1;
$end = $this->total;
}
//loop through page numbers
for($i = $start; $i <= $end; $i++){ //*********3
echo '<li><a href="'.$this->_link .'?current='.$i.'"';
if($i==$this->currentPage) echo "class='current'";
echo '>'.$i.'</a></li>';
}
//next link button
if($this->textNav&&($this->currentPage<$this->total)){ //*********4
echo '<li><a href="'.$this->_link .'?current='.($this->currentPage+1).'"';
echo '>'.$this->_navigation['next'].'</a></li>';
}
$html .= '</ul>';
return $html;
}
IF (total page > range) {
start page = (current page <= range) ? 1 : current page - range;
end page = (total page - current page >= range) ? current page + range: total;
}ELSE{
start page = 1;
end page = total page;
}
private function _getItemSelect()
{
$items = '';
$ippArray = $this->itemSelect;
foreach($ippArray as $ippOpt){
$items .= ($ippOpt == $this->itemsPerPage) ? "<option selected value=\"$ippOpt\">$ippOpt</option>\n":"<option value=\"$ippOpt\">$ippOpt</option>\n";
}
return "<span class=\"paginate\">".$this->_navigation['ipp']."</span>
<select class=\"paginate\" onchange=\"window.location='$this->_link?current=1&item='+this[this.selectedIndex].value;return false\">$items</select>\n";
}
This function is very straightforward. It simply uses a foreach loop to form a select box.
Lastly, let us take a look at two public functions, which will be actually called by developers to print out the pagination.
public function pageNumbers()
{
if(empty($this->_pageNumHtml)){
exit('Please call function paginate() first.');
}
return $this->_pageNumHtml;
}
As you can see, besides from returning the pagination html, this function always provides a debug message, reminding people to call paginate() function first, This will be discussed on How To Use section. The reason, we have a separate function to return the html content is that it allows developers to print out the pagination multiple times without reprocessing.
public function itemsPerPage() is almost identical to pageNumbers().
To use this class, there are something you will need to do with your data source (MySql possibly, but can be anything). Firstly you will need to tell Paginator total number of records by setting variable $total. Secondly you will need to set your data record using combination of $currentPage and $itemsPerPage from Paginator class. For example, I am using MySql to store my data. What I need to do is firstly find total number of records (SELECT COUNT) using MySql and set it to $total:
//using mysql to find out total records
$totalRecords = using_mysql_find_out ("Select count(*) from table");
include 'paginator.php';
$paginator = new Paginator();
$paginator->total = $totalRecords;
$paginator->paginate();
After that, you will typically use "LIMIT" query to get data from database:
//using mysql to find out total records
$totalRecords = using_mysql_find_out ("Select count(*) from table");
include 'paginator.php';
$paginator = new Paginator();
$paginator->total = $totalRecords;
$paginator->paginate();
//get record from database and show
$records = using_mysql_find_out "Select (*) from table LIMIT ($paginator->currentPage-1)*$paginator->itemsPerPage, $paginator->itemsPerPage" ;
Finally, you can call pageNumbers() function to print the pagination, and itemsPerPage() to print the items per page select box. Even more, with the way this class is built. You can print both of them multiple times, and it will not cause any performance issue:
//using mysql to find out total records
$totalRecords = using_mysql_find_out ("Select count(*) from table");
include 'paginator.php';
$paginator = new Paginator();
$paginator->total = $totalRecords;
$paginator->paginate();
//get record from database and show
$records = using_mysql_find_out "Select (*) from table LIMIT ($paginator->currentPage-1)*$paginator->itemsPerPage, $paginator->itemsPerPage" ;
//print
echo $paginator->pageNumbers();
echo $paginator->itemsPerPage();
Since this class does not come with any style sheet, you should provide some basic style sheet for it to look better.
You can download this script from my github account.
Thank you for reading this article, and if you have any encountered anything different, have a different solution or think our solution is wrong, do let us know in the comment section. We will be very happy to hear that.
If you like our tutorial, please follow us on Twitter and help spread the word. We need your support to continue.