Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / PHP
Alternative
Tip/Trick

Dynamic Pagination

Rate me:
Please Sign up or sign in to vote.
4.22/5 (9 votes)
25 Jan 2010CPOL 13.2K   4   3
More validation can be applied when handling default values. I am not a fan of outputing anything directly from a class, I prefer to return the links as an array. It's easier to maintain. This way, when/if you change the styling; then it saves having to trawl through your classes.<?phpclass...
More validation can be applied when handling default values. I am not a fan of outputing anything directly from a class, I prefer to return the links as an array. It's easier to maintain. This way, when/if you change the styling; then it saves having to trawl through your classes.
PHP
<?php
class Pagination
{
	const DEFAULT_DISPLAYED_ROWS = 30;
	const DEFAULT_GET_INDEX = 'page';
	const DEFAULT_MAX_LINKS_DISPLAYED = 5;

	protected $get_index;
	protected $max_links_displayed;
	protected $total_number_of_records;

	protected $displayed_rows;
	public function get_displayed_rows()
	{
		return $this->displayed_rows;
	}
	
	protected $start;
	public function get_start()
	{
		return $this->start;
	}
	
	public function __construct( $total_number_of_records , $displayed_rows = null , $max_links_displayed = null , $get_index = null )
	{
		$this->total_number_of_records = is_int( $total_number_of_records ) && $this->total_number_of_records >= 0 ? $total_number_of_records : null;
		if ( !isset( $this->total_number_of_records ) )
			throw new Exception( '$total_number_of_records must be an int and greater than or equal to 0' );
		
		// Check is $displayed_rows is set and a int, otherwise it is the default.
		$this->displayed_rows = isset( $displayed_rows ) && is_int( $displayed_rows ) ? $displayed_rows : self::DEFAULT_DISPLAYED_ROWS;
		
		// Check is $max_links_displayed is set and an int, otherwise it is the default.
		$this->max_links_displayed = isset( $max_links_displayed ) && is_int( $max_links_displayed ) && $max_links_displayed >= 0
						? $max_links_displayed : self::DEFAULT_MAX_LINKS_DISPLAYED;

		// Check is $get_index is set and a string, otherwise it is the default.
		$this->get_index = isset( $get_index ) && is_string( $get_index ) ? $get_index : self::DEFAULT_GET_INDEX;
		
		// Check the if the page start ($_GET[$this->get_index]) is set, int, greater than 0 and less than $total_number_of_records.
		$this->start = isset( $_GET[ $this->get_index ] ) && is_int( (int)$_GET[ $this->get_index ] ) && $_GET[ $this->get_index ] >= 0
						&& $_GET[ $this->get_index ] < $total_number_of_records ? $_GET[ $this->get_index ] : 0;
		
		// Round down to a mulitple of $this->displayed_rows.
		$this->start = $this->start >= $this->displayed_rows ? $this->round_to_multiple( $this->displayed_rows , $this->start ) : 0;
	}

	public function get_paginate_links()
	{
		// Get a clean URL.
		$url = isset( $_GET[ $this->get_index ] ) ? str_ireplace( array( '?' . $this->get_index . '=' . $_GET[ $this->get_index ] ,
						'&' . $this->get_index . '=' . $_GET[ $this->get_index ] ) , '' , $_SERVER[ 'REQUEST_URI' ] ) : $_SERVER[ 'REQUEST_URI' ];
		$url = htmlentities( $url . ( ( substr( $url , -4 ) == '.php' || substr( $url , -1 ) == '/' ) ? '?' : '&' ) . $this->get_index . '=' );

		$links = array();
		
		// If the current paginate is not the first.
		if ( $this->start > 0 )
		{
			$links[] = $this->paginate_link( 'First' , $url . '0' );
			$links[] = $this->paginate_link( 'Prev' , $url . ( $this->start - $this->displayed_rows ) );
		}

		// The last multiple to be allowed to display.
		$last = $this->round_to_multiple( $this->displayed_rows , $this->total_number_of_records - 1);
		
		// Get the page currently on.
		$current_page = ( $this->start / $this->displayed_rows ) + 1;
		
		// Get the last page number to be displayed.
		$last_page = ( $last / $this->displayed_rows ) + 2;

		// Get the page to start counting from.
		$start_page = $current_page > 0 ? $current_page - ( floor( $this->max_links_displayed / 2 ) - ( $this->max_links_displayed % 2 == 0 ? 1 : 0 ) ) : 1;
		$start_page = $start_page + $this->max_links_displayed > $last_page ? $last_page - $this->max_links_displayed : $start_page;
		
		$links_displayed = 0;
		while ( $links_displayed < $this->max_links_displayed )
		{
			// If the last page is reached before the maximum links have been displayed.
			if ( $start_page + $links_displayed == $last_page )
				break;

			// If the current page (in the loop) is not in arrears (negative).
			if ( $start_page + $links_displayed > 0 )
			{
				if ( $start_page + $links_displayed == $current_page )
					$links[] = $this->paginate_link( $start_page + $links_displayed , '#', true );
				else
					$links[] = $this->paginate_link( $start_page + $links_displayed , $url . ( ($start_page + $links_displayed - 1) * $this->displayed_rows ) );
			}
			else
				$this->max_links_displayed++;

			$links_displayed++;
		}

		// If the current page is not the last.
		if ( $current_page < $last_page - 1 )
		{
			$links[] = $this->paginate_link( 'Next' , $url . ( $this->start + $this->displayed_rows ) );
			$links[] = $this->paginate_link( 'Last' , $url . $last );
		}
		
		return $links;
	}

	private function paginate_link( $name , $href , $current = null )
	{
		if ( isset( $current ) )
			return array( 'name' => $name , 'href' => $href , 'current' => $current );
		else
			return array( 'name' => $name , 'href' => $href );
	}

	private function round_to_multiple( $factor , $value )
	{
		return $value % $factor == 0 ? $value : ( ceil( $value / $factor ) - 1 ) * $factor;
	}
}
?>
To be called similarly by your method.
PHP
<?php

$Pagination = new Pagination( 10 , 2 , 3 );

// ...
// mysql_query( 'SELECT * FROM table LIMIT ' . $Pagination->get_start() . ', ' . $Pagination->get_displayed_rows() );
// ...

foreach ( $Pagination->get_paginate_links() as $link )
{
	echo '<a href="' . $link[ 'href' ] . '"' . ( isset( $link[ 'current' ] ) ? 'style="text-decoration: none;"' : '' ) . '>' . $link[ 'name' ] . '</a> ';
}

?>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 1 Pin
jnrx7-Oct-12 18:03
jnrx7-Oct-12 18:03 
GeneralReason for my vote of 5 Returning value is better than direc... Pin
Res_Nullius12-Aug-11 0:54
Res_Nullius12-Aug-11 0:54 
GeneralReason for my vote of 5 ?a marche vraiment bien... Pin
jr from Yaoundé19-Jul-10 7:06
jr from Yaoundé19-Jul-10 7:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.