Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Created June 15, 2012 18:49
Show Gist options
  • Save mindplay-dk/2938142 to your computer and use it in GitHub Desktop.
Save mindplay-dk/2938142 to your computer and use it in GitHub Desktop.
Extending CController with support for action-method argument resolvers.
<?php
class Controller extends CController
{
/**
* @var array A stack of action-method arguments resolved by calls to resolve() from beforeAction().
*/
protected $resolved = array();
/**
* Resolves parameter-names (e.g. $_GET[] variables) as action-method arguments.
*
* Call this from within your Controller's beforeAction() method, typically to convert IDs to objects.
*
* @param string $param_name name of the input $_GET[] variable to resolve - typically something that ends in "_id".
* @param string $argument_name the name of the resolved action-method argument; defaults to $param_name without the "_id" suffix.
* @param string|array|callable $fn a Controller method-name, an anonymous function/closure, or a callback-array.
* @throws CException if the specified resolver-function could not be called.
*/
protected function resolve($param_name, $argument_name=null, $fn=null)
{
if (!array_key_exists($param_name, $_GET)) {
return; // no $_GET[] variable input - nothing to resolve.
}
if ($argument_name === null) {
// Establish argument-name based on parameter-name - e.g. "document" for "document_id"
if (substr_compare($param_name, '_id', -3) === 0) {
$argument_name = substr($param_name, 0, -3);
} else {
throw new CException("argument-name could not be inferred from parameter-name"
. " - use parameter-names ending in '_id', or specify the argument-name");
}
}
if ($fn === null) {
// Establish method-name based on parameter-name, e.g. resolveDocumentId() for "document_id".
$fn = 'resolve' . str_replace(' ', '', ucwords(str_replace('_', ' ', $param_name)));
}
$callback = $fn;
if (is_string($callback)) {
// Assume a method-name:
$callback = array($this, $fn);
}
if (is_callable($callback) === false) {
throw new CException("invalid resolver function: ".print_r($fn, true));
}
$this->resolved[ count($this->resolved)-1 ][$argument_name] = call_user_func($callback, $_GET[$param_name]);
}
/**
* Runs the action after passing through all filters.
*
* @param CAction $action action to run
*/
public function runAction($action)
{
$this->resolved[] = array();
parent::runAction($action);
array_pop($this->resolved);
}
/**
* Returns the request parameters that will be used for action parameter binding.
*
* @return array the request parameters to be used for action parameter binding.
* @throws CException for internal errors only.
*/
public function getActionParams()
{
$resolved = end($this->resolved);
if (!is_array($resolved)) {
throw new CException("internal error: resolve() should be called from inside your beforeAction() method only");
}
return array_merge($_GET, $resolved);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment