While working on a project of mine, I wanted to be able to do a search, but have the post data be retained as named parameters (basically like a $_GET string). My first attempt was setting the form method to get, and trying to convert the $_GET by doing some mod_rewrite magic. This didn't work out at all, mainly because I couldn't get it to work for multiple named parameters. The only alternative I found was suggested by someone in the Google groups; they suggested posting a form to another action to deal with the logic, and finally redirect applying named parameters. This works perfectly, albeit adding an extra step in the process.
The process I created is something id like to call a Proxy Search. The following code should be placed in your app_controller.php file, so that it can be used as a global search by all controllers. You should not overwrite the proxy() action, unless you want specific logic in a certain controller.
/**
* Sorts the named params for a posted page
* @param string $model
* @access public
*/
public function proxy($model) {
$data = array_map('urlencode', $this->data[Inflector::camelize($model)]);
$referer = explode('/', trim($this->referer(), '/'));
$router = array_merge(array('controller' => $referer[0], 'action' => $referer[1]), $data);
$this->redirect($router);
}
/**
* Applies the named params to the controller data
* @return array
*/
public function _proxyGather() {
return array_map('urldecode', $this->params['named']);
}
I will quickly try to explain how the form works. For example, if we are in the Users controller and want to do a search using the search() action, the forms url should point to /users/proxy/user instead of /users/search. Now shouldn't it be /users/proxy you ask? Well no, we need to know what model should be used in $data, so we need to pass an argument for the model that is used for the form (during $form->create()).
// UsersController::search()
echo $form->create('User', array('url' => array('controller' => 'users', 'action' => 'proxy', 'user')));
// If searching through books
echo $form->create('Book', array('url' => array('controller' => 'books', 'action' => 'proxy', 'book')));
Now back in the search() action, we need to grab the named params and pass them to the fields in the form. We do this by using the _proxyGather() method. No model name needs to be passed to _proxyGather(), simply because the data is pulled from the controller.
/**
* Search players
* @access public
*/
public function search() {
$this->data['User'] = $this->_proxyGather();
$this->pageTitle = 'Search Users';
$this->set('results', $this->paginate('User'));
}
You can also have this interact with pagination quite easily. All you need to do is add some conditional logic in the controller, and pass the data to paginator.
/**
* Search players
* @access public
*/
public function search() {
$this->data['User'] = $this->_proxyGather();
if (!empty($this->data['User']['username'])) {
$this->paginate['User']['conditions']['User.username LIKE'] = '%'. $this->data['User']['username'] .'%';
}
if (!empty($this->data['User']['firstName'])) {
$this->paginate['User']['conditions']['User.firstName LIKE'] = '%'. $this->data['User']['firstName'] .'%';
}
$this->pageTitle = 'Search Users';
$this->set('results', $this->paginate('User'));
}
// In the views using $paginator
$paginator->options(array('url' => $this->passedArgs));
I hope this has been helpful to someone who was looking to do a search system using named params, I know I had fun building it! I was thinking of turning this into a component, but have not figured out a way to do so yet, enjoy anyways!