Qiang Xue
12 years ago
4 changed files with 73 additions and 841 deletions
@ -1,837 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* UrlManager class file |
||||
* |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright © 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
use \yii\base\Component; |
||||
|
||||
/** |
||||
* UrlManager manages the URLs of Yii applications. |
||||
* |
||||
* It provides URL construction ({@link createUrl()}) as well as parsing ({@link parseUrl()}) functionality. |
||||
* |
||||
* URLs managed via UrlManager can be in one of the following two formats, |
||||
* by setting {@link setUrlFormat urlFormat} property: |
||||
* <ul> |
||||
* <li>'path' format: /path/to/EntryScript.php/name1/value1/name2/value2...</li> |
||||
* <li>'get' format: /path/to/EntryScript.php?name1=value1&name2=value2...</li> |
||||
* </ul> |
||||
* |
||||
* When using 'path' format, UrlManager uses a set of {@link setRules rules} to: |
||||
* <ul> |
||||
* <li>parse the requested URL into a route ('ControllerID/ActionID') and GET parameters;</li> |
||||
* <li>create URLs based on the given route and GET parameters.</li> |
||||
* </ul> |
||||
* |
||||
* A rule consists of a route and a pattern. The latter is used by UrlManager to determine |
||||
* which rule is used for parsing/creating URLs. A pattern is meant to match the path info |
||||
* part of a URL. It may contain named parameters using the syntax '<ParamName:RegExp>'. |
||||
* |
||||
* When parsing a URL, a matching rule will extract the named parameters from the path info |
||||
* and put them into the $_GET variable; when creating a URL, a matching rule will extract |
||||
* the named parameters from $_GET and put them into the path info part of the created URL. |
||||
* |
||||
* If a pattern ends with '/*', it means additional GET parameters may be appended to the path |
||||
* info part of the URL; otherwise, the GET parameters can only appear in the query string part. |
||||
* |
||||
* To specify URL rules, set the {@link setRules rules} property as an array of rules (pattern=>route). |
||||
* For example, |
||||
* <pre> |
||||
* array( |
||||
* 'articles'=>'article/list', |
||||
* 'article/<id:\d+>/*'=>'article/read', |
||||
* ) |
||||
* </pre> |
||||
* Two rules are specified in the above: |
||||
* <ul> |
||||
* <li>The first rule says that if the user requests the URL '/path/to/index.php/articles', |
||||
* it should be treated as '/path/to/index.php/article/list'; and vice versa applies |
||||
* when constructing such a URL.</li> |
||||
* <li>The second rule contains a named parameter 'id' which is specified using |
||||
* the <ParamName:RegExp> syntax. It says that if the user requests the URL |
||||
* '/path/to/index.php/article/13', it should be treated as '/path/to/index.php/article/read?id=13'; |
||||
* and vice versa applies when constructing such a URL.</li> |
||||
* </ul> |
||||
* |
||||
* The route part may contain references to named parameters defined in the pattern part. |
||||
* This allows a rule to be applied to different routes based on matching criteria. |
||||
* For example, |
||||
* <pre> |
||||
* array( |
||||
* '<_c:(post|comment)>/<id:\d+>/<_a:(create|update|delete)>'=>'<_c>/<_a>', |
||||
* '<_c:(post|comment)>/<id:\d+>'=>'<_c>/view', |
||||
* '<_c:(post|comment)>s/*'=>'<_c>/list', |
||||
* ) |
||||
* </pre> |
||||
* In the above, we use two named parameters '<_c>' and '<_a>' in the route part. The '<_c>' |
||||
* parameter matches either 'post' or 'comment', while the '<_a>' parameter matches an action ID. |
||||
* |
||||
* Like normal rules, these rules can be used for both parsing and creating URLs. |
||||
* For example, using the rules above, the URL '/index.php/post/123/create' |
||||
* would be parsed as the route 'post/create' with GET parameter 'id' being 123. |
||||
* And given the route 'post/list' and GET parameter 'page' being 2, we should get a URL |
||||
* '/index.php/posts/page/2'. |
||||
* |
||||
* It is also possible to include hostname into the rules for parsing and creating URLs. |
||||
* One may extract part of the hostname to be a GET parameter. |
||||
* For example, the URL <code>http://admin.example.com/en/profile</code> may be parsed into GET parameters |
||||
* <code>user=admin</code> and <code>lang=en</code>. On the other hand, rules with hostname may also be used to |
||||
* create URLs with parameterized hostnames. |
||||
* |
||||
* In order to use parameterized hostnames, simply declare URL rules with host info, e.g.: |
||||
* <pre> |
||||
* array( |
||||
* 'http://<user:\w+>.example.com/<lang:\w+>/profile' => 'user/profile', |
||||
* ) |
||||
* </pre> |
||||
* |
||||
* If you want to customize URL generation and parsing you can write custom |
||||
* URL rule classes and use them for one or several URL rules. For example, |
||||
* <pre> |
||||
* array( |
||||
* // a standard rule |
||||
* '<action:(login|logout)>' => 'site/<action>', |
||||
* // a custom rule using data in DB |
||||
* array( |
||||
* 'class' => '\application\components\MyUrlRule', |
||||
* 'connectionID' => 'db', |
||||
* ), |
||||
* ) |
||||
* </pre> |
||||
* Please note that the custom URL rule class should extend from {@link BaseUrlRule} and |
||||
* implement the following two methods, |
||||
* <ul> |
||||
* <li>{@link BaseUrlRule::createUrl()}</li> |
||||
* <li>{@link BaseUrlRule::parseUrl()}</li> |
||||
* </ul> |
||||
* |
||||
* UrlManager is a default application component that may be accessed via |
||||
* {@link \Yii::$app->urlManager}. |
||||
* |
||||
* @property string $baseUrl The base URL of the application (the part after host name and before query string). |
||||
* If {@link showScriptName} is true, it will include the script name part. |
||||
* Otherwise, it will not, and the ending slashes are stripped off. |
||||
* @property string $urlFormat The URL format. Defaults to 'path'. Valid values include 'path' and 'get'. |
||||
* Please refer to the guide for more details about the difference between these two formats. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class UrlManager extends Component |
||||
{ |
||||
const CACHE_KEY='Yii.UrlManager.rules'; |
||||
const GET_FORMAT='get'; |
||||
const PATH_FORMAT='path'; |
||||
|
||||
/** |
||||
* @var array the URL rules (pattern=>route). |
||||
*/ |
||||
public $rules=array(); |
||||
/** |
||||
* @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. |
||||
*/ |
||||
public $urlSuffix=''; |
||||
/** |
||||
* @var boolean whether to show entry script name in the constructed URL. Defaults to true. |
||||
*/ |
||||
public $showScriptName=true; |
||||
/** |
||||
* @var boolean whether to append GET parameters to the path info part. Defaults to true. |
||||
* This property is only effective when {@link urlFormat} is 'path' and is mainly used when |
||||
* creating URLs. When it is true, GET parameters will be appended to the path info and |
||||
* separate from each other using slashes. If this is false, GET parameters will be in query part. |
||||
*/ |
||||
public $appendParams=true; |
||||
/** |
||||
* @var string the GET variable name for route. Defaults to 'r'. |
||||
*/ |
||||
public $routeVar='r'; |
||||
/** |
||||
* @var boolean whether routes are case-sensitive. Defaults to true. By setting this to false, |
||||
* the route in the incoming request will be turned to lower case first before further processing. |
||||
* As a result, you should follow the convention that you use lower case when specifying |
||||
* controller mapping ({@link CWebApplication::controllerMap}) and action mapping |
||||
* ({@link CController::actions}). Also, the directory names for organizing controllers should |
||||
* be in lower case. |
||||
*/ |
||||
public $caseSensitive=true; |
||||
/** |
||||
* @var boolean whether the GET parameter values should match the corresponding |
||||
* sub-patterns in a rule before using it to create a URL. Defaults to false, meaning |
||||
* a rule will be used for creating a URL only if its route and parameter names match the given ones. |
||||
* If this property is set true, then the given parameter values must also match the corresponding |
||||
* parameter sub-patterns. Note that setting this property to true will degrade performance. |
||||
* @since 1.1.0 |
||||
*/ |
||||
public $matchValue=false; |
||||
/** |
||||
* @var string the ID of the cache application component that is used to cache the parsed URL rules. |
||||
* Defaults to 'cache' which refers to the primary cache application component. |
||||
* Set this property to false if you want to disable caching URL rules. |
||||
*/ |
||||
public $cacheID='cache'; |
||||
/** |
||||
* @var boolean whether to enable strict URL parsing. |
||||
* This property is only effective when {@link urlFormat} is 'path'. |
||||
* If it is set true, then an incoming URL must match one of the {@link rules URL rules}. |
||||
* Otherwise, it will be treated as an invalid request and trigger a 404 HTTP exception. |
||||
* Defaults to false. |
||||
*/ |
||||
public $useStrictParsing=false; |
||||
/** |
||||
* @var string the class name or path alias for the URL rule instances. Defaults to 'CUrlRule'. |
||||
* If you change this to something else, please make sure that the new class must extend from |
||||
* {@link CBaseUrlRule} and have the same constructor signature as {@link CUrlRule}. |
||||
* It must also be serializable and autoloadable. |
||||
*/ |
||||
public $urlRuleClass='UrlRule'; |
||||
|
||||
private $_urlFormat=self::GET_FORMAT; |
||||
private $_rules=array(); |
||||
private $_baseUrl; |
||||
|
||||
|
||||
/** |
||||
* Initializes the application component. |
||||
*/ |
||||
public function init() |
||||
{ |
||||
parent::init(); |
||||
$this->processRules(); |
||||
} |
||||
|
||||
/** |
||||
* Processes the URL rules. |
||||
*/ |
||||
protected function processRules() |
||||
{ |
||||
if(empty($this->rules) || $this->getUrlFormat()===self::GET_FORMAT) |
||||
return; |
||||
if($this->cacheID!==false && ($cache=\Yii::$app->getComponent($this->cacheID))!==null) |
||||
{ |
||||
$hash=md5(serialize($this->rules)); |
||||
if(($data=$cache->get(self::CACHE_KEY))!==false && isset($data[1]) && $data[1]===$hash) |
||||
{ |
||||
$this->_rules=$data[0]; |
||||
return; |
||||
} |
||||
} |
||||
foreach($this->rules as $pattern=>$route) |
||||
$this->_rules[]=$this->createUrlRule($route,$pattern); |
||||
if(isset($cache)) |
||||
$cache->set(self::CACHE_KEY,array($this->_rules,$hash)); |
||||
} |
||||
|
||||
/** |
||||
* Adds new URL rules. |
||||
* In order to make the new rules effective, this method must be called BEFORE |
||||
* {@link CWebApplication::processRequest}. |
||||
* @param array $rules new URL rules (pattern=>route). |
||||
* @param boolean $append whether the new URL rules should be appended to the existing ones. If false, |
||||
* they will be inserted at the beginning. |
||||
*/ |
||||
public function addRules($rules, $append=true) |
||||
{ |
||||
if ($append) |
||||
{ |
||||
foreach($rules as $pattern=>$route) |
||||
$this->_rules[]=$this->createUrlRule($route,$pattern); |
||||
} |
||||
else |
||||
{ |
||||
foreach($rules as $pattern=>$route) |
||||
array_unshift($this->_rules, $this->createUrlRule($route,$pattern)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a URL rule instance. |
||||
* The default implementation returns a CUrlRule object. |
||||
* @param mixed $route the route part of the rule. This could be a string or an array |
||||
* @param string $pattern the pattern part of the rule |
||||
* @return CUrlRule the URL rule instance |
||||
*/ |
||||
protected function createUrlRule($route,$pattern) |
||||
{ |
||||
if(is_array($route) && isset($route['class'])) |
||||
return $route; |
||||
else |
||||
return new $this->urlRuleClass($route,$pattern); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a URL. |
||||
* @param string $route the controller and the action (e.g. article/read) |
||||
* @param array $params list of GET parameters (name=>value). Both the name and value will be URL-encoded. |
||||
* If the name is '#', the corresponding value will be treated as an anchor |
||||
* and will be appended at the end of the URL. |
||||
* @param string $ampersand the token separating name-value pairs in the URL. Defaults to '&'. |
||||
* @return string the constructed URL |
||||
*/ |
||||
public function createUrl($route,$params=array(),$ampersand='&') |
||||
{ |
||||
unset($params[$this->routeVar]); |
||||
foreach($params as $i=>$param) |
||||
if($param===null) |
||||
$params[$i]=''; |
||||
|
||||
if(isset($params['#'])) |
||||
{ |
||||
$anchor='#'.$params['#']; |
||||
unset($params['#']); |
||||
} |
||||
else |
||||
$anchor=''; |
||||
$route=trim($route,'/'); |
||||
foreach($this->_rules as $i=>$rule) |
||||
{ |
||||
if(is_array($rule)) |
||||
$this->_rules[$i]=$rule=Yii::createComponent($rule); |
||||
if(($url=$rule->createUrl($this,$route,$params,$ampersand))!==false) |
||||
{ |
||||
if($rule->hasHostInfo) |
||||
return $url==='' ? '/'.$anchor : $url.$anchor; |
||||
else |
||||
return $this->getBaseUrl().'/'.$url.$anchor; |
||||
} |
||||
} |
||||
return $this->createUrlDefault($route,$params,$ampersand).$anchor; |
||||
} |
||||
|
||||
/** |
||||
* Creates a URL based on default settings. |
||||
* @param string $route the controller and the action (e.g. article/read) |
||||
* @param array $params list of GET parameters |
||||
* @param string $ampersand the token separating name-value pairs in the URL. |
||||
* @return string the constructed URL |
||||
*/ |
||||
protected function createUrlDefault($route,$params,$ampersand) |
||||
{ |
||||
if($this->getUrlFormat()===self::PATH_FORMAT) |
||||
{ |
||||
$url=rtrim($this->getBaseUrl().'/'.$route,'/'); |
||||
if($this->appendParams) |
||||
{ |
||||
$url=rtrim($url.'/'.$this->createPathInfo($params,'/','/'),'/'); |
||||
return $route==='' ? $url : $url.$this->urlSuffix; |
||||
} |
||||
else |
||||
{ |
||||
if($route!=='') |
||||
$url.=$this->urlSuffix; |
||||
$query=$this->createPathInfo($params,'=',$ampersand); |
||||
return $query==='' ? $url : $url.'?'.$query; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
$url=$this->getBaseUrl(); |
||||
if(!$this->showScriptName) |
||||
$url.='/'; |
||||
if($route!=='') |
||||
{ |
||||
$url.='?'.$this->routeVar.'='.$route; |
||||
if(($query=$this->createPathInfo($params,'=',$ampersand))!=='') |
||||
$url.=$ampersand.$query; |
||||
} |
||||
else if(($query=$this->createPathInfo($params,'=',$ampersand))!=='') |
||||
$url.='?'.$query; |
||||
return $url; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parses the user request. |
||||
* @param HttpRequest $request the request application component |
||||
* @return string the route (controllerID/actionID) and perhaps GET parameters in path format. |
||||
*/ |
||||
public function parseUrl($request) |
||||
{ |
||||
if($this->getUrlFormat()===self::PATH_FORMAT) |
||||
{ |
||||
$rawPathInfo=$request->getPathInfo(); |
||||
$pathInfo=$this->removeUrlSuffix($rawPathInfo,$this->urlSuffix); |
||||
foreach($this->_rules as $i=>$rule) |
||||
{ |
||||
if(is_array($rule)) |
||||
$this->_rules[$i]=$rule=Yii::createComponent($rule); |
||||
if(($r=$rule->parseUrl($this,$request,$pathInfo,$rawPathInfo))!==false) |
||||
return isset($_GET[$this->routeVar]) ? $_GET[$this->routeVar] : $r; |
||||
} |
||||
if($this->useStrictParsing) |
||||
throw new HttpException(404,Yii::t('yii|Unable to resolve the request "{route}".', |
||||
array('{route}'=>$pathInfo))); |
||||
else |
||||
return $pathInfo; |
||||
} |
||||
else if(isset($_GET[$this->routeVar])) |
||||
return $_GET[$this->routeVar]; |
||||
else if(isset($_POST[$this->routeVar])) |
||||
return $_POST[$this->routeVar]; |
||||
else |
||||
return ''; |
||||
} |
||||
|
||||
/** |
||||
* Parses a path info into URL segments and saves them to $_GET and $_REQUEST. |
||||
* @param string $pathInfo path info |
||||
*/ |
||||
public function parsePathInfo($pathInfo) |
||||
{ |
||||
if($pathInfo==='') |
||||
return; |
||||
$segs=explode('/',$pathInfo.'/'); |
||||
$n=count($segs); |
||||
for($i=0;$i<$n-1;$i+=2) |
||||
{ |
||||
$key=$segs[$i]; |
||||
if($key==='') continue; |
||||
$value=$segs[$i+1]; |
||||
if(($pos=strpos($key,'['))!==false && ($m=preg_match_all('/\[(.*?)\]/',$key,$matches))>0) |
||||
{ |
||||
$name=substr($key,0,$pos); |
||||
for($j=$m-1;$j>=0;--$j) |
||||
{ |
||||
if($matches[1][$j]==='') |
||||
$value=array($value); |
||||
else |
||||
$value=array($matches[1][$j]=>$value); |
||||
} |
||||
if(isset($_GET[$name]) && is_array($_GET[$name])) |
||||
$value=CMap::mergeArray($_GET[$name],$value); |
||||
$_REQUEST[$name]=$_GET[$name]=$value; |
||||
} |
||||
else |
||||
$_REQUEST[$key]=$_GET[$key]=$value; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a path info based on the given parameters. |
||||
* @param array $params list of GET parameters |
||||
* @param string $equal the separator between name and value |
||||
* @param string $ampersand the separator between name-value pairs |
||||
* @param string $key this is used internally. |
||||
* @return string the created path info |
||||
*/ |
||||
public function createPathInfo($params,$equal,$ampersand, $key=null) |
||||
{ |
||||
$pairs = array(); |
||||
foreach($params as $k => $v) |
||||
{ |
||||
if ($key!==null) |
||||
$k = $key.'['.$k.']'; |
||||
|
||||
if (is_array($v)) |
||||
$pairs[]=$this->createPathInfo($v,$equal,$ampersand, $k); |
||||
else |
||||
$pairs[]=urlencode($k).$equal.urlencode($v); |
||||
} |
||||
return implode($ampersand,$pairs); |
||||
} |
||||
|
||||
/** |
||||
* Removes the URL suffix from path info. |
||||
* @param string $pathInfo path info part in the URL |
||||
* @param string $urlSuffix the URL suffix to be removed |
||||
* @return string path info with URL suffix removed. |
||||
*/ |
||||
public function removeUrlSuffix($pathInfo,$urlSuffix) |
||||
{ |
||||
if($urlSuffix!=='' && substr($pathInfo,-strlen($urlSuffix))===$urlSuffix) |
||||
return substr($pathInfo,0,-strlen($urlSuffix)); |
||||
else |
||||
return $pathInfo; |
||||
} |
||||
|
||||
/** |
||||
* Returns the base URL of the application. |
||||
* @return string the base URL of the application (the part after host name and before query string). |
||||
* If {@link showScriptName} is true, it will include the script name part. |
||||
* Otherwise, it will not, and the ending slashes are stripped off. |
||||
*/ |
||||
public function getBaseUrl() |
||||
{ |
||||
if($this->_baseUrl!==null) |
||||
return $this->_baseUrl; |
||||
else |
||||
{ |
||||
if($this->showScriptName) |
||||
$this->_baseUrl=\Yii::$app->getRequest()->getScriptUrl(); |
||||
else |
||||
$this->_baseUrl=\Yii::$app->getRequest()->getBaseUrl(); |
||||
return $this->_baseUrl; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the base URL of the application (the part after host name and before query string). |
||||
* This method is provided in case the {@link baseUrl} cannot be determined automatically. |
||||
* The ending slashes should be stripped off. And you are also responsible to remove the script name |
||||
* if you set {@link showScriptName} to be false. |
||||
* @param string $value the base URL of the application |
||||
*/ |
||||
public function setBaseUrl($value) |
||||
{ |
||||
$this->_baseUrl=$value; |
||||
} |
||||
|
||||
/** |
||||
* Returns the URL format. |
||||
* @return string the URL format. Defaults to 'path'. Valid values include 'path' and 'get'. |
||||
* Please refer to the guide for more details about the difference between these two formats. |
||||
*/ |
||||
public function getUrlFormat() |
||||
{ |
||||
return $this->_urlFormat; |
||||
} |
||||
|
||||
/** |
||||
* Sets the URL format. |
||||
* @param string $value the URL format. It must be either 'path' or 'get'. |
||||
*/ |
||||
public function setUrlFormat($value) |
||||
{ |
||||
if($value===self::PATH_FORMAT || $value===self::GET_FORMAT) |
||||
$this->_urlFormat=$value; |
||||
else |
||||
throw new CException(Yii::t('yii|CUrlManager.UrlFormat must be either "path" or "get".')); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* CBaseUrlRule is the base class for a URL rule class. |
||||
* |
||||
* Custom URL rule classes should extend from this class and implement two methods: |
||||
* {@link createUrl} and {@link parseUrl}. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
*/ |
||||
abstract class CBaseUrlRule extends CComponent |
||||
{ |
||||
/** |
||||
* @var boolean whether this rule will also parse the host info part. Defaults to false. |
||||
*/ |
||||
public $hasHostInfo=false; |
||||
/** |
||||
* Creates a URL based on this rule. |
||||
* @param CUrlManager $manager the manager |
||||
* @param string $route the route |
||||
* @param array $params list of parameters (name=>value) associated with the route |
||||
* @param string $ampersand the token separating name-value pairs in the URL. |
||||
* @return mixed the constructed URL. False if this rule does not apply. |
||||
*/ |
||||
abstract public function createUrl($manager,$route,$params,$ampersand); |
||||
/** |
||||
* Parses a URL based on this rule. |
||||
* @param UrlManager $manager the URL manager |
||||
* @param HttpRequest $request the request object |
||||
* @param string $pathInfo path info part of the URL (URL suffix is already removed based on {@link CUrlManager::urlSuffix}) |
||||
* @param string $rawPathInfo path info that contains the potential URL suffix |
||||
* @return mixed the route that consists of the controller ID and action ID. False if this rule does not apply. |
||||
*/ |
||||
abstract public function parseUrl($manager,$request,$pathInfo,$rawPathInfo); |
||||
} |
||||
|
||||
/** |
||||
* CUrlRule represents a URL formatting/parsing rule. |
||||
* |
||||
* It mainly consists of two parts: route and pattern. The former classifies |
||||
* the rule so that it only applies to specific controller-action route. |
||||
* The latter performs the actual formatting and parsing role. The pattern |
||||
* may have a set of named parameters. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
*/ |
||||
class CUrlRule extends CBaseUrlRule |
||||
{ |
||||
/** |
||||
* @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. |
||||
* Defaults to null, meaning using the value of {@link CUrlManager::urlSuffix}. |
||||
*/ |
||||
public $urlSuffix; |
||||
/** |
||||
* @var boolean whether the rule is case sensitive. Defaults to null, meaning |
||||
* using the value of {@link CUrlManager::caseSensitive}. |
||||
*/ |
||||
public $caseSensitive; |
||||
/** |
||||
* @var array the default GET parameters (name=>value) that this rule provides. |
||||
* When this rule is used to parse the incoming request, the values declared in this property |
||||
* will be injected into $_GET. |
||||
*/ |
||||
public $defaultParams=array(); |
||||
/** |
||||
* @var boolean whether the GET parameter values should match the corresponding |
||||
* sub-patterns in the rule when creating a URL. Defaults to null, meaning using the value |
||||
* of {@link CUrlManager::matchValue}. When this property is false, it means |
||||
* a rule will be used for creating a URL if its route and parameter names match the given ones. |
||||
* If this property is set true, then the given parameter values must also match the corresponding |
||||
* parameter sub-patterns. Note that setting this property to true will degrade performance. |
||||
*/ |
||||
public $matchValue; |
||||
/** |
||||
* @var string the HTTP verb (e.g. GET, POST, DELETE) that this rule should match. |
||||
* If this rule can match multiple verbs, please separate them with commas. |
||||
* 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. |
||||
*/ |
||||
public $verb; |
||||
/** |
||||
* @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 controller/action pair |
||||
*/ |
||||
public $route; |
||||
/** |
||||
* @var array the mapping from route param name to token name (e.g. _r1=><1>) |
||||
*/ |
||||
public $references=array(); |
||||
/** |
||||
* @var string the pattern used to match route |
||||
*/ |
||||
public $routePattern; |
||||
/** |
||||
* @var string regular expression used to parse a URL |
||||
*/ |
||||
public $pattern; |
||||
/** |
||||
* @var string template used to construct a URL |
||||
*/ |
||||
public $template; |
||||
/** |
||||
* @var array list of parameters (name=>regular expression) |
||||
*/ |
||||
public $params=array(); |
||||
/** |
||||
* @var boolean whether the URL allows additional parameters at the end of the path info. |
||||
*/ |
||||
public $append; |
||||
/** |
||||
* @var boolean whether host info should be considered for this rule |
||||
*/ |
||||
public $hasHostInfo; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param string $route the route of the URL (controller/action) |
||||
* @param string $pattern the pattern for matching the URL |
||||
*/ |
||||
public function __construct($route,$pattern) |
||||
{ |
||||
if(is_array($route)) |
||||
{ |
||||
foreach(array('urlSuffix', 'caseSensitive', 'defaultParams', 'matchValue', 'verb', 'parsingOnly') as $name) |
||||
{ |
||||
if(isset($route[$name])) |
||||
$this->$name=$route[$name]; |
||||
} |
||||
if(isset($route['pattern'])) |
||||
$pattern=$route['pattern']; |
||||
$route=$route[0]; |
||||
} |
||||
$this->route=trim($route,'/'); |
||||
|
||||
$tr2['/']=$tr['/']='\\/'; |
||||
|
||||
if(strpos($route,'<')!==false && preg_match_all('/<(\w+)>/',$route,$matches2)) |
||||
{ |
||||
foreach($matches2[1] as $name) |
||||
$this->references[$name]="<$name>"; |
||||
} |
||||
|
||||
$this->hasHostInfo=!strncasecmp($pattern,'http://',7) || !strncasecmp($pattern,'https://',8); |
||||
|
||||
if($this->verb!==null) |
||||
$this->verb=preg_split('/[\s,]+/',strtoupper($this->verb),-1,PREG_SPLIT_NO_EMPTY); |
||||
|
||||
if(preg_match_all('/<(\w+):?(.*?)?>/',$pattern,$matches)) |
||||
{ |
||||
$tokens=array_combine($matches[1],$matches[2]); |
||||
foreach($tokens as $name=>$value) |
||||
{ |
||||
if($value==='') |
||||
$value='[^\/]+'; |
||||
$tr["<$name>"]="(?P<$name>$value)"; |
||||
if(isset($this->references[$name])) |
||||
$tr2["<$name>"]=$tr["<$name>"]; |
||||
else |
||||
$this->params[$name]=$value; |
||||
} |
||||
} |
||||
$p=rtrim($pattern,'*'); |
||||
$this->append=$p!==$pattern; |
||||
$p=trim($p,'/'); |
||||
$this->template=preg_replace('/<(\w+):?.*?>/','<$1>',$p); |
||||
$this->pattern='/^'.strtr($this->template,$tr).'\/'; |
||||
if($this->append) |
||||
$this->pattern.='/u'; |
||||
else |
||||
$this->pattern.='$/u'; |
||||
|
||||
if($this->references!==array()) |
||||
$this->routePattern='/^'.strtr($this->route,$tr2).'$/u'; |
||||
|
||||
if(YII_DEBUG && @preg_match($this->pattern,'test')===false) |
||||
throw new CException(Yii::t('yii|The URL pattern "{pattern}" for route "{route}" is not a valid regular expression.', |
||||
array('{route}'=>$route,'{pattern}'=>$pattern))); |
||||
} |
||||
|
||||
/** |
||||
* Creates a URL based on this rule. |
||||
* @param CUrlManager $manager the manager |
||||
* @param string $route the route |
||||
* @param array $params list of parameters |
||||
* @param string $ampersand the token separating name-value pairs in the URL. |
||||
* @return mixed the constructed URL or false on error |
||||
*/ |
||||
public function createUrl($manager,$route,$params,$ampersand) |
||||
{ |
||||
if($this->parsingOnly) |
||||
return false; |
||||
|
||||
if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive) |
||||
$case=''; |
||||
else |
||||
$case='i'; |
||||
|
||||
$tr=array(); |
||||
if($route!==$this->route) |
||||
{ |
||||
if($this->routePattern!==null && preg_match($this->routePattern.$case,$route,$matches)) |
||||
{ |
||||
foreach($this->references as $key=>$name) |
||||
$tr[$name]=$matches[$key]; |
||||
} |
||||
else |
||||
return false; |
||||
} |
||||
|
||||
foreach($this->defaultParams as $key=>$value) |
||||
{ |
||||
if(isset($params[$key])) |
||||
{ |
||||
if($params[$key]==$value) |
||||
unset($params[$key]); |
||||
else |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
foreach($this->params as $key=>$value) |
||||
if(!isset($params[$key])) |
||||
return false; |
||||
|
||||
if($manager->matchValue && $this->matchValue===null || $this->matchValue) |
||||
{ |
||||
foreach($this->params as $key=>$value) |
||||
{ |
||||
if(!preg_match('/\A'.$value.'\z/u'.$case,$params[$key])) |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
foreach($this->params as $key=>$value) |
||||
{ |
||||
$tr["<$key>"]=urlencode($params[$key]); |
||||
unset($params[$key]); |
||||
} |
||||
|
||||
$suffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix; |
||||
|
||||
$url=strtr($this->template,$tr); |
||||
|
||||
if($this->hasHostInfo) |
||||
{ |
||||
$hostInfo=\Yii::$app->getRequest()->getHostInfo(); |
||||
if(stripos($url,$hostInfo)===0) |
||||
$url=substr($url,strlen($hostInfo)); |
||||
} |
||||
|
||||
if(empty($params)) |
||||
return $url!=='' ? $url.$suffix : $url; |
||||
|
||||
if($this->append) |
||||
$url.='/'.$manager->createPathInfo($params,'/','/').$suffix; |
||||
else |
||||
{ |
||||
if($url!=='') |
||||
$url.=$suffix; |
||||
$url.='?'.$manager->createPathInfo($params,'=',$ampersand); |
||||
} |
||||
|
||||
return $url; |
||||
} |
||||
|
||||
/** |
||||
* Parses a URL based on this rule. |
||||
* @param UrlManager $manager the URL manager |
||||
* @param HttpRequest $request the request object |
||||
* @param string $pathInfo path info part of the URL |
||||
* @param string $rawPathInfo path info that contains the potential URL suffix |
||||
* @return mixed the route that consists of the controller ID and action ID or false on error |
||||
*/ |
||||
public function parseUrl($manager,$request,$pathInfo,$rawPathInfo) |
||||
{ |
||||
if($this->verb!==null && !in_array($request->getRequestType(), $this->verb, true)) |
||||
return false; |
||||
|
||||
if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive) |
||||
$case=''; |
||||
else |
||||
$case='i'; |
||||
|
||||
if($this->urlSuffix!==null) |
||||
$pathInfo=$manager->removeUrlSuffix($rawPathInfo,$this->urlSuffix); |
||||
|
||||
// URL suffix required, but not found in the requested URL |
||||
if($manager->useStrictParsing && $pathInfo===$rawPathInfo) |
||||
{ |
||||
$urlSuffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix; |
||||
if($urlSuffix!='' && $urlSuffix!=='/') |
||||
return false; |
||||
} |
||||
|
||||
if($this->hasHostInfo) |
||||
$pathInfo=strtolower($request->getHostInfo()).rtrim('/'.$pathInfo,'/'); |
||||
|
||||
$pathInfo.='/'; |
||||
|
||||
if(preg_match($this->pattern.$case,$pathInfo,$matches)) |
||||
{ |
||||
foreach($this->defaultParams as $name=>$value) |
||||
{ |
||||
if(!isset($_GET[$name])) |
||||
$_REQUEST[$name]=$_GET[$name]=$value; |
||||
} |
||||
$tr=array(); |
||||
foreach($matches as $key=>$value) |
||||
{ |
||||
if(isset($this->references[$key])) |
||||
$tr[$this->references[$key]]=$value; |
||||
else if(isset($this->params[$key])) |
||||
$_REQUEST[$key]=$_GET[$key]=$value; |
||||
} |
||||
if($pathInfo!==$matches[0]) // there're additional GET params |
||||
$manager->parsePathInfo(ltrim(substr($pathInfo,strlen($matches[0])),'/')); |
||||
if($this->routePattern!==null) |
||||
return strtr($this->route,$tr); |
||||
else |
||||
return $this->route; |
||||
} |
||||
else |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,52 @@
|
||||
<?php |
||||
/** |
||||
* UrlManager class file |
||||
* |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright © 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\web; |
||||
|
||||
use \yii\base\Component; |
||||
|
||||
/** |
||||
* UrlManager manages the URLs of Yii applications. |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class UrlManager extends Component |
||||
{ |
||||
public $routeVar = 'r'; |
||||
|
||||
/** |
||||
* Initializes the application component. |
||||
*/ |
||||
public function init() |
||||
{ |
||||
parent::init(); |
||||
$this->processRules(); |
||||
} |
||||
|
||||
/** |
||||
* Processes the URL rules. |
||||
*/ |
||||
protected function processRules() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Parses the user request. |
||||
* @param HttpRequest $request the request application component |
||||
* @return string the route (controllerID/actionID) and perhaps GET parameters in path format. |
||||
*/ |
||||
public function parseUrl($request) |
||||
{ |
||||
if(isset($_GET[$this->routeVar])) |
||||
return $_GET[$this->routeVar]; |
||||
else |
||||
return ''; |
||||
} |
||||
} |
Loading…
Reference in new issue