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
https://forums.phpfreaks.com/topic/130432-solved-class-critique-pagination-class/
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?)

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!

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.

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

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.

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

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.

Archived

This topic is now archived and is closed to further replies.

×
×
  • 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.