Jump to content

[SOLVED] Class critique - Pagination class


wrathican

Recommended Posts

So, im pretty new to OOP and have read many a tutorial on alot of stuff to do with it.

 

I recently needed a pagination class and decided to write one. I have no idea whether its good/bad/ugly but it works and it didnt take long either.

 

this is the class:

<?php
#############################################
#############################################
############# Pagination Class ##############
#############################################
#############################################
# Purpose:
# To manage the pagination of database query
# results. 
# 
# Make this generic. Any set of results can
# be passed to the class and paginated.
# Count the amount of results, divide by 
# rows to show and boom! Result set would be
# a 2 dimensional array so gotta put something 
# in to make sure everything is ok. 
# 
# Two return functions: One to return the pagination
# links. Other to return the result set to 
# show.
# 
# Version 1.0 - First attempt
#############################################


class Pagination {

# Properties
private $server_addr; # Current address in address bar.
private $rows_to_show; # Declares the number of database rows to show
private $all_records; # Contains all records passed to the class
private $total_records; # Contains the number of total records
private $current_page; # Sets the number of current page
private $max_num_pages; # Contains the maximum number of pages 
private $row_start; # Sets the row number to start at
private $returned_records; # Contains the records that are going to be returned
private $paged_links; # Contains the paginated links to display.
private $links_first; # Contains the links to be displayed
private $links_prev;
private $links_sep;
private $links_next;
private $links_last;
private $query_string;
private $previous_page;
private $next_page;

# Parsing function
// Function to call all other functions
public function paginateResults ($results, $page, $an_array) {
	$this->setRowsToShow();
	$this->storeRecords($results);
	$this->countResults();
	$this->setCurrentPage($page);
	$this->setMaxPages();
	$this->setRowStart();
	$this->setReturnedRecords();
	$this->setServerAddr();
	$this->setLinksFormat($an_array);
	$this->setPagedLinks();
} // function


######################################################
################### SETTER METHODS ###################
######################################################

# Sets the number of rows to show
// This function uses a constant defined in class.conf.php
private function setRowsToShow () {
	$this->rows_to_show = ROWS_TO_SHOW;
} // function

# Store all the records
private function storeRecords ($results) {
	$this->all_records = $results;
} // function

# Count number of rows
private function countResults () {
	$this->total_records = count($this->all_records);
} // function

# Set current page
private function setCurrentPage ($page) {
	if($page == '') {
		$this->current_page = 1;
	}else{
		$this->current_page = $page;
	}
} // function

# Set max number of pages
private function setMaxPages () {
	$this->max_num_pages = ceil($this->total_records / $this->rows_to_show);
} // function

# Set row_start
private function setRowStart() {
	// do some math! noooooooooo!
	if($this->current_page < 1) {
		$this->row_start = 0;
	}elseif($this->current_page > $this->max_num_pages) {
		$this->row_start = $this->max_num_pages * $this->rows_to_show - $this->rows_to_show;
	}else{
		$this->row_start = $this->current_page * $this->rows_to_show - $this->rows_to_show;
	} // if
} // function

# Check page is within scope
private function checkPage () {
	// count results divide them up etc...
	// don't know if i really need this function...
} // function

# Set returned records
private function setReturnedRecords() {
	// splice the array
	$this->returned_records = array_slice($this->all_records, $this->row_start, $this->rows_to_show, true);
} // function

# Sets the next, prev, first, last and seperator
private function setLinksFormat ($an_array) {
	// $an_array will always be an array
	// [0] = first
	// [1] = prev
	// [2] = seperator
	// [3] = next
	// [4] = last
	$this->links_first = $an_array[0];
	$this->links_prev = $an_array[1];
	$this->links_sep = $an_array[2];
	$this->links_next = $an_array[3];
	$this->links_last = $an_array[4];
} // function

# Sets the page and query string. E.g - /index.php?p=1&d=2
private function setServerAddr () {
	$this->query_string = $_SERVER['QUERY_STRING'];
	$this->server_addr = basename($_SERVER['SCRIPT_FILENAME']) . '?';


	// do some cleaning of the query string to remove the page variable.
	//split the QS into different sections
	$this->query_string_array = explode("&", $this->query_string);
	// '/(.*)page=[0-9]*/i' Match the page pattern
	$this->server_addr .= preg_replace('/&page=[0-9]*/i', '', $this->query_string);
	// encode ampersands
	$this->server_addr = preg_replace('/&/', '&', $this->server_addr);
}

# Sets the links that are displayed on a page.
private function setPagedLinks () {
	$this->paged_links = '';
	// First/Prev
	if($this->current_page > 1) {
		// First Link
		$this->paged_links .= '<a href="'.$this->server_addr . '&page=1">' . $this->links_first .'</a> ';
		// Previous Link
		if($this->current_page - 1 < 1) {
			$this->previous_page = 1;
		}else{
			$this->previous_page = $this->current_page - 1;
		}
		$this->paged_links .= '<a href="'.$this->server_addr . '&page=' . $this->previous_page . '">' . $this->links_prev .'</a> ';
	}else{
		$this->paged_links .= $this->links_first . ' ' . $this->links_prev . ' ';
	}
	// page links
	for($i = $this->current_page - 3; $i < $this->current_page + 3; $i++) {
		if($i == $this->current_page) {
			$this->paged_links .= '- Page ' . $i . ' of ' . $this->max_num_pages . ' - ';
		}elseif (($i < 1) || ($i > $this->max_num_pages)) {
			$this->paged_links .= '';
		}elseif ($i == $this->max_num_pages){
			$this->paged_links .= '<a href="' . $this->server_addr . '&page=' . $i . '">' . $i .'</a> ';
		}else{
			$this->paged_links .= '<a href="' . $this->server_addr . '&page=' . $i . '">' . $i .'</a> ';
		}
	}

	// Next/Last
	if($this->current_page < $this->max_num_pages) {
		// Next link
		if($this->current_page + 1 > $this->max_num_pages) {
			$this->next_page = $this->max_num_pages;
		}else{
			$this->next_page = $this->current_page + 1;
		}
		$this->paged_links .= '<a href="'.$this->server_addr . '&page=' . $this->next_page . '">' . $this->links_next .'</a> ';
		// Last link
		$this->paged_links .= '<a href="'.$this->server_addr . '&page=' . $this->max_num_pages . '">' . $this->links_last .'</a>';
	}else{
		$this->paged_links .= $this->links_next . ' ' . $this->links_last;
	}
} // function

######################################################
################### GETTER METHODS ###################
######################################################

# returns the paged records
public function getReturnedRecords () {
	return $this->returned_records;
} // function

#returns the paged links
public function getPagedLinks () {
	return $this->paged_links;
} // function
}

