You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
437 lines
16 KiB
437 lines
16 KiB
<?php |
|
/** |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
*/ |
|
|
|
namespace yiiunit\framework\web; |
|
|
|
use yii\caching\ArrayCache; |
|
use yii\web\Request; |
|
use yii\web\UrlManager; |
|
use yiiunit\TestCase; |
|
|
|
/** |
|
* This class implements the tests for URL parsing with "pretty" url format. |
|
* |
|
* See [[UrlManagerTest]] for tests with "default" URL format. |
|
* See [[UrlManagerCreateUrlTest]] for url creation with "pretty" URL format. |
|
* |
|
* Behavior of UrlManager::parseRequest() for the "pretty" URL format varies among the following options: |
|
* - strict parsing = true / false |
|
* - rules format |
|
* - key => value |
|
* - array config |
|
* |
|
* The following features are tested: |
|
* - named parameters |
|
* - as query params |
|
* - as controller/actions '<controller:(post|comment)>/<id:\d+>/<action:(update|delete)>' => '<controller>/<action>', |
|
* - Rules with Server Names |
|
* - with protocol |
|
* - without protocol i.e protocol relative, see https://github.com/yiisoft/yii2/pull/12697 |
|
* - with parameters |
|
* - with suffix |
|
* - with default values |
|
* - with HTTP methods |
|
* |
|
* - Adding rules dynamically |
|
* - Test custom rules that only implement the interface |
|
* |
|
* NOTE: if a test is added here, you probably also need to add one in UrlManagerCreateUrlTest. |
|
* |
|
* @group web |
|
*/ |
|
class UrlManagerParseUrlTest extends TestCase |
|
{ |
|
protected function getUrlManager($config = []) |
|
{ |
|
// in this test class, all tests have enablePrettyUrl enabled. |
|
$config['enablePrettyUrl'] = true; |
|
// normalizer is tested in UrlNormalizerTest |
|
$config['normalizer'] = false; |
|
|
|
return new UrlManager(array_merge([ |
|
'cache' => null, |
|
], $config)); |
|
} |
|
|
|
protected function getRequest($pathInfo, $hostInfo = 'http://www.example.com', $method = 'GET', $config = []) |
|
{ |
|
$config['pathInfo'] = $pathInfo; |
|
$config['hostInfo'] = $hostInfo; |
|
$_POST['_method'] = $method; |
|
return new Request($config); |
|
} |
|
|
|
protected function tearDown() |
|
{ |
|
unset($_POST['_method']); |
|
parent::tearDown(); |
|
} |
|
|
|
public function testWithoutRules() |
|
{ |
|
$manager = $this->getUrlManager(); |
|
|
|
// empty pathinfo |
|
$result = $manager->parseRequest($this->getRequest('')); |
|
$this->assertEquals(['', []], $result); |
|
// normal pathinfo |
|
$result = $manager->parseRequest($this->getRequest('site/index')); |
|
$this->assertEquals(['site/index', []], $result); |
|
// pathinfo with module |
|
$result = $manager->parseRequest($this->getRequest('module/site/index')); |
|
$this->assertEquals(['module/site/index', []], $result); |
|
// pathinfo with trailing slashes |
|
$result = $manager->parseRequest($this->getRequest('module/site/index/')); |
|
$this->assertEquals(['module/site/index/', []], $result); |
|
} |
|
|
|
public function testWithoutRulesStrict() |
|
{ |
|
$manager = $this->getUrlManager(); |
|
$manager->enableStrictParsing = true; |
|
|
|
// empty pathinfo |
|
$this->assertFalse($manager->parseRequest($this->getRequest(''))); |
|
// normal pathinfo |
|
$this->assertFalse($manager->parseRequest($this->getRequest('site/index'))); |
|
// pathinfo with module |
|
$this->assertFalse($manager->parseRequest($this->getRequest('module/site/index'))); |
|
// pathinfo with trailing slashes |
|
$this->assertFalse($manager->parseRequest($this->getRequest('module/site/index/'))); |
|
} |
|
|
|
public function suffixProvider() |
|
{ |
|
return [ |
|
['.html'], |
|
['/'], |
|
]; |
|
} |
|
|
|
/** |
|
* @dataProvider suffixProvider |
|
* @param string $suffix |
|
*/ |
|
public function testWithoutRulesWithSuffix($suffix) |
|
{ |
|
$manager = $this->getUrlManager(['suffix' => $suffix]); |
|
|
|
// empty pathinfo |
|
$result = $manager->parseRequest($this->getRequest('')); |
|
$this->assertEquals(['', []], $result); |
|
// normal pathinfo |
|
$result = $manager->parseRequest($this->getRequest('site/index')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("site/index$suffix")); |
|
$this->assertEquals(['site/index', []], $result); |
|
// pathinfo with module |
|
$result = $manager->parseRequest($this->getRequest('module/site/index')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("module/site/index$suffix")); |
|
$this->assertEquals(['module/site/index', []], $result); |
|
// pathinfo with trailing slashes |
|
if ($suffix !== '/') { |
|
$result = $manager->parseRequest($this->getRequest('module/site/index/')); |
|
$this->assertFalse($result); |
|
} |
|
$result = $manager->parseRequest($this->getRequest("module/site/index/$suffix")); |
|
$this->assertEquals(['module/site/index/', []], $result); |
|
} |
|
|
|
public function testSimpleRules() |
|
{ |
|
$config = [ |
|
'rules' => [ |
|
'post/<id:\d+>' => 'post/view', |
|
'posts' => 'post/index', |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
], |
|
]; |
|
$manager = $this->getUrlManager($config); |
|
|
|
// matching pathinfo |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample')); |
|
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
// trailing slash is significant, no match |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample/')); |
|
$this->assertEquals(['book/123/this+is+sample/', []], $result); |
|
// empty pathinfo |
|
$result = $manager->parseRequest($this->getRequest('')); |
|
$this->assertEquals(['', []], $result); |
|
// normal pathinfo |
|
$result = $manager->parseRequest($this->getRequest('site/index')); |
|
$this->assertEquals(['site/index', []], $result); |
|
// pathinfo with module |
|
$result = $manager->parseRequest($this->getRequest('module/site/index')); |
|
$this->assertEquals(['module/site/index', []], $result); |
|
} |
|
|
|
public function testSimpleRulesStrict() |
|
{ |
|
$config = [ |
|
'rules' => [ |
|
'post/<id:\d+>' => 'post/view', |
|
'posts' => 'post/index', |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
], |
|
]; |
|
$manager = $this->getUrlManager($config); |
|
$manager->enableStrictParsing = true; |
|
|
|
// matching pathinfo |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample')); |
|
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
// trailing slash is significant, no match |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample/')); |
|
$this->assertFalse($result); |
|
// empty pathinfo |
|
$result = $manager->parseRequest($this->getRequest('')); |
|
$this->assertFalse($result); |
|
// normal pathinfo |
|
$result = $manager->parseRequest($this->getRequest('site/index')); |
|
$this->assertFalse($result); |
|
// pathinfo with module |
|
$result = $manager->parseRequest($this->getRequest('module/site/index')); |
|
$this->assertFalse($result); |
|
} |
|
|
|
/** |
|
* @dataProvider suffixProvider |
|
* @param string $suffix |
|
*/ |
|
public function testSimpleRulesWithSuffix($suffix) |
|
{ |
|
$config = [ |
|
'rules' => [ |
|
'post/<id:\d+>' => 'post/view', |
|
'posts' => 'post/index', |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
], |
|
'suffix' => $suffix, |
|
]; |
|
$manager = $this->getUrlManager($config); |
|
|
|
// matching pathinfo |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample$suffix")); |
|
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
// trailing slash is significant, no match |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample/')); |
|
if ($suffix === '/') { |
|
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
} else { |
|
$this->assertFalse($result); |
|
} |
|
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample/$suffix")); |
|
$this->assertEquals(['book/123/this+is+sample/', []], $result); |
|
// empty pathinfo |
|
$result = $manager->parseRequest($this->getRequest('')); |
|
$this->assertEquals(['', []], $result); |
|
// normal pathinfo |
|
$result = $manager->parseRequest($this->getRequest('site/index')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("site/index$suffix")); |
|
$this->assertEquals(['site/index', []], $result); |
|
// pathinfo with module |
|
$result = $manager->parseRequest($this->getRequest('module/site/index')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("module/site/index$suffix")); |
|
$this->assertEquals(['module/site/index', []], $result); |
|
} |
|
|
|
/** |
|
* @dataProvider suffixProvider |
|
* @param string $suffix |
|
*/ |
|
public function testSimpleRulesWithSuffixStrict($suffix) |
|
{ |
|
$config = [ |
|
'rules' => [ |
|
'post/<id:\d+>' => 'post/view', |
|
'posts' => 'post/index', |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
], |
|
'suffix' => $suffix, |
|
]; |
|
$manager = $this->getUrlManager($config); |
|
$manager->enableStrictParsing = true; |
|
|
|
// matching pathinfo |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample$suffix")); |
|
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
// trailing slash is significant, no match |
|
$result = $manager->parseRequest($this->getRequest('book/123/this+is+sample/')); |
|
if ($suffix === '/') { |
|
$this->assertEquals(['book/view', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
} else { |
|
$this->assertFalse($result); |
|
} |
|
$result = $manager->parseRequest($this->getRequest("book/123/this+is+sample/$suffix")); |
|
$this->assertFalse($result); |
|
// empty pathinfo |
|
$result = $manager->parseRequest($this->getRequest('')); |
|
$this->assertFalse($result); |
|
// normal pathinfo |
|
$result = $manager->parseRequest($this->getRequest('site/index')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("site/index$suffix")); |
|
$this->assertFalse($result); |
|
// pathinfo with module |
|
$result = $manager->parseRequest($this->getRequest('module/site/index')); |
|
$this->assertFalse($result); |
|
$result = $manager->parseRequest($this->getRequest("module/site/index$suffix")); |
|
$this->assertFalse($result); |
|
} |
|
|
|
|
|
|
|
// TODO implement with hostinfo |
|
|
|
|
|
|
|
public function testParseRESTRequest() |
|
{ |
|
$request = new Request(); |
|
|
|
// pretty URL rules |
|
$manager = new UrlManager([ |
|
'enablePrettyUrl' => true, |
|
'showScriptName' => false, |
|
'cache' => null, |
|
'rules' => [ |
|
'PUT,POST post/<id>/<title>' => '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(['post/view', ['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(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
$_SERVER['REQUEST_METHOD'] = 'POST'; |
|
$request->pathInfo = 'post/123/this+is+sample'; |
|
$result = $manager->parseRequest($request); |
|
$this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); |
|
|
|
// no wrong matching |
|
$_SERVER['REQUEST_METHOD'] = 'POST'; |
|
$request->pathInfo = 'POST/GET'; |
|
$result = $manager->parseRequest($request); |
|
$this->assertEquals(['post/get', []], $result); |
|
|
|
// createUrl should ignore REST rules |
|
$this->mockApplication([ |
|
'components' => [ |
|
'request' => [ |
|
'hostInfo' => 'http://localhost/', |
|
'baseUrl' => '/app', |
|
], |
|
], |
|
], \yii\web\Application::className()); |
|
$this->assertEquals('/app/post/delete?id=123', $manager->createUrl(['post/delete', 'id' => 123])); |
|
$this->destroyApplication(); |
|
|
|
unset($_SERVER['REQUEST_METHOD']); |
|
} |
|
|
|
public function testAppendRules() |
|
{ |
|
$manager = $this->getUrlManager(['rules' => ['post/<id:\d+>' => 'post/view']]); |
|
|
|
$this->assertCount(1, $manager->rules); |
|
$firstRule = $manager->rules[0]; |
|
$this->assertInstanceOf('yii\web\UrlRuleInterface', $firstRule); |
|
|
|
$manager->addRules([ |
|
'posts' => 'post/index', |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
]); |
|
$this->assertCount(3, $manager->rules); |
|
$this->assertSame($firstRule, $manager->rules[0]); |
|
} |
|
|
|
public function testPrependRules() |
|
{ |
|
$manager = $this->getUrlManager(['rules' => ['post/<id:\d+>' => 'post/view']]); |
|
|
|
$this->assertCount(1, $manager->rules); |
|
$firstRule = $manager->rules[0]; |
|
$this->assertInstanceOf('yii\web\UrlRuleInterface', $firstRule); |
|
|
|
$manager->addRules([ |
|
'posts' => 'post/index', |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
], false); |
|
$this->assertCount(3, $manager->rules); |
|
$this->assertNotSame($firstRule, $manager->rules[0]); |
|
$this->assertSame($firstRule, $manager->rules[2]); |
|
} |
|
|
|
public function testRulesCache() |
|
{ |
|
$arrayCache = new ArrayCache(); |
|
|
|
$manager = $this->getUrlManager([ |
|
'rules' => ['post/<id:\d+>' => 'post/view'], |
|
'cache' => $arrayCache, |
|
]); |
|
|
|
$this->assertCount(1, $manager->rules); |
|
$firstRule = $manager->rules[0]; |
|
$this->assertInstanceOf('yii\web\UrlRuleInterface', $firstRule); |
|
$this->assertCount(1, $this->getInaccessibleProperty($arrayCache, '_cache'), |
|
'Cache contains the only one record that represents initial built rules' |
|
); |
|
|
|
$manager->addRules(['posts' => 'post/index']); |
|
$manager->addRules([ |
|
'book/<id:\d+>/<title>' => 'book/view', |
|
'book/<id:\d+>/<author>' => 'book/view' |
|
]); |
|
|
|
$this->assertCount(4, $manager->rules); |
|
$this->assertSame($firstRule, $manager->rules[0]); |
|
$this->assertCount(3, $this->getInaccessibleProperty($arrayCache, '_cache'), |
|
'The addRules() method was called twice, adding 3 new rules to the UrlManager, but we have only ' . |
|
'two additional caches: one for each addRules() method call.' |
|
); |
|
} |
|
|
|
public function testRulesCacheIsUsed() |
|
{ |
|
$arrayCache = $this->getMockBuilder('yii\caching\ArrayCache') |
|
->setMethods(['get', 'set']) |
|
->getMock(); |
|
|
|
$manager = $this->getUrlManager([ |
|
'rules' => ['post/<id:\d+>' => 'post/view'], |
|
'cache' => $arrayCache, |
|
]); |
|
|
|
$savedRules = $manager->rules; |
|
// save rules to "cache" and make sure it is reused |
|
$arrayCache->expects($this->exactly(2))->method('get')->willReturn($savedRules); |
|
$arrayCache->expects($this->never())->method('set'); |
|
|
|
for ($i = 0; $i < 2; $i++) { |
|
$this->getUrlManager([ |
|
'rules' => ['post/<id:\d+>' => 'post/view'], |
|
'cache' => $arrayCache, |
|
]); |
|
} |
|
} |
|
}
|
|
|