Zend Framework Controller Actions with Function Parameters

This guide assumes you already know the basics of the Zend Framework Controller Actions. A typical Controller class with a default Index action may look as follows:

class IndexController extends Zend_Controller_Action {
public function indexAction() {
//get a 'name' param from the request (could be GET or POST, etc.)
$name = $this->getRequest()->getParam($name);

//make this parameter available to the default view for rendering
$this->view->name = $name;
}
}

This is a very simple example of how most actions will function. That is, the action retrieves a number of parameters from the request object, usually performs some logic on these parameters, then sets data to be used by the view. There's nothing wrong with this approach and it works.

But wouldn't it be cleaner if we could define parameter names and default values in the action function signature directly and have these available without needing to manually pull them out of the request object? And wouldn't it be nice if these parameters were immediately made available to the view?

Fortunately there's an easy way to do this. We need to extend the default Zend_Controller_Action class and override the dispatch() function with our own implementation. Then we need to extend from this new class in each of our Controllers and we're done!

So let's get started. First create a new class, say Zend_Controller_Action_With_Params.php (code below). Put this anywhere in your application path and make sure you include/require it before you bootstrap your FrontController.


<?php

/* This is an extension of the default Zend_Controller_Action class which all
* actions inherit from. The extension allows for PHP params in the action
* function signiture, which are automatically retrieved from the GET/POST
* request. This allows for direct access to these params in the action,
* without having to call $this->getRequest()->getParam('param1');
*
* The class is based on code at
* http://devzone.zend.com/article/2855-Actions-now-with-parameters
*/
class Zend_Controller_Action_With_Params extends Zend_Controller_Action {

/* This is more or less a copy paste from the real Zend/Controller/Action::dispatch() function.
* Only difference is we hijack the call to the action function with our own implementation
* that does the request parameter parsing (abstracted in the call_action() function )
*/
public function dispatch($action) {
// Notify helpers of action preDispatch state
$this->_helper->notifyPreDispatch();
$this->preDispatch();
if ($this->getRequest()->isDispatched()) {
if (null === $this->_classMethods) {
$this->_classMethods = get_class_methods($this);
}

// preDispatch() didn't change the action, so we can continue
if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
if ($this->getInvokeArg('useCaseSensitiveActions')) {
trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
}
//$this->$action();
$this->call_action($action);
} else {
//$this->__call($action, array());
$this->call_action($action);
}

$this->postDispatch();
}

// whats actually important here is that this action controller is
// shutting down, regardless of dispatching; notify the helpers of this
// state
$this->_helper->notifyPostDispatch();
}

private function call_action($action) {
//Get all request parameters
$params = $this->_getAllParams();

//Get all action method parameters
$method_params_array = $this->get_action_params($action);

$data = array(); // It will be sent to the action

//build the parameter array
foreach($method_params_array as $param) {
$name = $param->getName();
if($param->isOptional()) { // Check whether the parameter is optional
//If there is no data to send, use the default
$data[$name] = !empty($params[$name])? $params[$name] : $param->getDefaultValue();
} elseif(empty($params[$name])) {
//The parameter cannot be empty as defined
throw new Exception("Parameter '$name' is required.");
} else {
$data[$name] = $params[$name];
}
}

//set the parameters in the view object
$this->view->assign($data);

// Invoke the action and pass the request parameters as actions method parameters, according to their order and names.
call_user_func_array(array($this, $action), $data);
}

private function get_action_params($action) {
$classRef = new ReflectionObject($this);
$className = $classRef->getName();
$funcRef = new ReflectionMethod($className, $action);
$paramsRef = $funcRef->getParameters();
return $paramsRef;
}
}
?>



Now define your IndexController as follows:


<?php
class IndexController extends Zend_Controller_Action_With_Params {
public function indexAction($name = 'John') {

}
}
?>



Notice we have the parameter $name defined directly in our indexAction() signature. Notice also that this has a default value of 'John', which will be used if the parameter is not found in the request. Notice also that we do not need to explicitly set this in the view object, it's done automatically by our extension class.

HOWEVER, the $name parameter is assigned to the view based on the initial function value (i.e. either the default value, or whatever value was passed in the request). So if you change the value within the action function, and want this updated value to be available in the view, you then need to manually call $this->view->name = $name within your action. The variable will not be automatically updated otherwise.

Comments

Popular posts from this blog

Wkhtmltopdf font and sizing issues

Import Google Contacts to Nokia PC Suite

Can't delete last blank page from Word