?>

 

presume database connection is made

and includes are already included (couldnt be bothered writing it in)

and it would be used something like this:

<?php
define('ROWS_TO_SHOW', '10');

$link_format = array('<<First', '<Prev', '|', 'Next>', 'Last>>');

$query = "select * from table";
$result mysql_query($query);
$all_files = mysql_fetch_assoc($result)
$r->paginateResults($all_files, $_GET['page'], $link_format);
$trunc_files = $r->getReturnedRecords();
for($i=0; $i < count($trunc_files); $i++) {
//display the truncated rsults
}
echo $r->getPagedLinks();
?>

 

if it sucks, i would really appreciate knowing why, and your suggestions for making it better.

 

Thanking all who look kindly,

Wrathican

Link to comment
Share on other sites

Personally, I can't stand methods with one executable line and called only once (crumbled code). Your method setRowsToShow is IMHO also unneeded, because you can directly use constant ROWS_TO_SHOW.

 

Otherwise it looks good, although I am surprised to see URL composed only from server_addr and page_number. (Where is component_name or subject_name or st. of that kind?)

Link to comment
Share on other sites

The reason i define the ROWS_TO_SHOW is because i use this class on many pages and i needed a way of being able to set that data globally, rather than in every instance.

The reason i set $rows_to_show using a method is because i like to have all the class properties stored inside the class rather than using external data for any calculation.

 

Mastodont:

I dont get what you mean by this:

(Where is component_name or subject_name or st. of that kind?)

 

also, Which methods are you referring to?

I can't stand methods with one executable line and called only once (crumbled code)

 

Thanks for you feed back!

Link to comment
Share on other sites

