diff --git a/framework/yii/web/UrlManager.php b/framework/yii/web/UrlManager.php index 47f5c5d..44c63c5 100644 --- a/framework/yii/web/UrlManager.php +++ b/framework/yii/web/UrlManager.php @@ -43,6 +43,31 @@ class UrlManager extends Component * array, one can use the key to represent the pattern and the value the corresponding route. * For example, `'post/' => 'post/view'`. * + * For RESTful routing the mentioned shortcut format also allows you to specify the + * [[UrlRule::verb|HTTP verb]] that the rule should apply for. + * You can do that by prepending it to the pattern, separated by space. + * For example, `'PUT post/' => 'post/update'`. + * You may specify multiple verbs by separating them with comma + * like this: `'POST,PUT post/index' => 'post/create'`. + * The supported verbs in the shortcut format are: GET, HEAD, POST, PUT and DELETE. + * Note that [[UrlRule::mode|mode]] will be set to PARSING_ONLY when specifying verb in this way + * so you normally would not specify a verb for normal GET request. + * + * Here is an example configuration for RESTful CRUD controller: + * + * ~~~php + * array( + * 'dashboard' => 'site/index', + * + * 'POST s' => '/create', + * 's' => '/index', + * + * 'PUT /' => '/update', + * 'DELETE /' => '/delete', + * '/' => '/view', + * ); + * ~~~ + * * Note that if you modify this property after the UrlManager object is created, make sure * you populate the array with rule objects instead of rule configurations. */ @@ -115,9 +140,14 @@ class UrlManager extends Component foreach ($this->rules as $key => $rule) { if (!is_array($rule)) { $rule = array( - 'pattern' => $key, 'route' => $rule, ); + if (preg_match('/^((?:(GET|HEAD|POST|PUT|DELETE),)*(GET|HEAD|POST|PUT|DELETE))\s+(.*)$/', $key, $matches)) { + $rule['verb'] = explode(',', $matches[1]); + $rule['mode'] = UrlRule::PARSING_ONLY; + $key = $matches[4]; + } + $rule['pattern'] = $key; } $rules[] = Yii::createObject(array_merge($this->ruleConfig, $rule)); } diff --git a/tests/unit/TestCase.php b/tests/unit/TestCase.php index 479f85d..efcedf0 100644 --- a/tests/unit/TestCase.php +++ b/tests/unit/TestCase.php @@ -38,14 +38,13 @@ abstract class TestCase extends \yii\test\TestCase * The application will be destroyed on tearDown() automatically. * @param array $config The application configuration, if needed */ - protected function mockApplication($config=array()) + protected function mockApplication($config = array(), $appClass = '\yii\console\Application') { static $defaultConfig = array( 'id' => 'testapp', 'basePath' => __DIR__, ); - $appClass = $this->getParam( 'appClass', '\yii\web\Application' ); new $appClass(array_merge($defaultConfig,$config)); } diff --git a/tests/unit/data/config.php b/tests/unit/data/config.php index 88c8127..a2cc445 100644 --- a/tests/unit/data/config.php +++ b/tests/unit/data/config.php @@ -1,8 +1,6 @@ '\yii\web\Application', - 'appClass' => '\yii\console\Application', 'databases' => array( 'mysql' => array( 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', diff --git a/tests/unit/framework/web/UrlManagerTest.php b/tests/unit/framework/web/UrlManagerTest.php index 0f08790..7da8f34 100644 --- a/tests/unit/framework/web/UrlManagerTest.php +++ b/tests/unit/framework/web/UrlManagerTest.php @@ -248,4 +248,58 @@ class UrlManagerTest extends TestCase $result = $manager->parseRequest($request); $this->assertFalse($result); } + + public function testParseRESTRequest() + { + $manager = new UrlManager(array( + 'cache' => null, + )); + $request = new Request; + + // pretty URL rules + $manager = new UrlManager(array( + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => array( + 'PUT,POST post//' => 'post/create', + 'DELETE post/<id>' => 'post/delete', + 'post/<id>/<title>' => 'post/view', + 'POST/GET' => 'post/get', + ), + )); + // matching pathinfo GET request + $_SERVER['REQUEST_METHOD'] = 'GET'; + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(array('post/view', array('id' => '123', 'title' => 'this+is+sample')), $result); + // matching pathinfo PUT/POST request + $_SERVER['REQUEST_METHOD'] = 'PUT'; + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(array('post/create', array('id' => '123', 'title' => 'this+is+sample')), $result); + $_SERVER['REQUEST_METHOD'] = 'POST'; + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(array('post/create', array('id' => '123', 'title' => 'this+is+sample')), $result); + + // no wrong matching + $_SERVER['REQUEST_METHOD'] = 'POST'; + $request->pathInfo = 'POST/GET'; + $result = $manager->parseRequest($request); + $this->assertEquals(array('post/get', array()), $result); + + // createUrl should ignore REST rules + $this->mockApplication(array( + 'components' => array( + 'request' => array( + 'hostInfo' => 'http://localhost/', + 'baseUrl' => '/app' + ) + ) + ), \yii\web\Application::className()); + $this->assertEquals('/app/post/delete?id=123', $manager->createUrl('post/delete', array('id' => 123))); + $this->destroyApplication(); + + unset($_SERVER['REQUEST_METHOD']); + } }