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.