The reason i define the ROWS_TO_SHOW is because i use this class on many pages and i needed a way of being able to set that data globally, rather than in every instance.

 

It's still incredibly bad practice. You could have something like a static method Pagination::setDefaultConfig() which will take default configuration using an associative array. You can then set it in the constructor. You'll then still have the regular setter methods for custom configuration data.

Link to comment
Share on other sites

that's a good point. I never thought of it like that.

 

so add a contructor method like so:

 

<?php
//inside of class
private function __contruct($array) {
$this->rows_to_show = $array['rows'];
$this->links_first = $array['first'];
}

//on instanciation
$array = ('rows' => 10, 'first' => '<<First');
$p = new Pagination($array);
?>

 

or am i missing the point?

 

Thanks for the advice

Link to comment
Share on other sites

You could do that, but I was thinking of something more like this:

 

class Pagination
{
static private $defaultConfig = array();
private $config = array();

public function __construct()
{
	$this->config = self::$defaultConfig;
}

static public function setDefaultConfig(array $config)
{
	self::$defaultConfig = $config;
}

public function setConfig(array $config)
{
	foreach ($config as $key => $value) {
		$this->config[$key] = $value;
	}

	return $this;
}

public function getConfig($key = null)
{
	if (!is_null($key) && isset($this->config[$key])) {
		return $this->config[$key];
	}

	return $this->config;
}

// etc.
}

Pagination::setDefaultConfig(array('foo' => 'bar', 'Daniel' => 'cool'));

$paginationOne = new Pagination(); // this one has the default config
$paginationTwo = new Pagination(); // so does this one... for now...
$pagination->setConfig(array('foo' => '123')); // ... but we changed a bit here

 

So you have a default setter and a specific setter and getter for the configuration data.

Link to comment
Share on other sites

Ahh that makes alot of sense.

 

Thanks so much for your advice.

 

here is the amended class:

<?php
#############################################
#############################################
############# Pagination Class ##############
#############################################
#############################################
# Purpose:
# To manage the pagination of database query
# results. 
# 
# Make this generic. Any set of results can
# be passed to the class and paginated.
# Count the amount of results, divide by 
# rows to show and boom! Result set would be
# a 2 dimensional array so gotta put something 
# in to make sure everything is ok. 
# Two functions: One to return the pagination
# links. Other to return the result set to 
# show.
# 
# Version 1.0 - First attempt
#############################################


