Yii分析5:路由管理类UrlManager

在分析yii webapplication执行之前,我们先来看看yii的路由管理类CUrlManager,很多框架都有路由的功能,通常情况是将controller和view的名称作为url的一部分传给入口程序,进而调用相应的controller和view进行处理,我们来分析一下yii是如何完成这样的工作的。
关于UrlManager的使用,可以参考Yii官方文档:
(http://www.yiiframework.com/doc/guide/1.1/zh_cn/topics.url),先看一下这个component的初始化代码:

 

class CUrlManager extends CApplicationComponent
{
	const CACHE_KEY='Yii.CUrlManager.rules';
	const GET_FORMAT='get';
	const PATH_FORMAT='path';
	public $cacheID='cache';
	private $_urlFormat=self::GET_FORMAT;
/**
	 * Initializes the application component.
	 */
	public function init()
	{
		parent::init();
		$this->processRules();
	}

	/**
	 * Processes the URL rules.
	 */
	protected function processRules()
	{
		//默认采用get格式
		if(empty($this->rules) || $this->getUrlFormat()===self::GET_FORMAT)
			return;
		//如果使用缓存,并且能缓存组建可用,将url规则序列化之后以其md5值为缓存的键名获取键值,如果没有设置过,将其
		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));
	}
	/**
	 * Returns the URL format.
	 * @return URL格式的字符串,默认是’path’,有效的形式包括’path’和’get’。
	 * Please refer to the guide for more details about the difference between these two formats.
	 */
	public function getUrlFormat()
	{
		return $this->_urlFormat;
	}
	/**
	 * Creates a URL rule instance.
	 * The default implementation returns a CUrlRule object.
	 * @param string $route 规则的匹配部分
	 * @param mixed $pattern 规则的路由部分,可以是字符串,也可以是数组。
	 * @return CUrlRule the URL rule instance
	 * @since 1.1.0
	 */
	protected function createUrlRule($route,$pattern)
	{
		return new CUrlRule($route,$pattern);
	}
}

 其中的rules是在配置文件中进行配置的,参考本文yii官方文档中的介绍,典型的配置文件形式如下,格式(pattern)必须是有效的正则表达式,没有分隔符和修饰语。它是用于匹配网址的路径信息部分。还有route应指向一个有效的路线控制器(controllerID/actionID)。
'urlManager'=>array(
            'urlFormat'=>'path',
            'rules'=>array(
                'pattern1'=>'route1',
                'pattern2'=>'route2',
                'pattern3'=>'route3',
            ),
        ),
rules的一个示例如下:
'pattern1'=>array('route1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false)
yii的官方文档对此的解释如下:
•    urlSuffix: 此规则使用的url后缀,默认使用CurlManger::urlSuffix,即为null。例如可以将此设置为.html,让url看起来“像”是一个静态页面。
•    caseSensitive: 是否大小写敏感,默认使用CUrlManager::caseSensitive,即为null。
•    defaultParams: 该规则使用的默认get参数。当使用该规则来解析一个请求时,这个参数的值会被注入到$_GET参数中。
•    matchValue: 当创建一个URL时,GET参数是否匹配相应的子模式。默认使用CurlManager::matchValue,即为null。如果该属性为false,那么意味着当路由和参数名匹配给定的规则时,将以此来创建一个URL。如果该属性为true,那么给定的参数值夜必须匹配相应的参数子模式。注意:将此属性设置为true会降低性能。

那么,CUrlRule是如何实现url路由规则的呢?我们看一下CUrlRule的构造函数:

 

class CUrlRule extends CComponent
{
	/**
	 * 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))
		{
			if(isset($route['urlSuffix']))
				$this->urlSuffix=$route['urlSuffix'];
			if(isset($route['caseSensitive']))
				$this->caseSensitive=$route['caseSensitive'];
			if(isset($route['defaultParams']))
				$this->defaultParams=$route['defaultParams'];
			if(isset($route['matchValue']))
				$this->matchValue=$route['matchValue'];
			$route=$this->route=$route[0];
		}
		else
			$this->route=$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(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)));
	}

	/**
     * Parses the user request.
     * @param CHttpRequest $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)//如果是‘path’形式
        {
            $rawPathInfo=$request->getPathInfo();
            $pathInfo=$this->removeUrlSuffix($rawPathInfo,$this->urlSuffix);
            foreach($this->_rules as $rule)
            {
                if(($r=$rule->parseUrl($this,$request,$pathInfo,$rawPathInfo))!==false)
                    return isset($_GET[$this->routeVar]) ? $_GET[$this->routeVar] : $r;
            }
            if($this->useStrictParsing)
                throw new CHttpException(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 '';
    }
}

 事实上,路由规则主要是用于调用createurl时,更为有效地实现参数传递而使用的一种方式,最终还是转换成controllerID/actionID的形式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值