Page Navigator

Can someone recommend a coding example of a well-developed “page navigator”. (This is for a gallery.)

When a user selects a category, the number of products returned will likely not fit on one gallery page, so I need a way to have page navigation functionality that lets people more forward one, backward one, go to first, and go to end.

Maybe like this?!

|<< <1 2 3 4 5 > >>|

This link isn’t too bad. (I like how you can also set the number of images per page.)

Also, if you have examples that are coded using OOP that would be a plus!

TomTees

It’s called pagination. If you google for it, you’ll get tons of examples.

Okay, but do you have any examples that you use and prefer??

Any links to help me see good examples?

Anyone else?

TomTees

Here are some good examples of php pagination

Being a smart-ass adds no value to this thread or Sitepoint…

If I just wanted to randomly surf the Internet for solutions I wouldn’t have joined Sitepoint.

There obviously must be a few above average examples that people commonly use/follow. (Sort of a “best practices” on pagination thing.)

If anyone wants to add some value to this thread, I welcome people experiences on this topic, how they choose to do things, opinions on why one approach is better than another, and of course any code that they can share (preferably OOP PHP).

TomTees

If memeory serves, Oddz has some very good Pagination examples here. Not sure if this will work, but try this search.

:slight_smile:

This is my algorithm to create a pagination interface w/ back, forward, next, last and page controls. It requires the use of a callback which is a offset and limit given a page that can be used to embed in a SQL statement. The callback must additionally return the number of total rows for the interface to be build correctly. It has been modified quite a bit so that it is decoupled from the rest of my frameworks code. You can modify as necessary to suite your needs but the logic to both retrieve data and build a HTML interface is all here in a reusable format. To test it out paste into any script and run it. Currently, I’m not running an SQL but the statement that could be ran to to get data is output at the top. Conseqentely hard coded values are also being hard coded for found rows. However, you would just return the number of total rows there when actually using it with your application code. I tried to make it as straightforward as possible given the lack of the rest of the code that it was meant to be used with. In doing so I decided to use dynamic functions for the call back. However, you could easily type hint the callback to an interface passing an object and calling the interface method instead. I just thought it would be more straightforward to use a dynamic function.


<?php
class Pagination {
	
	protected
	
	/*
	* Configuration defaults
	*/
	$_arrConfig = array(
		'limit'=>10
		,'page'=>1
		,'basePath'=>'#'
		,'label'=>'Items'
		,'visiblePages'=>5
		,'pageFlag'=>'{page}'
	)
	
	/*
	* Data to be passed to template
	*/
	,$_arrTemplateData = array()
	
	/*
	* function to pass resolved offset and limit
	*/
	,$_onPaginate
	
	/*
	* extra arguments to pass to to pagination callback 
	* such as data source or db connection
	*/
	,$_arrArgs;
	
	public function __construct($onPaginate,$arrConfig=array(),$arrArgs=array()) {
	
		$this->_onPaginate = $onPaginate;
		$this->_arrArgs = $arrArgs;
	
		foreach($arrConfig as $strKey=>$mixValue) {
			if(array_key_exists($strKey,$this->_arrConfig)) {
				$this->_arrConfig[$strKey] = $mixValue;
			}
		}
	}
	
	public function paginate() {
	
		/*
		* Calculate page offset 
		*/
		$intOffset = ($this->_arrConfig['page']-1)*$this->_arrConfig['limit'];
		
		/*
		* Paginate and get number of found rows 
		*/
		$intFoundRows = call_user_func_array($this->_onPaginate,array_merge(array($intOffset,$this->_arrConfig['limit']),$this->_arrArgs));
		
		/*
		* Assign template data 
		*/
		$this->_arrTemplateData['limit'] = $this->_arrConfig['limit'];
		$this->_arrTemplateData['page'] = $this->_arrConfig['page'];
		$this->_arrTemplateData['offset'] = $intOffset;
		$this->_arrTemplateData['found_rows'] = $intFoundRows;
		$this->_arrTemplateData['total_pages'] = $intFoundRows < $this->_arrConfig['limit']?1:ceil($intFoundRows/$this->_arrConfig['limit']);
		$this->_arrTemplateData['visible_pages'] = $this->_arrConfig['visiblePages'];
		$this->_arrTemplateData['base_path'] = $this->_arrConfig['basePath'];
		$this->_arrTemplateData['label'] = $this->_arrConfig['label'];
		$this->_arrTemplateData['page_flag'] = $this->_arrConfig['pageFlag'];
		
		/*
		* Return the pagination template 
		*/
		return $this->display();
	}
	
