In my leedsphp talk last week I mentioned making a developer (and consumers) life easier by automatically implementing the allow methods functionality that your API may expose (e.g. you call PUT on a URL that only allows GET or POST). I did have an example slide there showing how to implement but I thought I’d posted a bare bones controller here that shows how it works.
abstract class ApiController extends Zend_Rest_Controller
{
/**
* Default head action.
*
* @internal
* @return void
*/
public function headAction()
{
ob_start();
$this->getAction();
ob_get_clean();
}
/**
* Default get action.
*
* @internal
* @return void
*/
public function getAction()
{
$this->_showAllowedMethods();
}
/**
* Default post action.
*
* @internal
* @return void
*/
public function postAction()
{
$this->_showAllowedMethods();
}
/**
* Default put action.
*
* @internal
* @return void
*/
public function putAction()
{
$this->_showAllowedMethods();
}
/**
* Default delete action.
*
* @internal
* @return void
*/
public function deleteAction()
{
$this->_showAllowedMethods();
}
/**
* Allowed methods output.
*
* @internal
* @return void
*/
private function _showAllowedMethods()
{
$methods = $this->implementedMethods();
$methods = implode(',', $methods);
$methods = strtoupper($methods);
$this->_response->setHeader('Allow', $methods);
$this->_forward('method-not-allowed', 'error', 'default'); # I have a methodNotAllowedAction on my ErrorController
# just for clarity - it does nothing other than headers
}
/**
* Direct call to get implemented methods
*
* @internal
* @return array
*/
public function implementedMethods()
{
if(!isset($this->_actionController))
return array();
$class = get_class($this->_actionController);
$oReflector = new ReflectionClass($class);
$methods = $oReflector->getMethods(ReflectionMethod::IS_PUBLIC);
$implementedMethods = array();
foreach($methods as $i => $method) /* @var $method ReflectionMethod */
{
if($method->getDeclaringClass()->getName() == $class)
$implementedMethods[] = str_replace('Action', '', $method->getName());
}
return array_intersect($implementedMethods, array('get', 'put', 'post', 'delete', 'head', 'options', 'trace'));
}
}
If you extend this controller for all your actions, you’ll get automated Allow headers every time someone calls a URL that does not implement their request type.
As I said in my talk, be sure to use an op-code cache so reflection doesn’t become your bottleneck!
Also I should mention, this code lives in my ApiController and not in an action helper or similar due to Zend Framework’s performance hit as a result of using magic methods.

