###What was expected:###
I expected lithium add REST support to router.
it may like this:
{{{
Router::connect('/articles.{:type}', array('controller' => 'articles', 'action' => 'show') ,'get');
Router::connect('/articles/{:id:[0-9]+}.{:type}', array('controller' => 'articles', 'action' => 'edit') ,'get');
Router::connect('/articles.{:type}', array('controller' => 'articles', 'action' => 'create') ,'post');
Router::connect('/articles/{:id:[0-9]+}.{:type}', array('controller' => 'articles', 'action' => 'update') ,'put');
Router::connect('/articles/{:id:[0-9]+}.{:type}', array('controller' => 'articles', 'action' => 'destroy') ,'delete');
}}}
###My solution:###
I have modify Router and Route class in my libraies to support this.
in **lithium/http/Router.php**
{{{
public static function connect($template, $params = array(), $method = 'get', $options = array()) {
if ($template === null) {
return static::__init();
}
if (!is_object($template)) {
$params + array('action' => 'index');
$class = static::$_classes['route'];
$template = new $class(compact('template', 'params', 'method', 'options'));
}
return (static::$_configuration[] = $template);
}
}}}
then in **lithium/http/Route.php**
{{{
class Route extends \lithium\core\Object {
protected $_method = array();
protected $_autoConfig = array(
'template', 'pattern', 'keys', 'params', 'match', 'defaults', 'subPatterns' , 'method'
);
public function __construct($config = array()) {
$defaults = array(
'params' => array(),
'template' => '/',
'pattern' => '^[\/]*$',
'match' => array(),
'defaults' => array(),
'keys' => array(),
'method' => 'get',
'options' => array()
);
parent::__construct((array) $config + $defaults);
}
public function parse($request) {
if ($request instanceof \lithium\action\Request ){
if(!$request->is($this->_method)){
return false;
}
} elseif ($request instanceof \lithium\http\Request ){
if(strcasecmp($request->method,$this->_method)!=0){
return false;
}
}
$url = '/' . trim($request->url, '/');
if (preg_match($this->_pattern, $url, $match)) {
$match['args'] = isset($match['args']) ? explode('/', $match['args']) : array();
$result = array_intersect_key($match, $this->_keys) + $this->_params + $this->_defaults;
$result['action'] = $result['action'] ?: 'index';
return $result;
}
return false;
}
public function export() {
$result = array();
$keys = array('template', 'pattern', 'keys', 'params', 'match', 'method', 'defaults', 'subPatterns');
foreach ($keys as $key) {
$result[$key] = $this->{'_' . $key};
}
return $result;
}
}}}
###Finally,i add some test case.###
tests/http/RouteTest.php
{{{
public function testRouteParsingWithMethod() {
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles.xml'
));
$route = new Route(array(
'template' => '/articles.{:type}',
'params' => array('controller' => 'articles', 'action' => 'show'),
'method' => 'get'
));
$result = $route->parse($request);
$this->assertEqual(array('controller' => 'articles', 'action' => 'show', 'type' => 'xml'), $result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'POST'),
'url' => '/articles.xml'
));
$result = $route->parse($request);
$this->assertFalse($result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles/1.xml'
));
$route = new Route(array(
'template' => '/articles/{:id:\d+}.{:type}',
'params' => array('controller' => 'articles', 'action' => 'edit'),
'method' => 'get'
));
$result = $route->parse($request);
$this->assertEqual(array('controller' => 'articles', 'action' => 'edit', 'id' => '1', 'type' => 'xml'), $result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'POST'),
'url' => '/articles/1.xml'
));
$result = $route->parse($request);
$this->assertFalse($result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'POST'),
'url' => '/articles.xml'
));
$route = new Route(array(
'template' => '/articles.{:type}',
'params' => array('controller' => 'articles', 'action' => 'create'),
'method' => 'post'
));
$result = $route->parse($request);
$this->assertEqual(array('controller' => 'articles', 'action' => 'create', 'type' => 'xml'), $result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles'
));
$result = $route->parse($request);
$this->assertFalse($result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'PUT'),
'url' => '/articles/1.xml'
));
$route = new Route(array(
'template' => '/articles/{:id:\d+}.{:type}',
'params' => array('controller' => 'articles', 'action' => 'update'),
'method' => 'put'
));
$result = $route->parse($request);
$this->assertEqual(array('controller' => 'articles', 'action' => 'update', 'id' => '1', 'type' => 'xml'), $result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles/1.xml'
));
$result = $route->parse($request);
$this->assertFalse($result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'DELETE'),
'url' => '/articles/1.xml'
));
$route = new Route(array(
'template' => '/articles/{:id:\d+}.{:type}',
'params' => array('controller' => 'articles', 'action' => 'destroy'),
'method' => 'delete'
));
$result = $route->parse($request);
$this->assertEqual(array('controller' => 'articles', 'action' => 'destroy', 'id' => '1', 'type' => 'xml'), $result);
$request = new \lithium\action\Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles/1.xml'
));
$result = $route->parse($request);
$this->assertFalse($result);
}
}}}
tests/http/RouterTest.php
{{{
public function testRouteConnectionWithDefaultMethod() {
$result = Router::connect('/{:controller}/{:action}');
$expected = array(
'template' => '/{:controller}/{:action}',
'pattern' => '@^(?:/(?P<controller>[^\\/]+))(?:/(?P<action>[^\\/]+)?)?$@',
'params' => array('action' => 'index'),
'match' => array(),
'defaults' => array('action' => 'index'),
'keys' => array('controller' => 'controller', 'action' => 'action'),
'subPatterns' => array(),
'method' => 'get'
);
$this->assertEqual($expected, $result->export());
}
public function testRouteConnectionWithMethod() {
$result = Router::connect('/articles.{:type}', array('controller' => 'articles', 'action' => 'show') ,'get');
$expected = array(
'template' => '/articles.{:type}',
'pattern' => '@^/articles\.(?P<type>[^\/]+)$@',
'params' => array('controller' => 'articles', 'action' => 'show'),
'match' => array('controller' => 'articles', 'action' => 'show'),
'defaults' => array(),
'keys' => array('type' => 'type'),
'subPatterns' => array(),
'method' => 'get'
);
$this->assertEqual($expected, $result->export());
$result = Router::connect('/articles/{:id}.{:type}', array('controller' => 'articles', 'action' => 'edit') ,'get');
$expected = array(
'template' => '/articles/{:id}.{:type}',
'pattern' => '@^/articles(?:/(?P<id>[^\/]+))\.(?P<type>[^\/]+)$@',
'params' => array('controller' => 'articles', 'action' => 'edit'),
'match' => array('controller' => 'articles', 'action' => 'edit'),
'defaults' => array(),
'keys' => array('id' => 'id', 'type' => 'type'),
'subPatterns' => array(),
'method' => 'get'
);
$this->assertEqual($expected, $result->export());
$result = Router::connect('/articles.{:type}', array('controller' => 'articles', 'action' => 'create') ,'post');
$expected = array(
'template' => '/articles.{:type}',
'pattern' => '@^/articles\.(?P<type>[^\/]+)$@',
'params' => array('controller' => 'articles', 'action' => 'create'),
'match' => array('controller' => 'articles', 'action' => 'create'),
'defaults' => array(),
'keys' => array('type' => 'type'),
'subPatterns' => array(),
'method' => 'post'
);
$this->assertEqual($expected, $result->export());
$result = Router::connect('/articles/{:id}.{:type}', array('controller' => 'articles', 'action' => 'update') ,'put');
$expected = array(
'template' => '/articles/{:id}.{:type}',
'pattern' => '@^/articles(?:/(?P<id>[^\/]+))\.(?P<type>[^\/]+)$@',
'params' => array('controller' => 'articles', 'action' => 'update'),
'match' => array('controller' => 'articles', 'action' => 'update'),
'defaults' => array(),
'keys' => array('id' => 'id', 'type' => 'type'),
'subPatterns' => array(),
'method' => 'put'
);
$this->assertEqual($expected, $result->export());
$result = Router::connect('/articles/{:id}.{:type}', array('controller' => 'articles', 'action' => 'destroy') ,'delete');
$expected = array(
'template' => '/articles/{:id}.{:type}',
'pattern' => '@^/articles(?:/(?P<id>[^\/]+))\.(?P<type>[^\/]+)$@',
'params' => array('controller' => 'articles', 'action' => 'destroy'),
'match' => array('controller' => 'articles', 'action' => 'destroy'),
'defaults' => array(),
'keys' => array('id' => 'id', 'type' => 'type'),
'subPatterns' => array(),
'method' => 'delete'
);
$this->assertEqual($expected, $result->export());
}
public function testRouteMatchingWithMethod() {
Router::connect('/articles.{:type}', array('controller' => 'articles', 'action' => 'show') ,'get');
Router::connect('/articles/{:id}.{:type}', array('controller' => 'articles', 'action' => 'edit') ,'get');
Router::connect('/articles.{:type}', array('controller' => 'articles', 'action' => 'create') ,'post');
Router::connect('/articles/{:id}.{:type}', array('controller' => 'articles', 'action' => 'update') ,'put');
Router::connect('/articles/{:id}.{:type}', array('controller' => 'articles', 'action' => 'destroy') ,'delete');
$request = new Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles.xml')
);
$result = Router::parse($request);
$expected = array('controller' => 'articles', 'action' => 'show', 'type' => 'xml');
$this->assertEqual($expected, $result);
$request = new Request(array(
'env' => array('REQUEST_METHOD' => 'GET'),
'url' => '/articles/1.xml')
);
$result = Router::parse($request);
$expected = array('controller' => 'articles', 'action' => 'edit', 'id' => '1', 'type' => 'xml');
$this->assertEqual($expected, $result);
$request = new Request(array(
'env' => array('REQUEST_METHOD' => 'POST'),
'url' => '/articles.xml')
);
$result = Router::parse($request);
$expected = array('controller' => 'articles', 'action' => 'create', 'type' => 'xml');
$this->assertEqual($expected, $result);
$request = new Request(array(
'env' => array('REQUEST_METHOD' => 'PUT'),
'url' => '/articles/1.xml')
);
$result = Router::parse($request);
$expected = array('controller' => 'articles', 'action' => 'update', 'id' => '1', 'type' => 'xml');
$this->assertEqual($expected, $result);
$request = new Request(array(
'env' => array('REQUEST_METHOD' => 'DELETE'),
'url' => '/articles/1.xml')
);
$result = Router::parse($request);
$expected = array('controller' => 'articles', 'action' => 'destroy', 'id' => '1', 'type' => 'xml');
$this->assertEqual($expected, $result);
}
}}}
Sorry for my poor english.
Hi kaptin, thanks for your hard work on this patch. It is now possible to create routes based on HTTP methods and verbs using the following syntax: {{{ Router::connect('/{:controller}/{:id:[0-9]+}', array('http:method' => 'PUT', 'action' => 'edit')); }}} For right now we feel that this is sufficient, but we're holding this ticket for a future release, when a higher-level resources API can be decided on. Thanks again for your efforts.