	public function display() {
		extract($this->_arrTemplateData);
		
		if($total_pages <= $visible_pages) {
    		$page_start = 1;
    		$page_end = $total_pages;
		} else if($page <= ceil($visible_pages/2)) {
    		$page_start = 1;
    		$page_end = $visible_pages;
		} else if($page > ($total_pages - ceil($visible_pages/2))) {
    		$page_start = $total_pages - (ceil(($visible_pages/2)*2)-1);
    		$page_end = $total_pages;
		} else {
    		$page_start = $page-(floor($visible_pages/2));
    		$page_end = $page+(floor($visible_pages/2));
		}
		
		$return = sprintf(
   			'<div class="summary"><p class="pages">&#37;u %s</p><p class="total">%u %s</p></div>'
    		,$total_pages
    		,$total_pages == 1?'Page':'Pages'
    		,$found_rows
    		,$found_rows == 1?$label:$label
		);
		
		$return.= sprintf('<ul class="pagination">');
		$return.= sprintf(
    		'<li class="first">%s%s%s</li>'
    		,$page == 1?'':sprintf('<a href="%s">',str_replace($page_flag,1,$base_path))
    		,'First'
    		,$page == 1?'':'</a>'
		);    
		$return.= sprintf(
    		'<li class="previous">%s%s%s</li>'
   		 	,$page == 1?'':sprintf('<a href="%s">',str_replace($page_flag,($page-1),$base_path))
    		,'Previous'
    		,$page == 1?'':'</a>'
		);
		foreach(range($page_start,$page_end,1) as $i) {
    		$return.= sprintf(
        		'<li%s>%s%s%s</li>'
        		,$page == $i?' class="current"':''
        		,$page == $i?'':sprintf('<a href="%s">',str_replace($page_flag,$i,$base_path))
        		,$i
        		,$page == $i?'':'</a>'
    		);
		}
		$return.= sprintf(
			'<li class="next">%s%s%s</li>'
			,$page == $total_pages?'':sprintf('<a href="%s">',str_replace($page_flag,($page+1),$base_path))
    		,'Next'
    		,$page == $total_pages?'':'</a>'
		);
		$return.= sprintf(
    		'<li class="last">%s%s%s</li>'
    		,$page == $total_pages?'':sprintf('<a href="%s">',str_replace($page_flag,$total_pages,$base_path))
    		,'Last'
    		,$page == $total_pages?'':'</a>'
		);
		$return.= sprintf('</ul>');
		
		return $return;
		
	}

}

class Action {

	public function paginate($offset,$limit) {
		
		// run query and assign returned data for listing
		echo "<p>SELECT SQL_CALC_FOUND_ROWS * FROM PRODUCTS LIMIT $offset,$limit</p>";
		
		// return number of total found rows
		return 400;
	
	}

}

$action = new Action();

$func = create_function('$offset,$limit,$action','return $action->paginate($offset,$limit);');
$pg = new Pagination($func,array(
	'basePath'=>$_SERVER['PHP_SELF'].'?pg={replace_me_with_page}'
	,'pageFlag'=>'{replace_me_with_page}'
	,'label'=>'Products'
	,'limit'=>5
	,'page'=>isset($_GET['pg']) && is_numeric($_GET['pg']) && $_GET['pg'] != 0?$_GET['pg']:1
),array($action));

echo $pg->paginate();

?>