Commit 24e086de by Qiang Xue

Added `yii\web\UrlRuleInterface` and `yii\web\CompositeUrlRule`

parent e99d5dba
......@@ -149,6 +149,7 @@ Yii Framework 2 Change Log
- Enh: Added `Pagination::getLinks()` (qiangxue)
- Enh: Added support for reading page size from query parameters by `Pagination` (qiangxue)
- Enh: LinkPager can now register relational link tags in the html header for prev, next, first and last page (cebe)
- Enh: Added `yii\web\UrlRuleInterface` and `yii\web\CompositeUrlRule` (qiangxue)
- Chg #1186: Changed `Sort` to use comma to separate multiple sort fields and use negative sign to indicate descending sort (qiangxue)
- Chg #1519: `yii\web\User::loginRequired()` now returns the `Response` object instead of exiting the application (qiangxue)
- Chg #1586: `QueryBuilder::buildLikeCondition()` will now escape special characters and use percentage characters by default (qiangxue)
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
use Yii;
use yii\base\Object;
/**
* CompositeUrlRule represents a collection of related URL rules.
*
* These URL rules are typically created for a common purpose (e.g. RESTful API for a resource).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
abstract class CompositeUrlRule extends Object implements UrlRuleInterface
{
/**
* @var UrlRuleInterface[] the URL rules contained in this composite rule.
* This property is set in [[init()]] by the return value of [[createRules()]].
*/
protected $rules = [];
/**
* Creates the URL rules that should be contained within this composite rule.
* @return UrlRuleInterface[] the URL rules
*/
abstract protected function createRules();
/**
* @inheritdoc
*/
public function init()
{
parent::init();
$this->rules = $this->createRules();
}
/**
* @inheritdoc
*/
public function parseRequest($manager, $request)
{
foreach ($this->rules as $rule) {
/** @var \yii\web\UrlRule $rule */
if (($result = $rule->parseRequest($manager, $request)) !== false) {
Yii::trace("Request parsed with URL rule: {$rule->name}", __METHOD__);
return $result;
}
}
return false;
}
/**
* @inheritdoc
*/
public function createUrl($manager, $route, $params)
{
foreach ($this->rules as $rule) {
/** @var \yii\web\UrlRule $rule */
if (($url = $rule->createUrl($manager, $route, $params)) !== false) {
return $url;
}
}
return false;
}
}
......@@ -9,6 +9,7 @@ namespace yii\web;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\caching\Cache;
/**
......@@ -156,17 +157,22 @@ class UrlManager extends Component
}
$rules = [];
$verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS';
foreach ($this->rules as $key => $rule) {
if (!is_array($rule)) {
$rule = ['route' => $rule];
if (preg_match('/^((?:(GET|HEAD|POST|PUT|PATCH|DELETE),)*(GET|HEAD|POST|PUT|PATCH|DELETE))\s+(.*)$/', $key, $matches)) {
if (preg_match("/^((?:($verbs),)*($verbs))\\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));
$rule = Yii::createObject(array_merge($this->ruleConfig, $rule));
if (!$rule instanceof UrlRuleInterface) {
throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.');
}
$rules[] = $rule;
}
$this->rules = $rules;
......@@ -188,7 +194,6 @@ class UrlManager extends Component
/** @var UrlRule $rule */
foreach ($this->rules as $rule) {
if (($result = $rule->parseRequest($this, $request)) !== false) {
Yii::trace("Request parsed with URL rule: {$rule->name}", __METHOD__);
return $result;
}
}
......@@ -245,7 +250,7 @@ class UrlManager extends Component
/** @var UrlRule $rule */
foreach ($this->rules as $rule) {
if (($url = $rule->createUrl($this, $route, $params)) !== false) {
if ($rule->host !== null) {
if (strpos($url, '://') !== false) {
if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) {
return substr($url, 0, $pos) . $baseUrl . substr($url, $pos);
} else {
......
......@@ -7,6 +7,7 @@
namespace yii\web;
use Yii;
use yii\base\Object;
use yii\base\InvalidConfigException;
......@@ -26,7 +27,7 @@ use yii\base\InvalidConfigException;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UrlRule extends Object
class UrlRule extends Object implements UrlRuleInterface
{
/**
* Set [[mode]] with this value to mark that this rule is for URL parsing only
......@@ -47,7 +48,7 @@ class UrlRule extends Object
*/
public $pattern;
/**
* @var string the pattern used to parse and create the host info part of a URL.
* @var string the pattern used to parse and create the host info part of a URL (e.g. `http://example.com`).
* @see pattern
*/
public $host;
......@@ -127,7 +128,8 @@ class UrlRule extends Object
$this->pattern = trim($this->pattern, '/');
if ($this->host !== null) {
$this->pattern = rtrim($this->host, '/') . rtrim('/' . $this->pattern, '/') . '/';
$this->host = rtrim($this->host, '/');
$this->pattern = rtrim($this->host . '/' . $this->pattern, '/');
} elseif ($this->pattern === '') {
$this->_template = '';
$this->pattern = '#^$#u';
......@@ -157,7 +159,7 @@ class UrlRule extends Object
foreach ($matches as $match) {
$name = $match[1][0];
$pattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+';
if (isset($this->defaults[$name])) {
if (array_key_exists($name, $this->defaults)) {
$length = strlen($match[0][0]);
$offset = $match[0][1];
if ($offset > 1 && $this->pattern[$offset - 1] === '/' && $this->pattern[$offset + $length] === '/') {
......@@ -243,6 +245,9 @@ class UrlRule extends Object
} else {
$route = $this->route;
}
Yii::trace("Request parsed with URL rule: {$this->name}", __METHOD__);
return [$route, $params];
}
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UrlRuleInterface is the interface that should be implemented URL rule classes.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
interface UrlRuleInterface
{
/**
* Parses the given request and returns the corresponding route and parameters.
* @param UrlManager $manager the URL manager
* @param Request $request the request component
* @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 parseRequest($manager, $request);
/**
* 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);
}
......@@ -12,6 +12,12 @@ use yiiunit\TestCase;
*/
class UrlRuleTest extends TestCase
{
protected function setUp()
{
parent::setUp();
$this->mockApplication();
}
public function testCreateUrl()
{
$manager = new UrlManager(['cache' => null]);
......
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