3

I have been working on implementing a search method within codeigniter that uses codeigniters pagination functionality. This required a bit of research up front since we are including filters and a user could select a variable number of filters, throwing off the uri_segment count. I have a working solution below (only posted code that i felt was relative to understanding the process so not to confuse. If I missed anything let me know) that would get someone started if they run across the same issue, but want to ask a few questions:

QUESTIONS:

  1. Is there a better, more efficient way to go about having pagination on filtered search results?

  2. Is there anything anyone would do to improve THIS method?

  3. How could one display the current uri in the user's browser after the initial post? The way the pagination library functions it does not display the 'first_url' until it has been clicked via the generated links. I was tossing around a redirect idea, but wanted to get feedback before going that route.

VIEW

<!-- SEARCH FILTERS -->
<form action="/account/classified/browse" method="post" id="searchForm">

<p>Search
<br/>
<input type="text" name="phrase" id="searchString" value="<?php echo $selectedPhrase; ?>"/></p>

<p>Type<br/>
<?php echo form_dropdown('type', $types, $selectedType); ?>
</p>

<p>County<br/>
<?php echo form_dropdown('location', $locations, $selectedLocation); ?>
</p>

<p>Market<br/>
<?php echo form_dropdown('market', $markets, $selectedMarket); ?>
</p>

<p>
    <input type="submit" id="searchClassifiedButton" name="" value="Search"/>

</p>

</form>
<table>

<?

/*
    Results returned
*/
if (count($classifieds) > 0) {
    foreach ($classifieds as $classified) {
        echo '<tr>';

        //rows returned from query using search filters

        echo '</tr>';
    }
} else {
    echo 'There are no classifieds posted at this time';
}
?>

</table>

CONTROLLER:

<?
public function browse() {
    $this -> load -> helper("url");
    $this -> load -> library("pagination");
    $this -> load -> model('classified_model');
    $post = $this -> input -> post();

    /*
        Here we determine if the post array contains values. If it does, then we know that the
        user has clicked the search button and wishs to view results by different filters.

        If the post array is empty, but the uri segment contains values, this would mean that we
        are viewing listings narrowed by the search filters. 

        If the post array is empty as well as the uri segment, then we are viewing all results
        with no filters applied.
    */
    if ($post) {
        foreach ($post as $key => $val) {
            if ($val != '') {
                $filters[$key] = $val;
            }
        }
    } elseif ($this -> uri -> uri_to_assoc(4)) {
        $filters = $this -> uri -> uri_to_assoc(4);
    } else {
        $filters = array();
    }

    /*
        Here we create the config array for the pagination.

        We assign 'first_url' so that the first generated paginated link will contain the uri filter

        When filters array is not empty we assign 'suffix' so that the uri segment can be appended to the link AFTER the page offest
    */
    $pageConfig = array();
    $pageConfig['first_url'] = !empty($filters) ? '/account/classified/browse/0/' . $this -> uri -> assoc_to_uri($filters) : '/account/classified/browse/0';
    $pageConfig["suffix"] = !empty($filters) ? '/' . $this -> uri -> assoc_to_uri($filters) : '';
    $pageConfig["base_url"] = "/account/classified/browse/";
    $pageConfig["per_page"] = 15;
    $pageConfig["uri_segment"] = 3;
    $pageConfig["total_rows"] = $this -> classified_model -> approved_classifieds_count($filters);


    $this -> pagination -> initialize($pageConfig);


    $page = ($this -> uri -> segment(3)) ? $this -> uri -> segment(3) : 0;


    $data['classifieds'] = $this -> classified_model -> approved_classifieds($filters, $pageConfig["per_page"], $page);
    $data['links'] = $this -> pagination -> create_links();


    //PHRASE
    $data['selectedPhrase'] = (isset($filters['phrase'])) ? $filters['phrase'] : '';

    //TYPES
    $returnTypes = array('' => '-- View All --');
    foreach($this->classified_model->classified_search_types() as $type){
        $returnTypes[$type->id] = $type->name;
    }
    $data['types'] = $returnTypes;
    $data['selectedType'] = (isset($filters['type'])) ? $filters['type'] : '';

    //MARKETS
    $returnMarkets = array('' => '-- View All --');
    foreach($this->classified_model->market_types() as $market){
        $returnMarkets[$market->id] = $market->name;
    }
    $data['markets'] = $returnMarkets;
    $data['selectedMarket'] = (isset($filters['market'])) ? $filters['market'] : '';

    //COUNTIES
    $returnLocations = array('' => '-- View All --');
    foreach($this->classified_model->locations() as $key => $val){
        $returnLocations[$key] = $val;
    }
    $data['locations'] = $returnLocations;
    $data['selectedLocation'] = (isset($filters['location'])) ? $filters['location'] : '';


    //using phil sturgeon's template library
    $this -> template -> build('browse_classified', $data);


}

MODEL:

public function classified_search_types(){
    $q = $this->db->query("SELECT * FROM classified_types");
    return $q->result();
}

public function market_types(){
    $query = $this -> db -> get('market_types');
    return $query -> result();
}

public function locations(){
    $query = $this -> db -> get('locations');
    return $query -> result();
}

public function approved_classifieds_count($filters){
    $result = $this->search($filters);
    return $result->num_rows();
}

public function approved_classifieds($filters, $limit, $start) {
    $result = $this->search($filters, $limit, $start);
    return $result->result();
}

function search($filters, $limit='', $start=''){
    $this->load->helper('security');

    /*
        Obtain values from filters array, set to '' if value not in array
    */
    $phrase = xss_clean((isset($filters['phrase'])) ? $filters['phrase'] : '');
    $type = xss_clean((isset($filters['type'])) ? $filters['type'] : '');
    $market = xss_clean((isset($filters['market'])) ? $filters['market'] : '');
    $location = xss_clean((isset($filters['location'])) ? $filters['location'] : '');


    /*
        QUERY LOGIC
    */


    $q = $this->db->query($query);


    return $q;

}
whitwhoa
  • 2,389
  • 4
  • 30
  • 61
  • You might greatly reduce this code by using DataMapper ORM. You can just do `$object->get_paged()` and add `where_in`, `having`, etc. to the object definition when a POST search is inserted. This way you hardly have to write code and can do very powerful searches with hardly any work. `get_paged` also gives you a nice array with all the settings you need. Even if you need a particular setting it doesn't show; you can just add it yourself. http://datamapper.wanwizard.eu/pages/getalt.html#get_paged. Finally you can put validation (like form validation) inside your DataMapper model. –  Feb 20 '14 at 18:15
  • you might try this http://code.tutsplus.com/tutorials/codeigniter-from-scratch-search-results-without-query-strings--net-18275 – Kyslik Feb 20 '14 at 19:57
  • @Allendar - This is interesting. I've skimmed over the documentation but will have to look a little deeper. If it allows you to write your own query in sql that would be perfect! – whitwhoa Feb 21 '14 at 14:18
  • @Kyslik - I'm not sure I'm sold on creating keys and storing them in a database for something that shouldn't require a call to a database. Interesting work around that appears to work though. – whitwhoa Feb 21 '14 at 14:20
  • @nullReference Yes you can do just that. DataMapper is build fully on top of the native ActiveRecord class. The Search function is probably easier to find content than the menu itself tho ;) –  Feb 21 '14 at 16:42
  • It seems that you are making things a bit complicated and not extensible. My advice is go through ajax pagination on key based searching/filtering/ordering with three groups (input [search field], filters [based on keys] and ordering [based on keys]). I always like active records instead of ORMs, give you better control over queries in favour of optimisations. I'll try cast a tutorial soon about application. Hope this gives you an idea on how to proceed. – YahyaE Apr 09 '17 at 09:38

0 Answers0