Browse Source

Merge pull request #13477 from yiisoft/urlmanager-test

Refactored UrlManagerTest to cover more use cases
tags/2.0.11
Carsten Brandt 8 years ago committed by GitHub
parent
commit
1e4484748b
  1. 2
      docs/guide/runtime-routing.md
  2. 5
      framework/web/UrlManager.php
  3. 2
      framework/web/UrlRule.php
  4. 566
      tests/framework/web/UrlManagerCreateUrlTest.php
  5. 343
      tests/framework/web/UrlManagerParseUrlTest.php
  6. 642
      tests/framework/web/UrlManagerTest.php
  7. 39
      tests/framework/web/UrlNormalizerTest.php

2
docs/guide/runtime-routing.md

@ -43,7 +43,7 @@ The [[yii\web\UrlManager|URL manager]] supports two URL formats:
- the default URL format;
- the pretty URL format.
The default URL format uses a query parameter named `r` to represent the route and normal query parameters
The default URL format uses a [[yii\web\UrlManager::$routeParam|query parameter]] named `r` to represent the route and normal query parameters
to represent the query parameters associated with the route. For example, the URL `/index.php?r=post/view&id=100` represents
the route `post/view` and the `id` query parameter `100`. The default URL format does not require any configuration of
the [[yii\web\UrlManager|URL manager]] and works in any Web server setup.

5
framework/web/UrlManager.php

@ -32,6 +32,9 @@ use yii\helpers\Url;
* ]
* ```
*
* Rules are classes implementing the [[UrlRuleInterface]], by default that is [[UrlRule]].
* For nesting rules, there is also a [[GroupUrlRule]] class.
*
* For more details and usage information on UrlManager, see the [guide article on routing](guide:runtime-routing).
*
* @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend to created URLs.
@ -542,7 +545,7 @@ class UrlManager extends Component
/**
* Returns the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
* @return string the host info (e.g. "http://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
* @return string the host info (e.g. `http://www.example.com`) that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
* @throws InvalidConfigException if running in console application and [[hostInfo]] is not configured.
*/
public function getHostInfo()

2
framework/web/UrlRule.php

