-
Notifications
You must be signed in to change notification settings - Fork 0
Digg Style Pagination
The existing pagination class is sufficient, however, I wanted to produce digg-style pagination.
See here for an example of what I mean - [url]http://www.strangerstudios.com/sandbox/pagination/diggstyle.php[/url]. A lot of the updated code has been taken from the script provided there. However, some other improvements/alterations have also been made. Basically this is a mish-mash between the CI_Pagination library and the code found at the above link.
Benefits
- ability to let the user control how many records per page they would like to see. The url's for this are in the form of /controller/function/perpage/page. E.g. /controller/function/10/2 means show 10 records per page, and show the second page. Therefore you would be getting records 11- 20. Make sense?
- pages are in terms of page numbers (e.g. /view/10/2 means page 2 rather than offset of 2 which is more logical to me)
- if there are 100 pages (for example) rather than showing only a few pages either side of this in the pagination, digg-style will show a few pages either side as well as the first couple of pages and the last couple of pages. I think this increases usability.
- i think it looks better :)
[b]I have only overwritten the existing CI_Pagination class. This is a bit lazy but if you want to do the right thing you should probably rename it and call it as a custom-made library. This is my first library and I am not a guru PHP coder so there may well be something which can be optimised further or some minor bugs. Test it thoroughly before using in anything critical.[/b]
Ok first of all, the updated /system/libraries/Pagination.php file.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Code Igniter
*
* An open source application development framework for PHP 4.3.2 or newer
*
* @package CodeIgniter
* @author Rick Ellis
* @copyright Copyright (c) 2006, pMachine, Inc.
* @license http://www.codeignitor.com/user_guide/license.html
* @link http://www.codeigniter.com
* @since Version 1.0
* @filesource
*/
// ------------------------------------------------------------------------
/**
* Pagination Class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Pagination
* @author Rick Ellis
* @link http://www.codeigniter.com/user_guide/libraries/pagination.html
*/
class CI_Pagination {
var $base_url = ''; // The page we are linking to
var $total_rows = ''; // Total number of items (database results)
var $per_page = 10; // Max number of items you want shown per page
var $num_links = 2; // Number of "digit" links to show before/after the currently viewed page
var $cur_page = 0; // The current page being viewed
var $first_link = '‹ First';
var $next_link = '>';
var $prev_link = '<';
var $last_link = 'Last ›';
var $uri_segment = 3;
var $full_tag_open = '';
var $full_tag_close = '';
var $first_tag_open = '';
var $first_tag_close = ' ';
var $last_tag_open = ' ';
var $last_tag_close = '';
var $cur_tag_open = ' <b>';
var $cur_tag_close = '</b>';
var $next_tag_open = ' ';
var $next_tag_close = ' ';
var $prev_tag_open = ' ';
var $prev_tag_close = '';
var $num_tag_open = ' ';
var $num_tag_close = '';
/**
* Constructor
*
* @access public
* @param array initialization parameters
*/
function CI_Pagination($params = array())
{
if (count($params) > 0)
{
$this->initialize($params);
}
log_message('debug', "Pagination Class Initialized");
}
// --------------------------------------------------------------------
/**
* Initialize Preferences
*
* @access public
* @param array initialization parameters
* @return void
*/
function initialize($params = array())
{
if (count($params) > 0)
{
foreach ($params as $key => $val)
{
if (isset($this->$key))
{
$this->$key = $val;
}
}
}
}
// --------------------------------------------------------------------
/**
* Generate the pagination links
*
* @access public
* @return string
*/
function create_links()
{
// If our item count or per-page total is zero there is no need to continue.
if ($this->total_rows == 0 OR $this->per_page == 0)
{
return '';
}
// Calculate the total number of pages
$num_pages = ceil($this->total_rows / $this->per_page);
// Is there only one page? Hm... nothing more to do here then.
if ($num_pages == 1)
{
return '';
}
// Determine the current page number.
$CI =& get_instance();
if ($CI->uri->segment($this->uri_segment) != 0)
{
$this->cur_page = $CI->uri->segment($this->uri_segment);
// Prep the current page - no funny business!
$this->cur_page = preg_replace("/[a-z\-]/", "", $this->cur_page);
}
else
{
$this->cur_page = 1;
}
if ( ! is_numeric($this->cur_page))
{
$this->cur_page = 0;
}
// Is the page number beyond the result range?
// If so we show the last page
if ($this->cur_page > $num_pages)
{
$this->cur_page = $num_pages;
}
$uri_page_number = $this->cur_page;
//$this->cur_page = floor(($this->cur_page/$this->per_page) + 1);
// Add a trailing slash to the base URL if needed
$this->base_url = preg_replace("/(.+?)\/*$/", "\\1/", $this->base_url);
// And here we go...
$pagination = '';
// Render the "First" link
if ($this->cur_page > 1)
{
$pagination .= $this->first_tag_open.'<a >base_url.'">'.$this->first_link.'</a>'.$this->first_tag_close;
}
else
$pagination.= "<span class=\"disabled\">".$this->first_link."</span>";
// Render the "previous" link
if ($this->cur_page > 1)
{
$prev = $this->cur_page - 1;
$pagination .= $this->prev_tag_open.'<a >base_url.$prev.'">'.$this->prev_link.'</a>'.$this->prev_tag_close;
}
else
$pagination.= "<span class=\"disabled\"><</span>";
if ($num_pages < 7 + ($this->num_links * 2)) //not enough pages to bother breaking it up
{
for ($counter = 1; $counter <= $num_pages; $counter++)
{
if ($counter == $this->cur_page)
{
$pagination .= "<span class=\"current\">$counter</span>"; // Current page
}
else
{
$pagination .= $this->num_tag_open.'<a >base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close;
}
}
}
elseif($num_pages > 5 + ($this->num_links * 2)) //enough pages to hide some
{
//close to beginning; only hide later pages
if($this->cur_page < 1 + ($this->num_links * 2))
{
for ($counter = 1; $counter < 4 + ($this->num_links * 2); $counter++)
{
if ($counter == $this->cur_page)
{
$pagination .= "<span class=\"current\">$counter</span>"; // Current page
}
else
{
$pagination .= $this->num_tag_open.'<a >base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close;
}
}
$pagination.= "...";
$num_pages_minus = $num_pages-1;
$pagination .= $this->num_tag_open.'<a >base_url.$num_pages_minus.'">'.$num_pages_minus.'</a>'.$this->num_tag_close;
$pagination .= $this->num_tag_open.'<a >base_url.$num_pages.'">'.$num_pages.'</a>'.$this->num_tag_close;
}
//in middle; hide some front and some back
elseif($num_pages - ($this->num_links * 2) > $this->cur_page && $this->cur_page > ($this->num_links * 2))
{
$one=1;
$two=2;
$pagination .= $this->num_tag_open.'<a >base_url.$one.'">'.$one.'</a>'.$this->num_tag_close;
$pagination .= $this->num_tag_open.'<a >base_url.$two.'">'.$two.'</a>'.$this->num_tag_close;
$pagination.= "...";
for ($counter = $this->cur_page - $this->num_links; $counter <= $this->cur_page + $this->num_links; $counter++)
{
if ($counter == $this->cur_page)
{
$pagination.= "<span class=\"current\">$counter</span>";
}
else
{
$pagination .= $this->num_tag_open.'<a >base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close;
}
}
$pagination.= "...";
$num_pages_minus = $num_pages-1;
$pagination .= $this->num_tag_open.'<a >base_url.$num_pages_minus.'">'.$num_pages_minus.'</a>'.$this->num_tag_close;
$pagination .= $this->num_tag_open.'<a >base_url.$num_pages.'">'.$num_pages.'</a>'.$this->num_tag_close;
}
//close to end; only hide early pages
else
{
$one=1;
$two=2;
$pagination .= $this->num_tag_open.'<a >base_url.$one.'">'.$one.'</a>'.$this->num_tag_close;
$pagination .= $this->num_tag_open.'<a >base_url.$two.'">'.$two.'</a>'.$this->num_tag_close;
$pagination.= "...";
for ($counter = $num_pages - (2 + ($this->num_links * 2)); $counter <= $num_pages; $counter++)
{
if ($counter == $this->cur_page)
{
$pagination.= "<span class=\"current\">$counter</span>";
}
else
{
$pagination .= $this->num_tag_open.'<a >base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close;
}
}
}
}
// Render the "next" link
if ($this->cur_page < $counter - 1)
{
$next = $this->cur_page + 1;
$pagination .= $this->next_tag_open.'<a >base_url.$next.'">'.$this->next_link.'</a>'.$this->next_tag_close;
}
else
$pagination.= "<span class=\"disabled\">></span>";
// Render the "Last" link
if ($this->cur_page < $counter - 1)
{
$pagination .= $this->last_tag_open.'<a >base_url.$num_pages.'">'.$this->last_link.'</a>'.$this->last_tag_close;
}
else
$pagination.= "<span class=\"disabled\">".$this->last_link."</span>";
// Kill double slashes. Note: Sometimes we can end up with a double slash
// in the penultimate link so we'll kill all double slashes.
$pagination = preg_replace("#([^:])//+#", "\\1/", $pagination);
// Add the wrapper HTML if exists
$pagination = $this->full_tag_open.$pagination.$this->full_tag_close;
return $pagination;
}
}
// END Pagination Class
/* End of file Pagination.php */
/* Location: ./system/libraries/Pagination.php */
Secondly, a new pagination plugin to keep our controller files a bit cleaner So, make a new file here /system/plugins/pagination_pi.php
<?php
/**
* Initalises pagination config settings and returns the create_links string.
*
* @param unknown_type $cur_page_seg
* @param unknown_type $total_rows
* @param unknown_type $per_page_val
* @param unknown_type $per_page_seg
* @param unknown_type $pbase_url
* @return string
*/
function init_paginate ($cur_page_seg, $total_rows, $per_page_val, $per_page_seg, $pbase_url)
{
$obj =& get_instance();
//load relevant libraries
$obj->load->library('pagination');
//pagination setup
//echo $per_page_val;
$pbase_url = $pbase_url."/".$per_page_val;
$config['base_url'] = $pbase_url;
$config['total_rows'] = $total_rows;
$config['per_page'] = $per_page_val;
$config['uri_segment'] = $cur_page_seg;
//pagination initialization
$obj->pagination->initialize($config);
return $obj->pagination->create_links();
// end paging
}
/**
* Works out how many records should be shown per page. The value will either be taken from
* 1. The uri segment
* 2. The default value set in the controller; or
* 3. A default upper/lower range if people try to do tricky things in the uri segment (e.g. negative
* values).
*
* @param unknown_type $per_page_val
* @param unknown_type $per_page_seg
* @return unknown
*/
function get_per_page($per_page_val, $per_page_seg)
{
$per_page = validate_per_page($per_page_val, $per_page_seg);
return $per_page;
}
/**
* Validates the per page val and returns the value. Will check for out of bounds and non-numerical values
*
* @param unknown_type $per_page_val
* @param unknown_type $per_page_seg
* @return unknown
*/
function validate_per_page($per_page_val, $per_page_seg)
{
$obj =& get_instance();
//use per page if set from the uri, otherwise use default value set in controller
$per_page = $obj->uri->segment($per_page_seg, $per_page_val);
//security check - ensure value is numeric
if (is_numeric($per_page)) : $per_page=$per_page; else: $per_page = $per_page_val; endif;
//limit the per page value - prevents someone from doing a query of 1000 rows etc
if ($per_page > 100) : $per_page = 100; endif;
//limit the per page value from negative numbers
if ($per_page < 1) : $per_page = 10; endif;
return $per_page;
}
/**
* Will work out what offset should be used for a given sql query for a given pag
*
* @param unknown_type $cur_page_seg
* @param unknown_type $per_page_val
* @return unknown
*/
function get_offset($cur_page_seg, $per_page_val)
{
$obj =& get_instance();
//determine offset - per_page_val has already been validated
$page = 1;
if ($obj->uri->segment($cur_page_seg, 0)) : $page = $obj->uri->segment($cur_page_seg, 0); endif;
if ( $page == 1): $offset = 0; else : $offset = ($page - 1) * $per_page_val; endif;
return $offset;
}
?>
Thirdly, our controller file. To use the pagination, add this to the controller.
$this->load->model('My_Model', 'sql', TRUE);
//********************SET UP PAGINATION VALUES****************************
//set up per_page_value, per_page_seg, cur_page_seg and $data['pbase_url']
//************************************************************************
$this->load->plugin('pagination');
$per_page_value = 5; //default - unless overridden later
$per_page_seg = 5; //the uri segment for the per page value
$cur_page_seg = 6; //the url segment for the current page value (generally +1 of per page seg)
$per_page = get_per_page($per_page_value, $per_page_seg);
$offset = get_offset($cur_page_seg, $per_page);
//generate the query
$data['query'] = $this->sql->get_records($offset, $per_page);
//find out the total amount of records
$total_rows = count($this->sql->get_records(NULL, NULL));
$data['pbase_url'] = base_url().'path/to/controller/';
$data['pagination'] = init_paginate($cur_page_seg, $total_rows, $per_page, $per_page_seg, $data['pbase_url']);
$this->load->view('path/to/controller', $data);
Fourthly, an example function from out model file.
function get_records($offset, $limit)
{
//add where clause processing here if required
$this->db->select('*');
//$this->db->having($having);
if ($offset != NULL)
$this->db->offset($offset);
if ($limit != NULL)
$this->db->limit($limit);
if ($limit == NULL && $offset == NULL)
{
$count = $this->db->get('my_table');
return $count->result_array();
}
else
return $this->db->get('my_table');
}
Fifthly, our view file. Wherever you want the pagination to be, add this:
<div class="pagination" align="left">
<?php echo $pagination;?>
</div>
<!-- this is the number of records part - an example only -->
<div align="right"><a href="<?=$pbase_url;?>/10">10</a> | <a href="<?=$pbase_url;?>/20">20</a></div>
Sixthly, and also lastly, here is an example css file
div.pagination
{
padding: 3px;
margin: 3px;
}
div.pagination a
{
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #AAAADD;
text-decoration: none; /* no underline */
color: #000099;
}
div.pagination a:hover, div.pagination a:active
{
border: 1px solid #000099;
color: #000;
}
div.pagination span.current
{
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #000099;
font-weight: bold;
background-color: #993300;
color: #FFF;
}
div.pagination span.disabled
{
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #EEE;
color: #DDD;
}
Hope it helps someone out there!