class Pagination {


# Config properties
static private $defaultConfig = array();
private $config = array();

# Properties
private $server_addr; # Current address in address bar.
private $all_records; # Contains all records passed to the class
private $total_records; # Contains the number of total records
private $current_page; # Sets the number of current page
private $max_num_pages; # Contains the maximum number of pages 
private $row_start; # Sets the row number to start at
private $returned_records; # Contains the records that are going to be returned
private $paged_links; # Contains the paginated links to display.
private $query_string;
private $previous_page;
private $next_page;

# Configuration functions
public function __construct(){
	$this->config = self::$defaultConfig;
}

static public function setDefaultConfig(array $config){
	self::$defaultConfig = $config;
}

public function setConfig(array $config){
	foreach ($config as $key => $value) {
		$this->config[$key] = $value;
	}
	return $this;
}

public function getConfig($key = null){
	if (!is_null($key) && isset($this->config[$key])) {
		return $this->config[$key];
	}
	return $this->config;
}

# Parsing function
// Function to call all other functions
public function paginateResults ($results, $page, $an_array) {
	$this->storeRecords($results);
	$this->countResults();
	$this->setCurrentPage($page);
	$this->setMaxPages();
	$this->setRowStart();
	$this->setReturnedRecords();
	$this->setServerAddr();
	$this->setPagedLinks();
} // function

######################################################
################### SETTER METHODS ###################
######################################################

# Store all the records
private function storeRecords ($results) {
	$this->all_records = $results;
} // function

# Count number of rows
private function countResults () {
	$this->total_records = count($this->all_records);
} // function

# Set current page
private function setCurrentPage ($page) {
	if($page == '') {
		$this->current_page = 1;
	}else{
		$this->current_page = $page;
	}
} // function

# Set max number of pages
private function setMaxPages () {
	$this->max_num_pages = ceil($this->total_records / $this->config['rows']);
} // function

# Set row_start
private function setRowStart() {
	// do some math! noooooooooo!
	if($this->current_page < 1) {
		$this->row_start = 0;
	}elseif($this->current_page > $this->max_num_pages) {
		$this->row_start = $this->max_num_pages * $this->config['rows'] - $this->config['rows'];
	}else{
		$this->row_start = $this->current_page * $this->config['rows'] - $this->config['rows'];
	} // if
} // function

# Set returned records
private function setReturnedRecords() {
	// splice the array
	$this->returned_records = array_slice($this->all_records, $this->row_start, $this->config['rows'], true);
} // function

# Sets the page and query string. E.g - /index.php?p=1&d=2
private function setServerAddr () {
	$this->query_string = $_SERVER['QUERY_STRING'];
	$this->server_addr = basename($_SERVER['SCRIPT_FILENAME']) . '?';


	// do some cleaning of the query string to remove the page variable.
	//split the QS into different sections
	$this->query_string_array = explode("&", $this->query_string);
	// '/(.*)page=[0-9]*/i' Match the page pattern
	$this->server_addr .= preg_replace('/&page=[0-9]*/i', '', $this->query_string);
	// encode ampersands
	$this->server_addr = preg_replace('/&/', '&', $this->server_addr);
}

# Sets the links that are displayed on a page.
private function setPagedLinks () {
	$this->paged_links = '';
	// First/Prev
	if($this->current_page > 1) {
		// First Link
		$this->paged_links .= '<a href="'.$this->server_addr . '&page=1">' . $this->config['first'] .'</a> ';
		// Previous Link
		if($this->current_page - 1 < 1) {
			$this->previous_page = 1;
		}else{
			$this->previous_page = $this->current_page - 1;
		}
		$this->paged_links .= '<a href="'.$this->server_addr . '&page=' . $this->previous_page . '">' . $this->config['prev'] .'</a> ';
	}else{
		$this->paged_links .= $this->config['first'] . ' ' . $this->config['prev'] . ' ';
	}
	// page links
	for($i = $this->current_page - 3; $i < $this->current_page + 3; $i++) {
		if($i == $this->current_page) {
			$this->paged_links .= $i;
		}elseif (($i < 1) || ($i > $this->max_num_pages)) {
			$this->paged_links .= '';
		}elseif($i < $this->current_page){
			$this->paged_links .= '<a href="' . $this->server_addr . '&page=' . $i . '">' . $i .'</a>' . $this->config['sep'];
		}elseif($i > $this->current_page){
			$this->paged_links .= $this->config['sep'] . '<a href="' . $this->server_addr . '&page=' . $i . '">' . $i .'</a>';
		}
	}

	// Next/Last
	if($this->current_page < $this->max_num_pages) {
		// Next link
		if($this->current_page + 1 > $this->max_num_pages) {
			$this->next_page = $this->max_num_pages;
		}else{
			$this->next_page = $this->current_page + 1;
		}
		$this->paged_links .= ' <a href="'.$this->server_addr . '&page=' . $this->next_page . '">' . $this->config['next'] .'</a> ';
		// Last link
		$this->paged_links .= ' <a href="'.$this->server_addr . '&page=' . $this->max_num_pages . '">' . $this->config['last'] .'</a>';
	}else{
		$this->paged_links .= ' ' .$this->config['next'] . ' ' . $this->config['last'];
	}
} // function

######################################################
################### GETTER METHODS ###################
######################################################

# returns the paged records
public function getReturnedRecords () {
	return $this->returned_records;
} // function

#returns the paged links
public function getPagedLinks () {
	return $this->paged_links;
} // function
}

?>

 

Anything more i should do to make it better?

 

Thanks a lot

 

Wrathican

Link to comment
Share on other sites

One final addition could be the usage of fluent interfaces for methods that do not return a value so you'll be able to do something like this:

$obj = new Foo();
$foo->doSomething()
    ->doSomethingElse();

 

It just looks nicer. You'll make a method able to do this by returning $this. It's just a nice little addition, but in no way required. It saves you from typing the name of the variable each time if you need the object to perform a lot of operations after each other and neither of those return any value.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.