@ -67,7 +67,7 @@ class UrlRule extends Object implements UrlRuleInterface
/**
* @var string the URL suffix used for this rule.
* For example, ".html" can be used so that the URL looks like pointing to a static HTML page.
* If not, the value of [[UrlManager::suffix]] will be used.
* If not set, the value of [[UrlManager::suffix]] will be used.
*/
public $suffix;
/**

566
tests/framework/web/UrlManagerCreateUrlTest.php

@ -0,0 +1,566 @@
<?php
namespace yiiunit\framework\web;
use yii\web\UrlManager;
use yiiunit\TestCase;
/**
* This class implements the tests for URL creation with "pretty" url format.
*
* See [[UrlManagerTest]] for tests with "default" URL format.
* See [[UrlManagerParseUrlTest]] for url parsing with "pretty" URL format.
*
* Behavior of UrlManager::createUrl() for the "pretty" URL format varies among the following options:
* - show script name = true / false
* - rules format
* - key => value
* - array config
*
* The following features are tested:
* - route only Url::to(['post/index']);
* - with params Url::to(['post/view', 'id' => 100]);
* - with anchor Url::to(['post/view', 'id' => 100, '#' => 'content']);
* - named parameters
* - as query params
* - as controller/actions '<controller:(post|comment)>/<id:\d+>/<action:(update|delete)>' => '<controller>/<action>',
* - Rules with Server Names
* - with protocol (TODO)
* - without protocol i.e protocol relative, see https://github.com/yiisoft/yii2/pull/12697 (TODO)
* - with parameters
* - with suffix
* - with default values
* - with HTTP methods (TODO)
* - absolute/relative
*
* - Adding rules dynamically (TODO)
* - Test custom rules that only implement the interface (TODO)
*
* NOTE: if a test is added here, you probably also need to add one in UrlManagerParseUrlTest.
*
* @group web
*/
class UrlManagerCreateUrlTest extends TestCase
{
protected function getUrlManager($config = [], $showScriptName = true)
{
// in this test class, all tests have enablePrettyUrl enabled.
$config['enablePrettyUrl'] = true;
$config['cache'] = null;
// set default values if they are not set
$config = array_merge([
'baseUrl' => '',
'scriptUrl' => '/index.php',
'hostInfo' => 'http://www.example.com',
'showScriptName' => $showScriptName,
], $config);
return new UrlManager($config);
}
public function variationsProvider()
{
$baseUrlConfig = [
'baseUrl' => '/test',
'scriptUrl' => '/test/index.php',
];
return [
// method name, $showScriptName, expected URL prefix
['createUrl', true, '/index.php', []],
['createUrl', false, '', []],
['createAbsoluteUrl', true, 'http://www.example.com/index.php', []],
['createAbsoluteUrl', false, 'http://www.example.com', []],
// with different baseUrl
['createUrl', true, '/test/index.php', $baseUrlConfig],
['createUrl', false, '/test', $baseUrlConfig],
['createAbsoluteUrl', true, 'http://www.example.com/test/index.php', $baseUrlConfig],
['createAbsoluteUrl', false, 'http://www.example.com/test', $baseUrlConfig],
];
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* without rules.
*
* @dataProvider variationsProvider
*/
public function testWithoutRules($method, $showScriptName, $prefix, $config)
{
$manager = $this->getUrlManager($config, $showScriptName);
$url = $manager->$method('post/view');
$this->assertEquals("$prefix/post/view", $url);
$url = $manager->$method(['post/view']);
$this->assertEquals("$prefix/post/view", $url);
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/post/view?id=1&title=sample+post", $url);
$url = $manager->$method(['post/view', '#' => 'testhash']);
$this->assertEquals("$prefix/post/view#testhash", $url);
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post', '#' => 'testhash']);
$this->assertEquals("$prefix/post/view?id=1&title=sample+post#testhash", $url);
// with defaultAction
$url = $manager->$method(['/post', 'page' => 1]);
$this->assertEquals("$prefix/post?page=1", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* without rules.
* With UrlManager::$suffix
*
* @dataProvider variationsProvider
*/
public function testWithoutRulesWithSuffix($method, $showScriptName, $prefix, $config)
{
$config['suffix'] = '.html';
$manager = $this->getUrlManager($config, $showScriptName);
$url = $manager->$method('post/view');
$this->assertEquals("$prefix/post/view.html", $url);
$url = $manager->$method(['post/view']);
$this->assertEquals("$prefix/post/view.html", $url);
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/post/view.html?id=1&title=sample+post", $url);
$url = $manager->$method(['post/view', '#' => 'testhash']);
$this->assertEquals("$prefix/post/view.html#testhash", $url);
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post', '#' => 'testhash']);
$this->assertEquals("$prefix/post/view.html?id=1&title=sample+post#testhash", $url);
// with defaultAction
$url = $manager->$method(['/post', 'page' => 1]);
$this->assertEquals("$prefix/post.html?page=1", $url);
// test suffix '/' as it may be trimmed
$config['suffix'] = '/';
$manager = $this->getUrlManager($config, $showScriptName);
$url = $manager->$method('post/view');
$this->assertEquals("$prefix/post/view/", $url);
$url = $manager->$method(['post/view']);
$this->assertEquals("$prefix/post/view/", $url);
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/post/view/?id=1&title=sample+post", $url);
$url = $manager->$method(['post/view', '#' => 'testhash']);
$this->assertEquals("$prefix/post/view/#testhash", $url);
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post', '#' => 'testhash']);
$this->assertEquals("$prefix/post/view/?id=1&title=sample+post#testhash", $url);
// with defaultAction
$url = $manager->$method(['/post', 'page' => 1]);
$this->assertEquals("$prefix/post/?page=1", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* with simple rules.
*
* @dataProvider variationsProvider
*/
public function testSimpleRules($method, $showScriptName, $prefix, $config)
{
$config['rules'] = [
'post/<id:\d+>' => 'post/view',
'posts' => 'post/index',
'book/<id:\d+>/<title>' => 'book/view',
];
$manager = $this->getUrlManager($config, $showScriptName);
// does not match any rule
$url = $manager->$method(['post/view']);
$this->assertEquals("$prefix/post/view", $url);
// with defaultAction also does not match any rule
$url = $manager->$method(['/post', 'page' => 1]);
$this->assertEquals("$prefix/post?page=1", $url);
// match first rule
$url = $manager->$method(['post/view', 'id' => 1]);
$this->assertEquals("$prefix/post/1", $url);
// match first rule with additional param
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/post/1?title=sample+post", $url);
// match first rule with hash
$url = $manager->$method(['post/view', 'id' => 1, '#' => 'testhash']);
$this->assertEquals("$prefix/post/1#testhash", $url);
// match second rule
$url = $manager->$method(['post/index']);
$this->assertEquals("$prefix/posts", $url);
// match second rule with additional param
$url = $manager->$method(['post/index', 'category' => 'test']);
$this->assertEquals("$prefix/posts?category=test", $url);
// match third rule, ensure encoding of params
$url = $manager->$method(['book/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/book/1/sample+post", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* with simple rules.
* With UrlManager::$suffix
*
* @dataProvider variationsProvider
*/
public function testSimpleRulesWithSuffix($method, $showScriptName, $prefix, $config)
{
$config['rules'] = [
'post/<id:\d+>' => 'post/view',
'posts' => 'post/index',
'book/<id:\d+>/<title>' => 'book/view',
];
$config['suffix'] = '/';
$manager = $this->getUrlManager($config, $showScriptName);
// does not match any rule
$url = $manager->$method(['post/view']);
$this->assertEquals("$prefix/post/view/", $url);
// with defaultAction also does not match any rule
$url = $manager->$method(['/post', 'page' => 1]);
$this->assertEquals("$prefix/post/?page=1", $url);
// match first rule
$url = $manager->$method(['post/view', 'id' => 1]);
$this->assertEquals("$prefix/post/1/", $url);
// match first rule with additional param
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/post/1/?title=sample+post", $url);
// match first rule with hash
$url = $manager->$method(['post/view', 'id' => 1, '#' => 'testhash']);
$this->assertEquals("$prefix/post/1/#testhash", $url);
// match second rule
$url = $manager->$method(['post/index']);
$this->assertEquals("$prefix/posts/", $url);
// match second rule with additional param
$url = $manager->$method(['post/index', 'category' => 'test']);
$this->assertEquals("$prefix/posts/?category=test", $url);
// match third rule, ensure encoding of params
$url = $manager->$method(['book/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/book/1/sample+post/", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* with rules that have varadic controller/actions.
*
* @dataProvider variationsProvider
*/
public function testControllerActionParams($method, $showScriptName, $prefix, $config)
{
$config['rules'] = [
'<controller>/<id:\d+>' => '<controller>/view',
'<controller>s' => '<controller>/index',
'<controller>/default' => '<controller>', // rule to match default action
'<controller>/test/<action:\w+>' => '<controller>/<action>',
];
$manager = $this->getUrlManager($config, $showScriptName);
// match last rule
$url = $manager->$method(['post/view']);
$this->assertEquals("$prefix/post/test/view", $url);
// defaultAction should match third rule
$url = $manager->$method(['/post/']);
$this->assertEquals("$prefix/post/default", $url);
$url = $manager->$method(['/post']);
$this->assertEquals("$prefix/post/default", $url);
// match first rule
$url = $manager->$method(['post/view', 'id' => 1]);
$this->assertEquals("$prefix/post/1", $url);
// match first rule with additional param
$url = $manager->$method(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals("$prefix/post/1?title=sample+post", $url);
// match first rule with hash
$url = $manager->$method(['post/view', 'id' => 1, '#' => 'testhash']);
$this->assertEquals("$prefix/post/1#testhash", $url);
// match second rule
$url = $manager->$method(['post/index']);
$this->assertEquals("$prefix/posts", $url);
// match second rule with additional param
$url = $manager->$method(['post/index', 'category' => 'test']);
$this->assertEquals("$prefix/posts?category=test", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* with rules that have default values for parameters.
*
* @dataProvider variationsProvider
*/
public function testRulesWithDefaultParams($method, $showScriptName, $prefix, $config)
{
$config['rules'] = [
[
'pattern' => '',
'route' => 'frontend/page/view',
'defaults' => ['slug' => 'index'],
],
'page/<slug>' => 'frontend/page/view',
];
$manager = $this->getUrlManager($config, $showScriptName);
// match first rule
$url = $manager->$method(['frontend/page/view', 'slug' => 'index']);
$this->assertEquals("$prefix/", $url);
// match first rule with additional param
$url = $manager->$method(['frontend/page/view', 'slug' => 'index', 'sort' => 'name']);
$this->assertEquals("$prefix/?sort=name", $url);
// match first rule with hash
$url = $manager->$method(['frontend/page/view', 'slug' => 'index', '#' => 'testhash']);
$this->assertEquals("$prefix/#testhash", $url);
// match second rule
$url = $manager->$method(['frontend/page/view', 'slug' => 'services']);
$this->assertEquals("$prefix/page/services", $url);
// match second rule with additional param
$url = $manager->$method(['frontend/page/view', 'slug' => 'services', 'sort' => 'name']);
$this->assertEquals("$prefix/page/services?sort=name", $url);
// match second rule with hash
$url = $manager->$method(['frontend/page/view', 'slug' => 'services', '#' => 'testhash']);
$this->assertEquals("$prefix/page/services#testhash", $url);
// matches none of the rules
$url = $manager->$method(['frontend/page/view']);
$this->assertEquals("$prefix/frontend/page/view", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* with empty or null parameters.
*
* @dataProvider variationsProvider
* @see https://github.com/yiisoft/yii2/issues/10935
*/
public function testWithNullParams($method, $showScriptName, $prefix, $config)
{
$config['rules'] = [
'<param1>/<param2>' => 'site/index',
'<param1>' => 'site/index',
];
$manager = $this->getUrlManager($config, $showScriptName);
// match first rule
$url = $manager->$method(['site/index', 'param1' => 111, 'param2' => 222]);
$this->assertEquals("$prefix/111/222", $url);
$url = $manager->$method(['site/index', 'param1' => 112, 'param2' => 222]);
$this->assertEquals("$prefix/112/222", $url);
// match second rule
$url = $manager->$method(['site/index', 'param1' => 111, 'param2' => null]);
$this->assertEquals("$prefix/111", $url);
$url = $manager->$method(['site/index', 'param1' => 123, 'param2' => null]);
$this->assertEquals("$prefix/123", $url);
// match none of the rules
$url = $manager->$method(['site/index', 'param1' => null, 'param2' => 111]);
$this->assertEquals("$prefix/site/index?param2=111", $url);
$url = $manager->$method(['site/index', 'param1' => null, 'param2' => 123]);
$this->assertEquals("$prefix/site/index?param2=123", $url);
}
/**
* Test createUrl() and createAbsoluteUrl()
* with varying $showScriptName
* with empty pattern.
*
* @dataProvider variationsProvider
* @see https://github.com/yiisoft/yii2/issues/6717
*/
public function testWithEmptyPattern($method, $showScriptName, $prefix, $config)
{
$assertations = function($manager) use ($method, $prefix) {
// match first rule
$url = $manager->$method(['front/site/index']);
$this->assertEquals("$prefix/", $url);
$url = $manager->$method(['/front/site/index']);
$this->assertEquals("$prefix/", $url);
// match first rule with additional parameter
$url = $manager->$method(['front/site/index', 'page' => 1]);
$this->assertEquals("$prefix/?page=1", $url);
$url = $manager->$method(['/front/site/index', 'page' => 1]);
$this->assertEquals("$prefix/?page=1", $url);
};
// normal rule
$config['rules'] = [
'' => 'front/site/index',
];
$manager = $this->getUrlManager($config, $showScriptName);
$assertations($manager);
// rule prefixed with /
$config['rules'] = [
'' => '/front/site/index',
];
$manager = $this->getUrlManager($config, $showScriptName);
$assertations($manager);
// with suffix
$config['rules'] = [
'' => 'front/site/index',
];
$config['suffix'] = '/';
$manager = $this->getUrlManager($config, $showScriptName);
$assertations($manager);
}
public function absolutePatternsVariations()
{
$baseUrlConfig = [
'baseUrl' => '/test',
'scriptUrl' => '/test/index.php',
];
return [
// $showScriptName, expected URL prefix
[true, '/index.php', []],
[false, '', []],
// with different baseUrl
[true, '/test/index.php', $baseUrlConfig],
[false, '/test', $baseUrlConfig],
];
}
/**
* Test rules that have host info in the patterns.
* @dataProvider absolutePatternsVariations
*/
public function testAbsolutePatterns($showScriptName, $prefix, $config)
{
$config['rules'] = [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
'host' => 'http://<lang:en|fr>.example.com', // TODO variation of scheme https://github.com/yiisoft/yii2/issues/12691
],
// note: baseUrl is not included in the pattern
'http://www.example.com/login' => 'site/login',
];
$manager = $this->getUrlManager($config, $showScriptName);
// first rule matches
$urlParams = ['post/view', 'id' => 1, 'title' => 'sample post', 'lang' => 'en'];
$expected = "http://en.example.com$prefix/post/1/sample+post";
$this->assertEquals($expected, $manager->createUrl($urlParams));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams, true));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams, 'http'));
$this->assertEquals('https' . substr($expected, 4), $manager->createAbsoluteUrl($urlParams, 'https'));
$this->assertEquals(substr($expected, 5), $manager->createAbsoluteUrl($urlParams, '')); // protocol relative Url
$urlParams = ['post/view', 'id' => 1, 'title' => 'sample post', 'lang' => 'en', '#' => 'testhash'];
$expected = "http://en.example.com$prefix/post/1/sample+post#testhash";
$this->assertEquals($expected, $manager->createUrl($urlParams));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams));
// second rule matches
$urlParams = ['site/login'];
$expected = "http://www.example.com$prefix/login";
$this->assertEquals($expected, $manager->createUrl($urlParams));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams, true));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams, 'http'));
$this->assertEquals('https' . substr($expected, 4), $manager->createAbsoluteUrl($urlParams, 'https'));
$this->assertEquals(substr($expected, 5), $manager->createAbsoluteUrl($urlParams, '')); // protocol relative Url
// none of the rules matches
$urlParams = ['post/index', 'page' => 1];
$this->assertEquals("$prefix/post/index?page=1", $manager->createUrl($urlParams));
$expected = "http://www.example.com$prefix/post/index?page=1";
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams, true));
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams, 'http'));
$this->assertEquals('https' . substr($expected, 4), $manager->createAbsoluteUrl($urlParams, 'https'));
$this->assertEquals(substr($expected, 5), $manager->createAbsoluteUrl($urlParams, '')); // protocol relative Url
$urlParams = ['post/index', 'page' => 1, '#' => 'testhash'];
$this->assertEquals("$prefix/post/index?page=1#testhash", $manager->createUrl($urlParams));
$expected = "http://www.example.com$prefix/post/index?page=1#testhash";
$this->assertEquals($expected, $manager->createAbsoluteUrl($urlParams));
}
public function multipleHostsRulesDataProvider()
{
return [
['http://example.com'],
['https://example.com'],
['http://example.fr'],
['https://example.fr'],
];
}
/**
* Test matching of Url rules dependent on the current host info
*
* @dataProvider multipleHostsRulesDataProvider
* @see https://github.com/yiisoft/yii2/issues/7948
*/
public function testMultipleHostsRules($host)
{
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
['host' => 'http://example.com', 'pattern' => '<slug:(search)>', 'route' => 'products/search', 'defaults' => ['lang' => 'en']],
['host' => 'http://example.fr', 'pattern' => '<slug:(search)>', 'route' => 'products/search', 'defaults' => ['lang' => 'fr']],
],
'hostInfo' => $host,
'baseUrl' => '/',
'scriptUrl' => '',
]);
$url = $manager->createAbsoluteUrl(['products/search', 'lang' => 'en', 'slug' => 'search'], 'https');
$this->assertEquals('https://example.com/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'en', 'slug' => 'search']);
$this->assertEquals('http://example.com/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'en', 'slug' => 'search', 'param1' => 'value1']);
$this->assertEquals('http://example.com/search?param1=value1', $url);
$url = $manager->createAbsoluteUrl(['products/search', 'lang' => 'fr', 'slug' => 'search'], 'https');
$this->assertEquals('https://example.fr/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'fr', 'slug' => 'search']);
$this->assertEquals('http://example.fr/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'fr', 'slug' => 'search', 'param1' => 'value1']);
$this->assertEquals('http://example.fr/search?param1=value1', $url);
}
}

343
tests/framework/web/UrlManagerParseUrlTest.php

@ -0,0 +1,343 @@
<?php
namespace yiiunit\framework\web;
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;
$config['cache'] = null;
// normalizer is tested in UrlNormalizerTest
$config['normalizer'] = false;
return new UrlManager($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
*/
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
*/
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
*/
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']);
}
}

642
tests/framework/web/UrlManagerTest.php

@ -1,547 +1,241 @@
<?php
namespace yiiunit\framework\web;
use Yii;
use yii\web\Request;
use yii\web\UrlManager;
use yii\web\UrlNormalizer;
use yiiunit\TestCase;
/**
* This tests verifies all features provided by UrlManager according to the documentation.
*
* UrlManager has two main operation modes:
*
* - "default" url format, which is the simple case. Tests in this class cover this case.
* Things to be covered in this mode are the following:
* - route only createUrl(['post/index']);
* - with params createUrl(['post/view', 'id' => 100]);
* - with anchor createUrl(['post/view', 'id' => 100, '#' => 'content']);
* Variations here are createUrl and createAbsoluteUrl, where absolute Urls also vary by schema.
*
* - "pretty" url format. This is the complex case, which involves UrlRules and url parsing.
* Url creation for "pretty" url format is covered by [[UrlManagerCreateUrlTest]].
* Url parsing for "pretty" url format is covered by [[UrlManagerParseUrlTest]].
*
* @group web
*/
class UrlManagerTest extends TestCase
{
protected function setUp()
protected function getUrlManager($config = [], $showScriptName = true, $enableStrictParsing = false)
{
parent::setUp();
// in this test class, all tests have enablePrettyUrl disabled.
$config['enablePrettyUrl'] = false;
$config['cache'] = null;
// baseUrl should not be used when prettyUrl is disabled
// trigger an exception here in case it gets called
$config['baseUrl'] = null;
$this->mockApplication();
Yii::$app->set('request', function() {
$this->fail('Request component should not be accessed by UrlManager with current settings.');
});
// set default values if they are not set
$config = array_merge([
'scriptUrl' => '/index.php',
'hostInfo' => 'http://www.example.com',
'showScriptName' => $showScriptName,
'enableStrictParsing' => $enableStrictParsing,
], $config);
return new UrlManager($config);
}
/**
* $showScriptName and $enableStrictParsing should have no effect in default format.
* Passing these options ensures that.
*/
public function ignoredOptionsProvider()
{
return [
[false, false],
[true, false],
[false, true],
[true, true],
];
}
public function testCreateUrl()
/**
* @dataProvider ignoredOptionsProvider
*/
public function testCreateUrlSimple($showScriptName, $enableStrictParsing)
{
// default setting with '/' as base url
$manager = new UrlManager([
'baseUrl' => '/',
'scriptUrl' => '',
'cache' => null,
]);
$manager = $this->getUrlManager([], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl('post/view');
$this->assertEquals('/index.php?r=post%2Fview', $url);
$url = $manager->createUrl(['post/view']);
$this->assertEquals('?r=post%2Fview', $url);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('?r=post%2Fview&id=1&title=sample+post', $url);
$this->assertEquals('/index.php?r=post%2Fview', $url);
// default setting with '/test/' as base url
$manager = new UrlManager([
$manager = $this->getUrlManager([
'baseUrl' => '/test/',
'scriptUrl' => '/test',
'cache' => null,
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test?r=post%2Fview&id=1&title=sample+post', $url);
], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl('post/view');
$this->assertEquals('/test?r=post%2Fview', $url);
$url = $manager->createUrl(['post/view']);
$this->assertEquals('/test?r=post%2Fview', $url);
}
// pretty URL without rules
$manager = new UrlManager([
'enablePrettyUrl' => true,
'baseUrl' => '/',
'scriptUrl' => '',
'cache' => null,
]);
/**
* @dataProvider ignoredOptionsProvider
*/
public function testCreateUrlWithParams($showScriptName, $enableStrictParsing)
{
// default setting with '/' as base url
$manager = $this->getUrlManager([], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/post/view?id=1&title=sample+post', $url);
$manager = new UrlManager([
'enablePrettyUrl' => true,
$this->assertEquals('/index.php?r=post%2Fview&id=1&title=sample+post', $url);
// default setting with '/test/' as base url
$manager = $this->getUrlManager([
'baseUrl' => '/test/',
'scriptUrl' => '/test',
'cache' => null,
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test/post/view?id=1&title=sample+post', $url);
$manager = new UrlManager([
'enablePrettyUrl' => true,
'baseUrl' => '/test',
'scriptUrl' => '/test/index.php',
'cache' => null,
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test/index.php/post/view?id=1&title=sample+post', $url);
// test showScriptName
$manager = new UrlManager([
'enablePrettyUrl' => true,
'baseUrl' => '/test',
'scriptUrl' => '/test/index.php',
'showScriptName' => true,
'cache' => null,
]);
], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test/index.php/post/view?id=1&title=sample+post', $url);
$url = $manager->createUrl(['/post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test/index.php/post/view?id=1&title=sample+post', $url);
$manager = new UrlManager([
'enablePrettyUrl' => true,
'baseUrl' => '/test',
'scriptUrl' => '/test/index.php',
'showScriptName' => false,
'cache' => null,
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test/post/view?id=1&title=sample+post', $url);
$url = $manager->createUrl(['/post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/test/post/view?id=1&title=sample+post', $url);
// pretty URL with rules
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
],
],
'baseUrl' => '/',
'scriptUrl' => '',
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/post/1/sample+post', $url);
$url = $manager->createUrl(['post/index', 'page' => 1]);
$this->assertEquals('/post/index?page=1', $url);
// rules with defaultAction
$url = $manager->createUrl(['/post', 'page' => 1]);
$this->assertEquals('/post?page=1', $url);
// pretty URL with rules and suffix
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
],
],
'baseUrl' => '/',
'scriptUrl' => '',
'suffix' => '.html',
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('/post/1/sample+post.html', $url);
$url = $manager->createUrl(['post/index', 'page' => 1]);
$this->assertEquals('/post/index.html?page=1', $url);
// pretty URL with rules that have host info
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
'host' => 'http://<lang:en|fr>.example.com',
],
],
'baseUrl' => '/test',
'scriptUrl' => '/test',
]);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post', 'lang' => 'en']);
$this->assertEquals('http://en.example.com/test/post/1/sample+post', $url);
$url = $manager->createUrl(['post/index', 'page' => 1]);
$this->assertEquals('/test/post/index?page=1', $url);
// create url with the same route but different params/defaults
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
[
'pattern' => '',
'route' => 'frontend/page/view',
'defaults' => ['slug' => 'index'],
],
'page/<slug>' => 'frontend/page/view',
],
'baseUrl' => '/test',
'scriptUrl' => '/test',
]);
$url = $manager->createUrl(['frontend/page/view', 'slug' => 'services']);
$this->assertEquals('/test/page/services', $url);
$url = $manager->createUrl(['frontend/page/view', 'slug' => 'index']);
$this->assertEquals('/test/', $url);
$this->assertEquals('/test?r=post%2Fview&id=1&title=sample+post', $url);
}
/**
* @depends testCreateUrl
* @see https://github.com/yiisoft/yii2/issues/10935
* @dataProvider ignoredOptionsProvider
*
* @see https://github.com/yiisoft/yii2/pull/9596
*/
public function testCreateUrlWithNullParams()
public function testCreateUrlWithAnchor($showScriptName, $enableStrictParsing)
{
$manager = new UrlManager([
'rules' => [
'<param1>/<param2>' => 'site/index',
'<param1>' => 'site/index',
],
'enablePrettyUrl' => true,
'scriptUrl' => '/test',
// default setting with '/' as base url
$manager = $this->getUrlManager([], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl(['post/view', '#' => 'anchor']);
$this->assertEquals('/index.php?r=post%2Fview#anchor', $url);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post', '#' => 'anchor']);
$this->assertEquals('/index.php?r=post%2Fview&id=1&title=sample+post#anchor', $url);
]);
$this->assertEquals('/test/111', $manager->createUrl(['site/index', 'param1' => 111, 'param2' => null]));
$this->assertEquals('/test/123', $manager->createUrl(['site/index', 'param1' => 123, 'param2' => null]));
$this->assertEquals('/test/111/222', $manager->createUrl(['site/index', 'param1' => 111, 'param2' => 222]));
$this->assertEquals('/test/112/222', $manager->createUrl(['site/index', 'param1' => 112, 'param2' => 222]));
// default setting with '/test/' as base url
$manager = $this->getUrlManager([
'baseUrl' => '/test/',
'scriptUrl' => '/test',
], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl(['post/view', '#' => 'anchor']);
$this->assertEquals('/test?r=post%2Fview#anchor', $url);
$url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post', '#' => 'anchor']);
$this->assertEquals('/test?r=post%2Fview&id=1&title=sample+post#anchor', $url);
}
/**
* https://github.com/yiisoft/yii2/issues/6717
* @dataProvider ignoredOptionsProvider
*/
public function testCreateUrlWithEmptyPattern()
public function testCreateAbsoluteUrl($showScriptName, $enableStrictParsing)
{
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
'' => 'front/site/index',
],
'baseUrl' => '/',
'scriptUrl' => '',
]);
$url = $manager->createUrl(['front/site/index']);
$this->assertEquals('/', $url);
$url = $manager->createUrl(['/front/site/index']);
$this->assertEquals('/', $url);
$url = $manager->createUrl(['front/site/index', 'page' => 1]);
$this->assertEquals('/?page=1', $url);
$url = $manager->createUrl(['/front/site/index', 'page' => 1]);
$this->assertEquals('/?page=1', $url);
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
'' => '/front/site/index',
],
'baseUrl' => '/',
'scriptUrl' => '',
]);
$url = $manager->createUrl(['front/site/index']);
$this->assertEquals('/', $url);
$url = $manager->createUrl(['/front/site/index']);
$this->assertEquals('/', $url);
$url = $manager->createUrl(['front/site/index', 'page' => 1]);
$this->assertEquals('/?page=1', $url);
$url = $manager->createUrl(['/front/site/index', 'page' => 1]);
$this->assertEquals('/?page=1', $url);
}
$manager = $this->getUrlManager([], $showScriptName, $enableStrictParsing);
$url = $manager->createAbsoluteUrl('post/view');
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl(['post/view']);
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl('post/view', true);
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl(['post/view'], true);
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl('post/view', 'http');
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl(['post/view'], 'http');
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl('post/view', 'https');
$this->assertEquals('https://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl(['post/view'], 'https');
$this->assertEquals('https://www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl('post/view', '');
$this->assertEquals('//www.example.com/index.php?r=post%2Fview', $url);
$url = $manager->createAbsoluteUrl(['post/view'], '');
$this->assertEquals('//www.example.com/index.php?r=post%2Fview', $url);
public function testCreateAbsoluteUrl()
{
$manager = new UrlManager([
'baseUrl' => '/',
'scriptUrl' => '',
'hostInfo' => 'http://www.example.com',
'cache' => null,
]);
$manager->hostInfo = 'https://www.example.com';
$url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post']);
$this->assertEquals('http://www.example.com?r=post%2Fview&id=1&title=sample+post', $url);
$this->assertEquals('https://www.example.com/index.php?r=post%2Fview&id=1&title=sample+post', $url);
$url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], 'https');
$this->assertEquals('https://www.example.com?r=post%2Fview&id=1&title=sample+post', $url);
$url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], '');
$this->assertEquals('//www.example.com?r=post%2Fview&id=1&title=sample+post', $url);
$this->assertEquals('https://www.example.com/index.php?r=post%2Fview&id=1&title=sample+post', $url);
$manager->hostInfo = 'https://www.example.com';
$url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], 'http');
$this->assertEquals('http://www.example.com?r=post%2Fview&id=1&title=sample+post', $url);
$this->assertEquals('http://www.example.com/index.php?r=post%2Fview&id=1&title=sample+post', $url);
$url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], '');
$this->assertEquals('//www.example.com?r=post%2Fview&id=1&title=sample+post', $url);
$this->assertEquals('//www.example.com/index.php?r=post%2Fview&id=1&title=sample+post', $url);
}
public function testCreateAbsoluteUrlWithSuffix()
/**
* Test normalisation of different routes.
* @dataProvider ignoredOptionsProvider
*/
public function testCreateUrlRouteVariants($showScriptName, $enableStrictParsing)
{
$manager = new UrlManager([
'baseUrl' => '/',
'scriptUrl' => '',
'hostInfo' => 'http://app.example.com',
'cache' => null,
// default setting with '/' as base url
$manager = $this->getUrlManager([], $showScriptName, $enableStrictParsing);
$url = $manager->createUrl(['/post/view']);
$this->assertEquals('/index.php?r=post%2Fview', $url);
$url = $manager->createUrl(['/post/view/']);
$this->assertEquals('/index.php?r=post%2Fview', $url);
$url = $manager->createUrl(['/module/post/view']);
$this->assertEquals('/index.php?r=module%2Fpost%2Fview', $url);
$url = $manager->createUrl(['/post/view/']);
$this->assertEquals('/index.php?r=post%2Fview', $url);
}
'enablePrettyUrl' => true,
'showScriptName' => false,
'suffix' => '/',
'rules' => [
'http://app.example.com/login' => 'site/login',
],
]);
$url = $manager->createAbsoluteUrl(['site/login']);
$this->assertEquals('http://app.example.com/login/', $url);
$url = $manager->createUrl(['site/login']);
$this->assertEquals('http://app.example.com/login/', $url);
/**
* @return array provides different names for UrlManager::$routeParam
*/
public function routeParamProvider()
{
return [
['r'], // default value
['route'],
['_'],
];
}
public function testParseRequest()
/**
* @dataProvider routeParamProvider
*/
public function testParseRequest($routeParam)
{
$manager = new UrlManager(['cache' => null]);
$manager = $this->getUrlManager(['routeParam' => $routeParam]);
$request = new Request;
// default setting without 'r' param
unset($_GET['r']);
$request->setQueryParams([]);
$result = $manager->parseRequest($request);
$this->assertEquals(['', []], $result);
// default setting with 'r' param
$_GET['r'] = 'site/index';
$request->setQueryParams([$routeParam => 'site/index']);
$result = $manager->parseRequest($request);
$this->assertEquals(['site/index', []], $result);
// default setting with 'r' param as an array
$_GET['r'] = ['site/index'];
$result = $manager->parseRequest($request);
$this->assertEquals(['', []], $result);
// pretty URL without rules
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'normalizer' => false,
]);
// empty pathinfo
$request->pathInfo = '';
$request->setQueryParams([$routeParam => ['site/index']]);
$result = $manager->parseRequest($request);
$this->assertEquals(['', []], $result);
// normal pathinfo
$request->pathInfo = 'site/index';
$result = $manager->parseRequest($request);
$this->assertEquals(['site/index', []], $result);
// pathinfo with module
$request->pathInfo = 'module/site/index';
$result = $manager->parseRequest($request);
$this->assertEquals(['module/site/index', []], $result);
// pathinfo with trailing slashes
$request->pathInfo = '/module/site/index/';
$result = $manager->parseRequest($request);
$this->assertEquals(['module/site/index/', []], $result);
// trailing slash is insignificant if normalizer is enabled
$manager->normalizer = new UrlNormalizer([
'action' => null,
]);
$request->pathInfo = '/module/site/index/';
$result = $manager->parseRequest($request);
$this->assertEquals(['module/site/index', []], $result);
// pretty URL rules
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'normalizer' => false,
'rules' => [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
],
],
]);
// matching pathinfo
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// trailing slash is significant
$request->pathInfo = 'post/123/this+is+sample/';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/123/this+is+sample/', []], $result);
// empty pathinfo
$request->pathInfo = '';
$result = $manager->parseRequest($request);
$this->assertEquals(['', []], $result);
// normal pathinfo
$request->pathInfo = 'site/index';
// other parameters are not returned here
$request->setQueryParams([$routeParam => 'site/index', 'id' => 5]);
$result = $manager->parseRequest($request);
$this->assertEquals(['site/index', []], $result);
// pathinfo with module
$request->pathInfo = 'module/site/index';
$result = $manager->parseRequest($request);
$this->assertEquals(['module/site/index', []], $result);
// trailing slash is insignificant if normalizer is enabled
$manager->normalizer = new UrlNormalizer([
'action' => null,
]);
$request->pathInfo = 'post/123/this+is+sample/';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// pretty URL rules
$manager = new UrlManager([
'enablePrettyUrl' => true,
'suffix' => '.html',
'cache' => null,
'rules' => [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
],
],
]);
// matching pathinfo
$request->pathInfo = 'post/123/this+is+sample.html';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// matching pathinfo without suffix
$request->pathInfo = 'post/123/this+is+sample';
$result = $manager->parseRequest($request);
$this->assertFalse($result);
// empty pathinfo
$request->pathInfo = '';
$result = $manager->parseRequest($request);
$this->assertEquals(['', []], $result);
// normal pathinfo
$request->pathInfo = 'site/index.html';
$result = $manager->parseRequest($request);
$this->assertEquals(['site/index', []], $result);
// pathinfo without suffix
$request->pathInfo = 'site/index';
$result = $manager->parseRequest($request);
$this->assertFalse($result);
// strict parsing
$manager = new UrlManager([
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'suffix' => '.html',
'cache' => null,
'rules' => [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
],
],
]);
// matching pathinfo
$request->pathInfo = 'post/123/this+is+sample.html';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
// unmatching pathinfo
$request->pathInfo = 'site/index.html';
$result = $manager->parseRequest($request);
$this->assertFalse($result);
}
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']);
}
/**
* Tests if hash-anchor present
*
* https://github.com/yiisoft/yii2/pull/9596
*/
public function testHash()
{
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
'http://example.com/testPage' => 'site/test',
],
'hostInfo' => 'http://example.com',
'scriptUrl' => '/index.php',
]);
$url = $manager->createAbsoluteUrl(['site/test', '#' => 'testhash']);
$this->assertEquals('http://example.com/index.php/testPage#testhash', $url);
}
/**
* @dataProvider multipleHostsRulesDataProvider
*
* @see https://github.com/yiisoft/yii2/issues/7948
*
* @param string $host
*/
public function testMultipleHostsRules($host)
{
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
['host' => 'http://example.com', 'pattern' => '<slug:(search)>', 'route' => 'products/search', 'defaults' => ['lang' => 'en']],
['host' => 'http://example.fr', 'pattern' => '<slug:(search)>', 'route' => 'products/search', 'defaults' => ['lang' => 'fr']],
],
'hostInfo' => $host,
'baseUrl' => '/',
'scriptUrl' => '',
]);
$url = $manager->createAbsoluteUrl(['products/search', 'lang' => 'en', 'slug' => 'search'], 'https');
$this->assertEquals('https://example.com/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'en', 'slug' => 'search']);
$this->assertEquals('http://example.com/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'en', 'slug' => 'search', 'param1' => 'value1']);
$this->assertEquals('http://example.com/search?param1=value1', $url);
$url = $manager->createAbsoluteUrl(['products/search', 'lang' => 'fr', 'slug' => 'search'], 'https');
$this->assertEquals('https://example.fr/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'fr', 'slug' => 'search']);
$this->assertEquals('http://example.fr/search', $url);
$url = $manager->createUrl(['products/search', 'lang' => 'fr', 'slug' => 'search', 'param1' => 'value1']);
$this->assertEquals('http://example.fr/search?param1=value1', $url);
}
public function multipleHostsRulesDataProvider()
{
return [
['http://example.com'],
['https://example.com'],
['http://example.fr'],
['https://example.fr'],
];
$this->assertEquals(5, $request->getQueryParam('id'));
}
}

39
tests/framework/web/UrlNormalizerTest.php

@ -10,6 +10,8 @@ namespace yiiunit\framework\web;
use Yii;
use yii\web\NotFoundHttpException;
use yii\web\Request;
use yii\web\UrlManager;
use yii\web\UrlNormalizer;
use yii\web\UrlNormalizerRedirectException;
use yiiunit\TestCase;
@ -114,4 +116,41 @@ class UrlNormalizerTest extends TestCase
$this->assertEquals($expected, $exc);
}
}
/**
* Test usage of UrlNormalizer in UrlManager
*
* trailing slash is insignificant if normalizer is enabled
*/
public function testUrlManager()
{
$config = [
'enablePrettyUrl' => true,
'cache' => null,
'normalizer' => [
'class' => 'yii\web\UrlNormalizer',
'action' => null,
],
];
$request = new Request();
// pretty URL without rules
$config['rules'] = [];
$manager = new UrlManager($config);
$request->pathInfo = '/module/site/index/';
$result = $manager->parseRequest($request);
$this->assertEquals(['module/site/index', []], $result);
// pretty URL with rules
$config['rules'] = [
[
'pattern' => 'post/<id>/<title>',
'route' => 'post/view',
],
];
$manager = new UrlManager($config);
$request->pathInfo = 'post/123/this+is+sample/';
$result = $manager->parseRequest($request);
$this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result);
}
}

Loading…
Cancel
Save