2
votes

I am trying to build in a "search" box on a results page in my cakephp app. The page uses the cakePHP pagination component to show and "page" results. This is perfect, but I am having difficulties to get the next part to work.

The desired outcome:

  1. A cakephp form (post) with an input box and a couple of select boxes, including a date selector so that I can select between dates. The user should be able to populate these fields and submit
  2. On submit, the user selection should change the cakePHP pagination conditions in the controller
  3. In the view I want the pagination bar to keep record of the user selection, so that when I filter through different pages, it keeps the users search. I understand this can be achieved using $this->passedArgs, hence why I am using post and not get.

The code:

 // Form:
 <?php 
      echo $this->Form->create('search', array('class' => false));
           echo $this->Form->input('searchFor');
           echo $this->Form->input('dateFrom');
           echo $this->Form->input('dateTo');
      echo $this->Form->end(); 
 ?>

 // Controller:
 if($this->request->is("post")) {
      $filters = $this->request->data["search"];
      $this->passedArgs["searchFor"] = $filters["searchFor"];
      $this->passedArgs["dateFrom"] = $filters["dateFrom"]." 00:00:00";
      $this->passedArgs["dateTo"] = $filters["dateTo"]." 00:00:00";


      // Assign search parameters:
      if($this->passedArgs["searchFor"] != "") {
           $conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
      }

      $conditions["Model.created >="] = $this->passedArgs["dateFrom"];
      $conditions["Model.created <="] = $this->passedArgs["dateTo"];


 } else {
      $conditions = array("Result.status_id >=" => 12);
 }

 $this->paginate = array(
     'conditions' => $conditions,
     'order' => array('Result.created ASC'),
     'limit' => 20
 );

 $this->set("results",$this->paginate("Model");


 // The view file:
 <?php
      $this->Paginator->options(array('url' => $this->passedArgs));
 ?>

Where I am now:

  1. The initial page loads with all of the results
  2. When I populate the search boxes it does return my results

The problem:

  1. I am convinced the way I am doing it is incorrect as I now need to do 2 checks, a) being if results has been posted and b) check if there is passedArgs available. I am 100% convinced this is not the right way of doing it.
  2. Let's say I have 2 free form fields for search, say name and surname, if I leave surname blank my url would be written as below, and this does not look or appear to be correct. That means I have to assign default values to ensure the items below does not happen, which does not appear to be very dynamic.

    http://localhost/site/controller/action/surname:0/name:John/date:0/

  3. On refresh it says the page does not exist because the posted values is not available anylonger.
2

2 Answers

6
votes

usually I proceed like this in the controller:

//transform POST into GET
if($this->request->is("post")) {
    $url = array('action'=>'index');
    $filters = array();

    if(isset($this->data['searchFor']) && $this->data['searchFor']){
        //maybe clean up user input here??? or urlencode??
        $filters['searchFor'] = $this->data['searchFor'];
    }
    //redirect user to the index page including the selected filters
    $this->redirect(array_merge($url,$filters)); 
}

$conditions = array();
//check filters on passedArgs
if(isset($this->passedArgs["searchFor"])){
    $conditions["Model.field LIKE"] = "%".$this->passedArgs["searchFor"]."%";
}

//paginate as normal
$this->paginate = array(
     'conditions' => $conditions,
     'order' => array('Result.created ASC'),
     'limit' => 20
 );

The idea is to transform the POST sent by your form into GET. so you wont have problems with the paginator nor the refresh

Hope this helps

1
votes

What you want can be done a lot more simple and DRY by using this search plugin.

It automates what you want more or less plus it already can do more than your code.

So I suggest you to use the plugin directly or take a look at it how it does the trick. :)