CodeIgniter pagination with multiple unlimited searching criteria
Undoubtedly, pagination is one of the most usefull CodeIgniter features. But this feature has lack of flexibility. Page number usualy put in a segment of a URI. So, if we use non-fixed query criteria, the URI segment number will change. It still can work this way, but surely too many conditions.
In this article i will show you how to trick it.
Imagine we have a car search page. The query criteria are `brand`, `year`, `style`, `start-price-range`, `stop-price-range`.
Original URI will be like this :
http://localhost:80/car/search/Toyota/2005/SUV/50000/85000/1
class_name : car
method_name : search
brand : Toyota
year : 2005
style : SUV
start-price-range : 50000
stop-price-range : 85000
page_number : 1
In that URI, page number is in uri_segment(8). But what if we don’t care about the brand and the style, the uri_segment for page_number will change and it is quite difficult to determine what criteria will be ignored.
Off course we still can make it work by put default value for ignored criteria, example :
http://localhost:80/car/search/unset/2005/unset/50000/85000/1
class_name : car
method_name : search
brand : unset -> don’t bother use it in query
year : 2005
style : unset -> don’t bother use it in query
start-price-range : 50000
stop-price-range : 85000
page_number : 1
This will work, but i will offer you a better way.
I will use this URI.
http://localhost:80/car/search/brand_Toyota__year_2005__style_SUV__start-price-range_50000__stop-price-range_85000/1
class_name : car
method_name : search
criteria : brand_Toyota__year_2005__style_SUV__start-price-range_50000__stop-price-range_85000
page_number : 1
In that URI page number is in uri_segment(4), and will allways in uri_segment(4) no matter how many criteria i added. Or i can ignored all criteria by using this URI
http://localhost:80/car/search/all/1
What we need is just to parse the criteria. Criteria to criteria separated by `__` and criteria to criteria-value separated by `_`. Here is the parsing function, you can put it in a helper or in a `car` controller itself.
<?php
function parsing_criteria($pairs){
$criteria = array();
if($pairs!=’all’){
$pairs = explode("__",$pairs);
foreach($pairs as $row){
$array_row = explode("_",$row);
$criteria[$array_row[0]] = $array_row[1];
}
}
return $criteria;
}?>
If you parse `pairs of criteria` above with function `parsing_criteria` will results an array below
Array
(
[brand] => Toyota
[year] => 2005
[style] => SUV
[start-price-range] => 50000
[stop-price-range] => 85000
)
The `search` method in the `car` class will look like this
<?php
—
// others methods
—
function search($criteria=’all’){
$this->load->library(‘pagination’);
$this->load->helper(‘car’); /*i put function parsing_criteria here*/
–
–
–
$pagination_per_page = 10;
$pagination_uri_segment = 4;
$pagination_pageno = $this->uri->segment(4)==” ? 1 : $this->uri->segment(4);/* i put parsing_criteria in a helper
$option will contain array of criteria*/
$option = parsing_criteria($criteria);/* add `start` and `count` to $option array for the sql query*/
$option['start'] = $pagination_pageno – 1;
$option['count'] = $pagination_per_page;
$config = array(
‘base_url’ => ‘/car/search/’ . $criteria . "/",
/* call some model using $option (array) to be used in sql query */
‘total_rows’ => $this->car_model->count_car($option),
‘per_page’ => $pagination_per_page,
‘uri_segment’=> $pagination_uri_segment
);
$this->pagination->initialize($config);/* call some model using $option (array) to be used in sql query */
$data['car'] = $this->car_model->search_car($option));$data['pagination_links'] = $this->pagination->create_links();
–
–
–
}
—
// others methods
—?>
By using this trick I can use multiple and unlimited criteria. Oops, off course it is limited, because HTTP $_GET has limitation too.
Hope you not having difficulty to understand my english, since I have. Happy coding
Hi…
It looks that your method is really excellent.
Could you please drop me a simple sample of the view page containing the searching fields?
I’m new in CodeIgniter and start loving this framework.
Regards,
moxerian
Hi moxerian, i have an answer for you in my comment bellow, sorry for super late respond
Good writing here I really really like the way you write your blogs. I will continue to visit your site in the future to read more great blog posts like this one! This is an awesome post here. love on web fighters :)
wow I realistically just like your current webpage maintain for keep method which are details I definitely should pop in a lot of another stage to read via some choice extra thanks.
Excellent article, plenty of good quality info. I am going to point out to my friend and ask them the things they think.
Thank you very much for this excellent method. It solved my problem :)
this is my view page form;
‘input_name’,
‘value’ => ”,
);
echo form_open(base_url().’search_class_name/search_method_name/’);
echo form_input($search_input);
echo form_submit($submit);
echo form_close();
?>
Hi , was just moving through the net looking for some information and came to your post. I am fascinated by the info that you write on this site. It shows how well you understand this topic. Bookmarked this page, will be back for more. You, my friend, Rock!!!
Hi admin! I have a tiny request. I was just searching for some information on this topic and found this post. Some really awesome stuff you wrote here, can I please link to this post on my new website I am currently workin on? It would be great:) . I will check back again later to see how you responded. Thanks, David Wilson .
Answer:
Sure, no problem.
Hi,
thanks for the excellent method, I’ve been search for this topic for a while.
and I have the same question with moxerian, is how the view page use submit to generate criteria string, can u explain this? thanks again!
regards,
Jack
ps: forgive my poor english
Hi Jack, i have an answer for you in my comment bellow
YOU ROCK! Thanks for the idea.
Answer for moxerian and jack
there are 2 way to generate that criteria URI
1. Use javascript, you can generate the uri on search button onclick, the URI depend on form fields value.
2. Use pre-search page, set action of the search form (in view) to a pre-search page, let name it ‘go’ with POST method. This page/CI-method generate the URI and go to it. You can see example bellow.
THE CONTROLLER :
class Car extends Controller { function Car(){ parent::Controller(); } function go(){ // here is pre-search page to generate the criteria $part = array(); foreach(array_keys($_POST) as $key){ // loop all form field $value = trim($this->input->post($key)); if($value!='' and $key!='smt'){ // collect all form field but submit button $part[] = $key . "_" . $value; } } $criteria = implode("__", $part); // join it header('location: /car/search/' . $criteria); // you can go now :) } function form(){ $this->load->view('form'); // call search form view } function search($criteria='all'){ echo $criteria; // searching process -as the article- here } }THE VIEW :
Hi Xamu,
Very nice post, thanks a lot. I was wondering how you’d build your method. Do you have an structure like:
isset($aData['brand']) {
// extend current query
// join brand table..
}
isset($aData['year']) {
// extend current query
// join brand table..
}
etc.?
Looking forward to your reaction!
Best regards,
Raymond
Yes Raymond, just like that.
But i make it even lazier :P, i create all the join with the left join, and i create/generate the WHERE clause using that $option criteria like this
function __generate_where($option = array()){
$where = ”;
if(isset($option['keyword'])){
$where .= ” AND c.name LIKE ‘%”.$option['keyword'].”%’”;
}
if(isset($option['brand'])){
$where .= ” AND c.brand_id=” . $option['brand'];
}
if(isset($option['year'])){
$where .= ” AND c.year=” . $option['year'];
}
if(isset($option['category'])){
$where .= ” AND c.category_id=” . $option['category'];
}
if(isset($option['model'])){
$where .= ” AND c.model_id=” . $option['model'];
}
if(isset($option['price_a'])){
$where .= ” AND c.price_on>=” . $option['price_a'];
}
if(isset($option['price_b'])){
$where .= ” AND c.price_on< =" . $option['price_b'];
}
if(isset($option['rating'])){
$where .= " AND c.rating>=” . $option['rating'];
}
return $where;
}
Best Regards,
Xamu
Hi Xamu, Thank you for this great idea!!
Just a small request if you are not to busy.
After i submit the form the search method loads with criteria. so far so good. But if go to the page 2 using search criteria the search form loses what it submit in the first page. What i should do in order to keep tha values i search for across the pagination?
Thanks
Answer for Dionisis:
Hi Dionisis,
You should set pagination config['base_url'] to ‘/your-class-name/your-method-name/’ . $criteria.
Variable $criteria is the argument for this page method (in the example search method). So your search form task is only to generate the right URI for the page, and the pagination will follow the URI.
For example i use method ‘go’ as the form listener/receiver and to create the right URI.
< ?php
function go(){
$keyword = $this->input->post(‘keyword’);
$brand = $this->input->post(‘brand’);
$model = $this->input->post(‘model’);
$criteria = ”;
$criteria = $brand!=” ? $criteria . “__brand_” . $brand : $criteria;
$criteria = $model!=” ? $criteria . “__model_” . $model : $criteria;
$criteria = $keyword!=” ? $criteria . “__keyword_” . $keyword : $criteria;
$criteria = $criteria==”? ‘all’ : substr($criteria,2);
header(“location: /car/search/$criteria/”);
}
?>
A very nice solution! I would like to ask if is also possible to add in the same manner the option of ordering some fields (in the view at the display…to order after the head of table) ASC / DESC .
Thanks,