-
Notifications
You must be signed in to change notification settings - Fork 0
Digg Style Pagination
[h3]Digg Style Pagination Library[/h3]
The existing pagination class is sufficient, however, I wanted to produce digg-style pagination.
See here for an example of what I mean - http://www.strangerstudios.com/sandbox/pagination/diggstyle.php . 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.
[code]<?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 = ''; var $cur_tag_close = ''; 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.''.$this->first_link.''.$this->first_tag_close; } else $pagination.= "<span class="disabled">".$this->first_link."";
// Render the "previous" link if ($this->cur_page > 1) { $prev = $this->cur_page - 1; $pagination .= $this->prev_tag_open.''.$this->prev_link.''.$this->prev_tag_close; } else $pagination.= "<span class="disabled"><";
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"; // Current page } else { $pagination .= $this->num_tag_open.''.$counter.''.$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"; // Current page } else { $pagination .= $this->num_tag_open.''.$counter.''.$this->num_tag_close; } }
$pagination.= "..."; $num_pages_minus = $num_pages-1; $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$num_pages_minus.'">'.$num_pages_minus.'</a>'.$this->num_tag_close; $pagination .= $this->num_tag_open.'<a href="'.$this->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 href="'.$this->base_url.$one.'">'.$one.'</a>'.$this->num_tag_close; $pagination .= $this->num_tag_open.'<a href="'.$this->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 href="'.$this->base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close; } } $pagination.= "..."; $num_pages_minus = $num_pages-1; $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$num_pages_minus.'">'.$num_pages_minus.'</a>'.$this->num_tag_close; $pagination .= $this->num_tag_open.'<a href="'.$this->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 href="'.$this->base_url.$one.'">'.$one.'</a>'.$this->num_tag_close; $pagination .= $this->num_tag_open.'<a href="'.$this->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 href="'.$this->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.''.$this->next_link.''.$this->next_tag_close; } else $pagination.= "<span class="disabled">>";
// Render the "Last" link if ($this->cur_page < $counter - 1) { $pagination .= $this->last_tag_open.''.$this->last_link.''.$this->last_tag_close; } else $pagination.= "<span class="disabled">".$this->last_link."";
// 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 ?>[/code]
-
Secondly, a new pagination plugin to keep our controller files a bit cleaner So, make a new file here /system/plugins/pagination_pi.php
[code]<?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
-
- The default value set in the controller; or
-
- 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; } ?>[/code]
Thirdly, our controller file. To use the pagination, add this to the controller.
[code] $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);
[/code]
Fourthly, an example function from out model file.
[code] 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');
}
[/code]
Fifthly, our view file. Wherever you want the pagination to be, add this:
[code]
Sixthly, and also lastly, here is an example css file
[code] 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; } [/code]
Hope it helps someone out there!