Commit 12fbb0f7 by Qiang Xue

url WIP

parent f65a0bd9
...@@ -27,7 +27,7 @@ class UrlManager extends Component ...@@ -27,7 +27,7 @@ class UrlManager extends Component
* @var string the URL suffix used when in 'path' format. * @var string the URL suffix used when in 'path' format.
* For example, ".html" can be used so that the URL looks like pointing to a static HTML page. Defaults to empty. * For example, ".html" can be used so that the URL looks like pointing to a static HTML page. Defaults to empty.
*/ */
public $urlSuffix = ''; public $suffix;
/** /**
* @var boolean whether to show entry script name in the constructed URL. Defaults to true. * @var boolean whether to show entry script name in the constructed URL. Defaults to true.
*/ */
...@@ -122,7 +122,7 @@ class UrlManager extends Component ...@@ -122,7 +122,7 @@ class UrlManager extends Component
/** @var $rule UrlRule */ /** @var $rule UrlRule */
foreach ($this->rules as $rule) { foreach ($this->rules as $rule) {
if (($url = $rule->createUrl($route, $params)) !== false) { if (($url = $rule->createUrl($this, $route, $params)) !== false) {
return $this->getBaseUrl() . $url . $anchor; return $this->getBaseUrl() . $url . $anchor;
} }
} }
...@@ -144,4 +144,20 @@ class UrlManager extends Component ...@@ -144,4 +144,20 @@ class UrlManager extends Component
{ {
$this->_baseUrl = trim($value, '/'); $this->_baseUrl = trim($value, '/');
} }
/**
* Removes the URL suffix from path info.
* @param string $pathInfo path info part in the URL
* @param string $suffix the URL suffix to be removed
* @return string path info with URL suffix removed.
*/
public function removeSuffix($pathInfo, $suffix)
{
$n = strlen($suffix);
if ($n > 0 && substr($pathInfo, -$n) === $suffix) {
return substr($pathInfo, 0, -$n);
} else {
return $pathInfo;
}
}
} }
...@@ -20,6 +20,15 @@ use yii\base\Object; ...@@ -20,6 +20,15 @@ use yii\base\Object;
class UrlRule extends Object class UrlRule extends Object
{ {
/** /**
* Set [[mode]] with this value to mark that this rule is for URL parsing only
*/
const PARSING_ONLY = 1;
/**
* Set [[mode]] with this value to mark that this rule is for URL creation only
*/
const CREATION_ONLY = 2;
/**
* @var string regular expression used to parse a URL * @var string regular expression used to parse a URL
*/ */
public $pattern; public $pattern;
...@@ -34,11 +43,6 @@ class UrlRule extends Object ...@@ -34,11 +43,6 @@ class UrlRule extends Object
*/ */
public $defaults = array(); public $defaults = array();
/** /**
* @var boolean whether this rule is only used for request parsing.
* Defaults to false, meaning the rule is used for both URL parsing and creation.
*/
public $parsingOnly = false;
/**
* @var string the URL suffix used for this rule. * @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. * 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, the value of [[UrlManager::suffix]] will be used.
...@@ -49,7 +53,6 @@ class UrlRule extends Object ...@@ -49,7 +53,6 @@ class UrlRule extends Object
* Use array to represent multiple verbs that this rule may match. * Use array to represent multiple verbs that this rule may match.
* If this property is not set, the rule can match any verb. * If this property is not set, the rule can match any verb.
* Note that this property is only used when parsing a request. It is ignored for URL creation. * Note that this property is only used when parsing a request. It is ignored for URL creation.
* @see parsingOnly
*/ */
public $verb; public $verb;
/** /**
...@@ -57,6 +60,14 @@ class UrlRule extends Object ...@@ -57,6 +60,14 @@ class UrlRule extends Object
* If not set, it means the host info is ignored. * If not set, it means the host info is ignored.
*/ */
public $hostInfo; public $hostInfo;
/**
* @var integer a value indicating if this rule should be used for both URL parsing and creation,
* parsing only, or creation only.
* If not set, it means the rule is both URL parsing and creation.
* If it is [[PARSING_ONLY]], the rule is for URL parsing only.
* If it is [[CREATION_ONLY]], the rule is for URL creation only.
*/
public $mode;
/** /**
* @var string the template for generating a new URL. This is derived from [[pattern]] and is used in generating URL. * @var string the template for generating a new URL. This is derived from [[pattern]] and is used in generating URL.
...@@ -138,12 +149,38 @@ class UrlRule extends Object ...@@ -138,12 +149,38 @@ class UrlRule extends Object
} }
} }
public function parseUrl($pathInfo) /**
* Parses the given path info and returns the corresponding route and parameters.
* @param UrlManager $manager the URL manager
* @param string $pathInfo the path info to be parsed. It should not have slashes at the beginning or the end.
* @return array|boolean the parsing result. The route and the parameters are returned as an array.
* If false, it means this rule cannot be used to parse this path info.
*/
public function parseUrl($manager, $pathInfo)
{ {
if ($this->mode === self::CREATION_ONLY) {
return false;
}
if ($this->verb !== null && !in_array(\Yii::$app->getRequest()->verb, $this->verb, true)) { if ($this->verb !== null && !in_array(\Yii::$app->getRequest()->verb, $this->verb, true)) {
return false; return false;
} }
$suffix = (string)($this->suffix === null ? $manager->suffix : $this->suffix);
if ($suffix !== '' && $pathInfo !== '') {
$n = strlen($suffix);
if (substr($pathInfo, -$n) === $suffix) {
$pathInfo = substr($pathInfo, 0, -$n);
if ($pathInfo === '') {
// suffix alone is not allowed
return false;
}
} elseif ($suffix !== '/') {
// we allow the ending '/' to be optional if it is a suffix
return false;
}
}
if (!preg_match($this->pattern, $pathInfo, $matches)) { if (!preg_match($this->pattern, $pathInfo, $matches)) {
return false; return false;
} }
...@@ -170,9 +207,16 @@ class UrlRule extends Object ...@@ -170,9 +207,16 @@ class UrlRule extends Object
return array($route, $params); return array($route, $params);
} }
public function createUrl($route, $params) /**
* Creates a URL according to the given route and parameters.
* @param UrlManager $manager the URL manager
* @param string $route the route. It should not have slashes at the beginning or the end.
* @param array $params the parameters
* @return string|boolean the created URL, or false if this rule cannot be used for creating this URL.
*/
public function createUrl($manager, $route, $params)
{ {
if ($this->parsingOnly) { if ($this->mode === self::PARSING_ONLY) {
return false; return false;
} }
...@@ -225,6 +269,11 @@ class UrlRule extends Object ...@@ -225,6 +269,11 @@ class UrlRule extends Object
if (strpos($url, '//') !== false) { if (strpos($url, '//') !== false) {
$url = preg_replace('#/+#', '/', $url); $url = preg_replace('#/+#', '/', $url);
} }
if ($url !== '') {
$url .= ($this->suffix === null ? $manager->suffix : $this->suffix);
}
if ($params !== array()) { if ($params !== array()) {
$url .= '?' . http_build_query($params); $url .= '?' . http_build_query($params);
} }
......
...@@ -2,19 +2,21 @@ ...@@ -2,19 +2,21 @@
namespace yiiunit\framework\web; namespace yiiunit\framework\web;
use yii\web\UrlManager;
use yii\web\UrlRule; use yii\web\UrlRule;
class UrlRuleTest extends \yiiunit\TestCase class UrlRuleTest extends \yiiunit\TestCase
{ {
public function testCreateUrl() public function testCreateUrl()
{ {
$manager = new UrlManager;
$suites = $this->getTestsForCreateUrl(); $suites = $this->getTestsForCreateUrl();
foreach ($suites as $i => $suite) { foreach ($suites as $i => $suite) {
list ($name, $config, $tests) = $suite; list ($name, $config, $tests) = $suite;
$rule = new UrlRule($config); $rule = new UrlRule($config);
foreach ($tests as $j => $test) { foreach ($tests as $j => $test) {
list ($route, $params, $expected) = $test; list ($route, $params, $expected) = $test;
$url = $rule->createUrl($route, $params); $url = $rule->createUrl($manager, $route, $params);
$this->assertEquals($expected, $url, "Test#$i-$j: $name"); $this->assertEquals($expected, $url, "Test#$i-$j: $name");
} }
} }
...@@ -22,6 +24,7 @@ class UrlRuleTest extends \yiiunit\TestCase ...@@ -22,6 +24,7 @@ class UrlRuleTest extends \yiiunit\TestCase
public function testParseUrl() public function testParseUrl()
{ {
$manager = new UrlManager;
$suites = $this->getTestsForParseUrl(); $suites = $this->getTestsForParseUrl();
foreach ($suites as $i => $suite) { foreach ($suites as $i => $suite) {
list ($name, $config, $tests) = $suite; list ($name, $config, $tests) = $suite;
...@@ -30,7 +33,7 @@ class UrlRuleTest extends \yiiunit\TestCase ...@@ -30,7 +33,7 @@ class UrlRuleTest extends \yiiunit\TestCase
$pathInfo = $test[0]; $pathInfo = $test[0];
$route = $test[1]; $route = $test[1];
$params = isset($test[2]) ? $test[2] : array(); $params = isset($test[2]) ? $test[2] : array();
$result = $rule->parseUrl($pathInfo); $result = $rule->parseUrl($manager, $pathInfo);
if ($route === false) { if ($route === false) {
$this->assertFalse($result, "Test#$i-$j: $name"); $this->assertFalse($result, "Test#$i-$j: $name");
} else { } else {
...@@ -75,6 +78,17 @@ class UrlRuleTest extends \yiiunit\TestCase ...@@ -75,6 +78,17 @@ class UrlRuleTest extends \yiiunit\TestCase
), ),
), ),
array( array(
'parsing only',
array(
'pattern' => 'posts',
'route' => 'post/index',
'mode' => UrlRule::PARSING_ONLY,
),
array(
array('post/index', array(), false),
),
),
array(
'with param', 'with param',
array( array(
'pattern' => 'post/<page>', 'pattern' => 'post/<page>',
...@@ -259,6 +273,58 @@ class UrlRuleTest extends \yiiunit\TestCase ...@@ -259,6 +273,58 @@ class UrlRuleTest extends \yiiunit\TestCase
array('post/index', array('page' => 1), 'post?page=1'), array('post/index', array('page' => 1), 'post?page=1'),
), ),
), ),
array(
'empty pattern with suffix',
array(
'pattern' => '',
'route' => 'post/index',
'suffix' => '.html',
),
array(
array('post/index', array(), ''),
array('comment/index', array(), false),
array('post/index', array('page' => 1), '?page=1'),
),
),
array(
'regular pattern with suffix',
array(
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.html',
),
array(
array('post/index', array(), 'posts.html'),
array('comment/index', array(), false),
array('post/index', array('page' => 1), 'posts.html?page=1'),
),
),
array(
'empty pattern with slash suffix',
array(
'pattern' => '',
'route' => 'post/index',
'suffix' => '/',
),
array(
array('post/index', array(), ''),
array('comment/index', array(), false),
array('post/index', array('page' => 1), '?page=1'),
),
),
array(
'regular pattern with slash suffix',
array(
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '/',
),
array(
array('post/index', array(), 'posts/'),
array('comment/index', array(), false),
array('post/index', array('page' => 1), 'posts/?page=1'),
),
),
); );
} }
...@@ -295,6 +361,17 @@ class UrlRuleTest extends \yiiunit\TestCase ...@@ -295,6 +361,17 @@ class UrlRuleTest extends \yiiunit\TestCase
), ),
), ),
array( array(
'creation only',
array(
'pattern' => 'posts',
'route' => 'post/index',
'mode' => UrlRule::CREATION_ONLY,
),
array(
array('posts', false),
),
),
array(
'with param', 'with param',
array( array(
'pattern' => 'post/<page>', 'pattern' => 'post/<page>',
...@@ -479,6 +556,58 @@ class UrlRuleTest extends \yiiunit\TestCase ...@@ -479,6 +556,58 @@ class UrlRuleTest extends \yiiunit\TestCase
array('index', false), array('index', false),
), ),
), ),
array(
'empty pattern with suffix',
array(
'pattern' => '',
'route' => 'post/index',
'suffix' => '.html',
),
array(
array('', 'post/index'),
array('.html', false),
array('a.html', false),
),
),
array(
'regular pattern with suffix',
array(
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.html',
),
array(
array('posts.html', 'post/index'),
array('posts', false),
array('posts.HTML', false),
array('a.html', false),
array('a', false),
),
),
array(
'empty pattern with slash suffix',
array(
'pattern' => '',
'route' => 'post/index',
'suffix' => '/',
),
array(
array('', 'post/index'),
array('a', false),
),
),
array(
'regular pattern with slash suffix',
array(
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '/',
),
array(
array('posts', 'post/index'),
array('a', false),
),
),
); );
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment