Skip to content

Instantly share code, notes, and snippets.

@anjan011
Last active August 17, 2016 07:55
Show Gist options
  • Save anjan011/4c1a2a6068d189a6769a to your computer and use it in GitHub Desktop.
Save anjan011/4c1a2a6068d189a6769a to your computer and use it in GitHub Desktop.
php class: SimplePager
<?php
/**
* Created by PhpStorm.
* User: anjan
* Date: 9/30/15
* Time: 9:23 AM
*/
class SimplePager {
const DEFAULT_RECORDS_PER_PAGE = 20;
const DEFAULT_MAX_VISIBLE_LINK = 3;
const DEFAULT_PAGE_NUMBER_TEMPLATE_TAG = '{{page}}';
/**
* Total records
*
* @var int
*/
private $totalRecords = 0;
/**
* Records per page
*
* @var int
*/
private $recordsPerPage = self::DEFAULT_RECORDS_PER_PAGE;
/**
* Total pages (Calculated)
*
* @var int
*/
private $totalPages = 0;
/**
* max visible links
*
* @var int
*/
private $maxVisibleLinks = 5;
/**
* The base URL
*
* @var string
*/
private $pageUrl = '';
/**
* Page number template tag, which will be replaced by actual page number
*
* @var string
*/
private $pageNumberTemplateTag = '{{page}}';
/**
* Current page number
*
* @var int
*/
private $currentPageNumber = 1;
/**
* Pager container tag
*
* @var array
*/
private $pagerContainer = array(
'tag' => 'ul',
'attrs' => array(
'class' => 'pagination'
)
);
/**
* Each link container tag
*
* @var string
*/
private $linkContainer = array(
'tag' => 'li',
'attrs' => array(
'class' => ''
)
);
/**
* Common css class for page hyperlinks
*
* @var string
*/
private $linkCssClass = 'page-link';
/**
* Show first and last links?
*
* @var bool
*/
private $showFirstLastLink = true;
/**
* Show prev and next links?
*
* @var bool
*/
private $showPrevNextLink = true;
/**
* Display all page links?
*
* @var bool
*/
private $showAllLinks = false;
/**
* Get array value.
*
* It takes the array and a key name or a key path to access element in multidimensional array
*
* @param array $array The array to conduct the search on
* @param string $key The Key name or key path (a/b/c/d)
* @param mixed $default The default value
* @param null $callback
*
* @return mixed
*/
function array_value( $array, $key, $default = NULL , $callback = NULL) {
if ( !is_array( $array ) ) {
return $default;
}
$key = trim( trim( $key ), '/' );
$parts = explode( '/', $key );
foreach ( $parts as $p ) {
$array = isset($array[ $p ]) ? $array[ $p ] : NULL;
if ( $array === NULL ) {
return $default;
}
}
if(is_callable($callback)) {
$array = call_user_func($callback,$array);
}
return $array;
}
/**
* Parse and format page container data
*
* @param array $data
*/
private function setPageContainerData($data = array()) {
$data = is_array($data) ? $data : array();
$data['tag'] = $this->array_value($data,'tag','ul','trim');
$data['attrs'] = $this->array_value($data,'attrs',array());
$data['attrs']['class'] = $this->array_value($data['attrs'],'class','pagination','trim');
$this->pagerContainer = $data;
}
/**
* Set link container data
*
* @param array $data
*/
private function setLinkContainerData($data = array()) {
$data = is_array($data) ? $data : array();
$data['tag'] = $this->array_value($data,'tag','li','trim');
$data['attrs'] = $this->array_value($data,'attrs',array());
$data['attrs']['class'] = $this->array_value($data['attrs'],'class','','trim');
$this->linkContainer = $data;
}
/**
* Generates a line of text
*
* @param int $tabs
* @param int $new_lines
* @param string $msg
*
* @return string
*/
private function _m( $tabs = 0, $new_lines = 1, $msg = '' ) {
$tabs = (int) $tabs;
if ( $tabs < 0 ) {
$tabs = 0;
}
$new_lines = (int) $new_lines;
if ( $new_lines < 0 ) {
$new_lines = 0;
}
return str_repeat( " ", $tabs ).$msg.str_repeat( PHP_EOL, $new_lines);
}
/**
* tag markup
*
* @param array $attrs atg attributes
*
* @return string
*/
private function __attr_markup( $attrs = array() ) {
$html = '';
if ( is_array( $attrs ) && count( $attrs ) > 0 ) {
foreach ( $attrs as $k => $v ) {
$html .= " {$k}=\"".htmlentities( (string) $v, ENT_QUOTES )."\"";
}
}
return trim( $html );
}
/**
* Generate the url for a pager
*
* @param $page_no
*
* @return mixed
*/
private function _link_url( $page_no ) {
$page_no = (int) $page_no;
$url = str_replace( $this->pageNumberTemplateTag, $page_no, $this->pageUrl );
return $url;
}
/**
* Constructor. We parse all params here
*
* @param array $params
*/
function __construct( $params = array() ) {
/* Total records */
$this->totalRecords = (int)$this->array_value($params,'totalRecords',0);
if ( $this->totalRecords < 0 ) {
$this->totalRecords = 0;
}
/* Records per page */
$this->recordsPerPage = (int)$this->array_value($params,'recordsPerPage',self::DEFAULT_RECORDS_PER_PAGE);
if ( $this->recordsPerPage < 1 ) {
$this->recordsPerPage = 1;
}
/* max visible links */
$this->maxVisibleLinks = (int)$this->array_value($params,'maxVisibleLinks',self::DEFAULT_MAX_VISIBLE_LINK);
if ( $this->maxVisibleLinks < 1 ) {
$this->maxVisibleLinks = 1;
}
/* Total pages */
if ( $this->totalRecords > 0 ) {
$this->totalPages = (int) (ceil( $this->totalRecords / $this->recordsPerPage ));
}
else {
$this->totalPages = 0;
}
/* page URL */
$this->pageUrl = $this->array_value($params,'pageUrl','','trim');
/* page number template tag */
$this->pageNumberTemplateTag = $this->array_value($params,'pageNumberTemplateTag',self::DEFAULT_PAGE_NUMBER_TEMPLATE_TAG,'trim');
if ( $this->pageNumberTemplateTag == '' ) {
$this->pageNumberTemplateTag = self::DEFAULT_PAGE_NUMBER_TEMPLATE_TAG;
}
/* Current page number */
$this->currentPageNumber = (int)$this->array_value($params,'currentPageNumber',1);
if ( $this->currentPageNumber < 1 ) {
$this->currentPageNumber = 1;
}
// page container
$this->setPageContainerData($this->array_value($params,'pagerContainer',array()));
// link container
$this->setLinkContainerData($this->array_value($params,'linkContainer',array()));
// Show first/last link
$this->showFirstLastLink = $this->array_value($params,'showFirstLastLink',true);
// Show prev/next link
$this->showPrevNextLink = $this->array_value($params,'showPrevNextLink',true);
// Show all links?
$this->showAllLinks = $this->array_value($params,'showAllLinks',false);
// page link css class
$this->linkCssClass = $this->array_value($params,'linkCssClass','page-link');
}
/**
* Generate pager
*
* @return string
*/
public function generatePager() {
if ( $this->pageUrl == '' ) {
return 'No page url specified!';
}
if ( strpos( $this->pageUrl, $this->pageNumberTemplateTag ) === FALSE ) {
return 'Page number template tag '.$this->pageNumberTemplateTag.' not found in the url!';
}
/**
* No paging if there is no page or only 1 page
*/
if ( $this->totalPages <= 1 ) {
return '';
}
# ========================================================
# Process when all links should be shown
# ========================================================
if($this->showAllLinks) {
$this->showFirstLastLink = false;
$this->showPrevNextLink = false;
}
# ========================================================
# Init variables for use later on
# ========================================================
$maxVisibleLinks = $this->maxVisibleLinks;
$currentPageNumber = $this->currentPageNumber;
$totalRecords = $this->totalRecords;
$recordsPerPage = $this->recordsPerPage;
$totalPages = $this->totalPages;
// Pager Container
$_ct = $this->array_value($this->pagerContainer,'tag','ul','trim');
$_c_attrs_markup = $this->__attr_markup($this->array_value($this->pagerContainer,'attrs',array()));
// Link Container
$_lt = $this->array_value($this->linkContainer,'tag','li','trim');
$_l_attrs = $this->array_value($this->linkContainer,'attrs',array());
// link css class
$linkCssClass = $this->linkCssClass;
# ========================================================
# Generate the html
# ========================================================
$html = $this->_m( 0, 1, "<{$_ct} {$_c_attrs_markup}>" );
// First link
if($this->showFirstLastLink) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= ($currentPageNumber == 1 ? ' disabled' : '');
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$linkAttr = array(
'class' => trim($linkCssClass.' page-link-first'),
'aria-label' => 'First Page',
'data-page' => 1,
'title' => 'First Page',
);
if($currentPageNumber != 1) {
$linkAttr['href'] = $this->_link_url( 1 );
}
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( $linkAttr ).'>' );
$html .= $this->_m( 3, 1, '<span class="glyphicon glyphicon-fast-backward"></span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// Prev link
if($this->showPrevNextLink) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= $currentPageNumber == 1 ? ' disabled' : '';
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$prevPageNumber = $currentPageNumber - 1;
if ( $prevPageNumber < 1 ) {
$prevPageNumber = 1;
}
$linkAttr = array(
'class' => trim($linkCssClass.' page-link-prev'),
'aria-label' => 'Previous Page',
'data-page' => $prevPageNumber,
'title' => 'Previous Page',
);
if($currentPageNumber != 1) {
$linkAttr['href'] = $this->_link_url( $prevPageNumber );
}
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( $linkAttr ).'>' );
$html .= $this->_m( 3, 1, '<span class="glyphicon glyphicon-chevron-left"></span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// generate visible links in middle
if($this->showAllLinks) {
$startIndex = 1;
$endIndex = $totalPages;
} else {
$startIndex = $currentPageNumber - $maxVisibleLinks;
$endIndex = $currentPageNumber + $maxVisibleLinks;
}
if ( $startIndex < 1 ) {
$startIndex = 1;
}
if ( $endIndex > $totalPages ) {
$endIndex = $totalPages;
}
// Left void region
if ( !$this->showAllLinks && $startIndex > 1 ) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= ' disabled';
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( array(
'class' => 'text-info',
) ).'>' );
$html .= $this->_m( 3, 1, '<span>...</span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// THE links ...
for ( $i = $startIndex; $i <= $endIndex; $i++ ) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= $i == $currentPageNumber ? ' active' : '';
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$linkAttrs = array(
'class' => trim($linkCssClass),
'aria-label' => "Page {$i} of {$totalPages}",
'data-page' => $i,
'title' => "Page {$i} of {$totalPages}",
);
if( $i != $currentPageNumber) {
$linkAttrs['href'] = $this->_link_url( $i );
}
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( $linkAttrs ).'>' );
$html .= $this->_m( 3, 1, '<span>'.$i.'</span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// Right void region
if ( !$this->showAllLinks && $endIndex < $totalPages ) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= ' disabled';
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( array(
'class' => 'text-info',
) ).'>' );
$html .= $this->_m( 3, 1, '<span>...</span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// Next link
if($this->showPrevNextLink) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= $currentPageNumber == $totalPages ? ' disabled' : '';
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$nextPageNumber = $currentPageNumber + 1;
if ( $nextPageNumber >= $totalPages ) {
$nextPageNumber = $totalPages;
}
$linkAttr = array(
'class' => trim($linkCssClass.' page-link-next'),
'aria-label' => 'Next Page',
'data-page' => $nextPageNumber,
'title' => 'Next Page',
);
if($currentPageNumber != $totalPages) {
$linkAttr['href'] = $this->_link_url( $nextPageNumber );
}
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( $linkAttr ).'>' );
$html .= $this->_m( 3, 1, '<span class="glyphicon glyphicon-chevron-right"></span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// Last link
if($this->showFirstLastLink) {
$liAttrs = $_l_attrs;
$liAttrs['class'] .= $currentPageNumber == $totalPages ? ' disabled' : '';
$html .= $this->_m( 1, 1, '<'.$_lt.' '.$this->__attr_markup( $liAttrs ).'>' );
$linkAttr = array(
'class' => trim($linkCssClass.' page-link-last'),
'aria-label' => 'Last Page',
'data-page' => $totalPages,
'title' => 'Last Page',
);
if($currentPageNumber != $totalPages) {
$linkAttr['href'] = $this->_link_url( $totalPages );
}
$html .= $this->_m( 2, 1, '<a '.$this->__attr_markup( $linkAttr ).'>' );
$html .= $this->_m( 3, 1, '<span class="glyphicon glyphicon-fast-forward"></span>' );
$html .= $this->_m( 2, 1, '</a>' );
$html .= $this->_m( 1, 1, '</'.$_lt.'>' );
}
// End of generation (almost!)
$html .= $this->_m( 0, 1, "</{$_ct}>" );
return $html;
}
/**
* Generates records info in the form of "Showing {start} - {end} of {total}" e.g. "Showing 1 - 20 of 78"
*
* @param null $callback Optional callback function, which are called with $start,$end and $total params,
* allowing user to override the text generated.
*
* @return string
*/
public function generateRecordsInfo($callback = null) {
$totalRecords = (int)$this->totalRecords;
if($totalRecords <= 0) {
return '';
}
$recordsPerPage = (int)$this->recordsPerPage;
if($recordsPerPage <= 0) {
return '';
}
$currentPageNo = (int)$this->currentPageNumber;
if($currentPageNo < 1) {
$currentPageNo = 1;
}
$startIndex = ($currentPageNo - 1) * $recordsPerPage + 1;
$endIndex = $currentPageNo * $recordsPerPage;
if($endIndex > $totalRecords) {
$endIndex = $totalRecords;
}
if(is_callable($callback)) {
return call_user_func($callback,$startIndex,$endIndex,$totalRecords);
}
$text = "Showing {$startIndex} - {$endIndex} of {$totalRecords}";
return $text;
}
}
# simple usage
$simplePager = new SimplePager(array(
'totalRecords' => 228,
'recordsPerPage' => 15,
'maxVisibleLinks' => 10,
'pageUrl' => 'http://mysite.net/some-page.php?_pageId={%pageNum%}',
'pageNumberTemplateTag' => '{%pageNum%}',
'currentPageNumber' => $_GET['_pageId'],
'pagerContainer' => array(
'tag' => 'div',
'attrs' => array(
'id' => 'top-pager',
'class' => 'pager'
)
),
'linkContainer' => array(
'tag' => 'span',
'attrs' => array(
'class' => 'page-link'
)
),
'linkCssClass' => ''
));
echo $simplePager->generatePager();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment