Proxy Search - Doing a search while using named parameters
Tuesday, March 31st 2009, 12:53am
Topics: Tutorials, CakePHP
Tags: CakePHP, Named, Params, Proxy, Search
Comments: 0
Permalink -
Tinylink
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.
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()).
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.
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.
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!
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
*/
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
*/
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
*/
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
*/
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!
No Comments