After a long pause, here am I. Well, there’s a few tutorials around, including the official CI wiki suggesting a more friendly pagination implementation, with page numbers on the link, because the actual CI pagination works with the offset from the database. The code I use today is from the official wiki, but the search system I implemented myself, So, here we go…
First, on the original file, we have the create_link() function. On mine, there is an argument $search, it will be permanent on every link, just like this: http://www.server.com/products/page/2/notebook-sony
I modified the ident style from CI Pagination.php, I Just can’t work with the Allman ident style (more info info: a href=”http://en.wikipedia.org/wiki/Indent_style”>wikipedia). Analising the whole code, there is no big tricks, I just concatenate the search argumento in the end of links.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * CodeIgniter * * An open source application development framework for PHP 4.3.2 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team * @copyright Copyright (c) 2008, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 * @filesource */ // ------------------------------------------------------------------------ /** * Pagination Class * * @package CodeIgniter * @subpackage Libraries * @category Pagination * @author ExpressionEngine Dev Team * @link http://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 = ''; var $page_query_string = FALSE; var $query_string_segment = 'per_page'; /** * 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($search='') { if ($search!='') $search = '/'.$search; // 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->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE){ if ($CI->input->get($this->query_string_segment) != 0){ $this->cur_page = $CI->input->get($this->query_string_segment); // Prep the current page - no funny business! $this->cur_page = (int) $this->cur_page; } } else { 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 = (int) $this->cur_page; } } if ( ! is_numeric($this->cur_page)) { $this->cur_page = 0; } if ($this->cur_page==0) { $this->cur_page = 1; } // Is the page number beyond the result range? // If so we show the last page if ($this->cur_page > $this->total_rows) { $this->cur_page = ($num_pages - 1) * $this->per_page; } $uri_page_number = $this->cur_page; // Calculate the start and end numbers. These determine // which number to start and end the digit links with $start = (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1; $end = (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages; // Is pagination being used over GET or POST? If get, add a per_page query // string. If post, add a trailing slash to the base URL if needed if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) { $this->base_url = rtrim($this->base_url).'&'.$this->query_string_segment.'='; } else { $this->base_url = rtrim($this->base_url, '/') .'/'; } // And herwe go... $output = ''; // Render the "First" link if ($this->cur_page > $this->num_links) { $output .= $this->first_tag_open.'<a href="'.$this->base_url.'1'.$search.'">'.$this->first_link.'</a>'.$this->first_tag_close; } // Render the "previous" link if (($this->cur_page - $this->num_links) >= 0) { $i = $this->cur_page - 1; if ($i == 0) $i = ''; $output .= $this->prev_tag_open.'<a href="'.$this->base_url.$i.$search.'">'.$this->prev_link.'</a>'.$this->prev_tag_close; } // Write the digit links for ($loop = $start -1; $loop <= $end; $loop++) { $i = ($loop * $this->per_page) - $this->per_page; if ($i >= 0) { if ($this->cur_page == $loop) { $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page } else { $n = ($i == 0) ? '1' : $loop; $output .= $this->num_tag_open.'<a href="'.$this->base_url.$n.$search.'">'.$loop.'</a>'.$this->num_tag_close; } } } // Render the "next" link if ($this->cur_page < $num_pages) { $output .= $this->next_tag_open.'<a href="'.$this->base_url.($this->cur_page + 1).$search.'">'.$this->next_link.'</a>'.$this->next_tag_close; } // Render the "Last" link if (($this->cur_page + $this->num_links) < $num_pages) { $i = $num_pages; $output .= $this->last_tag_open.'<a href="'.$this->base_url.$i.$search.'">'.$this->last_link.'</a>'.$this->last_tag_close; } // Kill double slashes. Note: Sometimes we can end up with a double slash // in the penultimate link so we'll kill all double slashes. $output = preg_replace("#([^:])//+#", "\\1/", $output); // Add the wrapper HTML if exists $output = $this->full_tag_open.$output.$this->full_tag_close; return $output; } } // END Pagination Class /* End of file Pagination.php */ /* Location: ./system/libraries/Pagination.php */ |
Copy the above file inside the application/libraries, CI try to find the files there first, and if not found, it uses from the core library. Well, on controller I use three functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | function index() { // Forcing the use of page function... redirect('products/page/1'); } /* Function search() * Search function of the controller. If you have a "product" controller, the * action form from of your view will be something like action="product/search" */ function search() { $terms = array(); /* * Here you have to adjust your "uri segment", * if your controller is inside a directory */ if ($this->uri->segment(3)!='') { /* * Here, I suppose I already have a search running... */ $search = $this->uri->segment(3); $search = str_replace(' ','-',$search); valid_char_only($search); // Function to remove accents and invalid characters, use any function // Preparando array $aux = explode('-',$search); foreach($aux as $key => $valor) { $terms[] = $valor; } } else { /* * Here I get the value from the field (myField) and split if there is * more than 2 words, and put an hyphen separating the words. */ $search = $this->input->post('myField'); $search = str_replace(' ','-',$search); valid_char_only($search); // Function to remove accents and invalid characters, use any function // Preparando array $aux = explode('-',$search); foreach($aux as $key => $valor) { $terms[] = $valor; } } /* * You see, there is no database query in here, this function * only format the url and send it to the controller that does * everything, the "page" controller */ redirect('product/page/1/'.$search); } function page($page='',$terms='') { /* * If there is no page on argument, I force using the page 1 */ if ($page=='') { redirect('produto/page/1'); } /* * On my application, the segment 4 is the search string */ if ($this->uri->segment(4)!='') { $terms = $this->uri->segment(4); } $this->load->library('pagination'); $limit = 20; $offset = ($page-1)*$limit; if ($terms=='') { /* * If there is no search, I do the normal query */ $this->db->limit($limit, $offset); $query = $this->db->get('products'); $data['total'] = $query->num_rows(); } else { /* * Preparing the search, spliting the terms and inserting * one LIKE for each field on database */ $search = str_replace(' ','-',$terms); // Preparing array $mysearch = array(); $aux = explode('-',$search); foreach($aux as $key => $valor) { $mysearch[] = $valor; } /* * On this example, I'm using only one search field, * but looking for 3 fields on table on same time, name, id, and description. */ $this->db->like('name', $mysearch[0]); $this->db->or_like('id', $mysearch[0]); $this->db->or_like('description', $mysearch[0]); $tt = count($mysearch); if ($tt>0) { for ($j=1;$j<$tt;$j++) { $this->db->or_like('name', $mysearch[$j]); $this->db->or_like('id', $mysearch[$j]); $this->db->or_like('description', $mysearch[$j]); } } /* * Here I recover the total number of products, * just to show the total on my view; */ $query_tt = $this->db->get('products'); $this->db->like('name', $mysearch[0]); $this->db->or_like('id', $mysearch[0]); $this->db->or_like('description', $mysearch[0]); $tt = count($mysearch); if ($tt>0) { for ($j=1;$j<$tt;$j++) { $this->db->or_like('name', $mysearch[$j]); $this->db->or_like('id', $mysearch[$j]); $this->db->or_like('description', $mysearch[$j]); } } $this->db->limit($limit, $offset); $query = $this->db->get('products'); $data['total'] = $query_tt->num_rows(); } $config['base_url'] = base_url().INDEX.'product/page/'; $config['total_rows'] = $data['total']; $config['per_page'] = $limit; $config['uri_segment'] = 3; $config['num_links'] = 5; $this->pagination->initialize($config); $data['num_of_pges'] = round($data['total'] / $limit); $data['products'] = $query; $this->load->view('products',$data); } |
Well, using this class, your website will search things in the following format:
http://www.server.com/products/page/13/notebook-sony
http://www.server.com/products/page/10/cannon-digital-cam
Just to mention, I didn’t tested with query strings on!

{ 7 comments… read them below or add one }
Not work for me, probable the segmet from the post of search. Is not there. Can you please, sent me all files for pagination ?
Hello guys the above worked a bit.. but needs few changes.
follow this, i have successfully done it
http://codeigniter.com/forums/viewthread/120770/
follow me on twitter http://www.twitter.com/bluepicaso
Excellent! Nice tutorial.
Hello
your tutorial is good
can you share valid_char_only function also?:) thanks
Can you give me a hint on how can I show the result on the VIEW page? Thanks
You can use SQL_CALC_FOUND_ROWS instead of double …->get(‘products’);
It will increase search speed. You should try.
I’ll try, thanks for sharing!