在Yii中重写URL(高级版)


前两天做了网站SEO方面的URL优化工作。

具体要求是:商品分类的URL中需要有这个分类的汉语拼音出现,

如:http://www.abc.com/category-shafa.html  

(之前的URL大致是这样的:http://www.abc.com/category/index/f/24/c/279/p.html,其中f参数对应分类id  )

分析:在分类表里面添加拼音字段;在url生成之前,将f参数转换成所需的拼音。在解析URL之前,将拼音转换成对应的分类id。

从哪里开始入手呢,首先想到的是在main.php中的urlManage配置中德rules数组中添加规则,

难题来了,id转换成拼音是需要查数据库的,在main.php中查数据库只能用原生的sql来查询,不但影响系统的扩展,还会破坏配置文件的整洁性。

于是乎,查了一下Yii的API,发现Yii的扩展性做的相当出色,rules参数里面还可以传入数组,而CUrlManager只是递归处理了一下这个rules就解决了数组参数。很佩服yii的设计者,复杂问题却用如此简单的几步就解决了(代码就不贴出来了)。

下面是API中的参考例子。 


//Starting from version 1.1.8, one can write custom URL rule classes and use them for one or several URL rules. For example,  
array( 
  // a standard rule 
  '<action:(login|logout)>' => 'site/<action>', 
  // a custom rule using data in DB 
  array( 
    'class' => 'application.components.MyUrlRule', 
    'connectionID' => 'db', 
  ), 
) 
//Please note that the custom URL rule class should extend from CBaseUrlRule and implement the following two methods,  
//CBaseUrlRule::createUrl()  
//CBaseUrlRule::parseUrl()
站在巨人的肩膀上,你才能前进的更快,确实如此。


现在只需简单几步就可以完成任务:

1、创建一个MyUrlRule类,继承自CUrlRule,(API中说是继承CBaseUrlRule,既然CUrlRule已经继承自CBaseUrlRule,且功能很完善,所以此处直接继承CUrlRule )

2、重写createUrl()、parseUrl()这两个方法

一步一步来,首先,先创建一个UrlRule类:


class CategoryUrlRule extends CUrlRule{ 
    public function __construct($route, $pattern) { 
        parent::__construct($route, $pattern); 
    } 
     
    public function createUrl($manager, $route, $params, $ampersand) { 
        return parent::createUrl($manager, $route, $params, $ampersand); 
    } 
     
    public function parseUrl($manager, $request, $pathInfo, $rawPathInfo) { 
        return parent::parseUrl($manager, $request, $pathInfo, $rawPathInfo); 
    } 
}
这是一个最简单的UrlRule类,接下来就是:


1、在构造函数中添加rule;

2、在createUrl()中先修改$params(将id转换为pinyin,转换后如果有多余的参数,可以unset掉。);

3、在parseUrl()中解析完$params后,添加拼音转id的代码。

按照上面的三个步骤,向UrlRule类中添加相应的代码后,如下所示:(parseUrl()里面只有汉字注释中间的部分是自己写的。里面最主要的就是上面三个步骤中提到的三个函数,其余的代码都是为了完成这三个步骤的辅助代码,根据自己的数据库及url规则来自定义 )


<?php 
/** 
 *  添加新的URL生成规则 
 *  原理:添加一个新的标识符(1) 或 替换原有标识符(2) 
 *  1)  适用于只需正向解析时,某一分类的商品URL中需要展示分类的汉语拼音时, 
 *      根据分类id添加新的参数(pinyin,动态写入createUrl()中的参数$params中), 
 *      然后再rules中定义次参数的位置即可 
 *  2) 如果需要反向解析,需要在parseUrl()函数中添加新的反向解析方法 
 *  
 *   
 */ 
class CategoryUrlRule extends CUrlRule{ 
    public static $extParamName = 'iii'; 


    public static $catExtFront = 'category-'; 
    //新添加的url对应关系 
    public static $_catUrls = array(); 


    //获取新添加的URL对应关系 
    public static function getFcByPinyin($show_pinyin){ 
        $category = Category::model()->findByAttributes(array('show_pinyin'=>$show_pinyin)); 
        if($category){ 
            $f = $category->id; 
            $c = $category->property_id; 
        } 
        return array('f'=>$f,'c'=>$c); 
    } 
    //获取新添加的URL对应关系 
    public static function getCatUrls(){ 
        if(empty(self::$_catUrls)){ 
            $c = Category::model()->findAll(); 
            $u = CHtml::listData($c, 'id', 'show_pinyin'); 
            self::$_catUrls = $u; 
        } 
        return self::$_catUrls; 
    } 
    /** 
     *  return 新添加的rules规则 
     */ 
    public static function getExtRules(){ 
        return array( 
           self::$catExtFront.'<'.self::$extParamName.':\w+>*' => 'category/index', 
        ); 
    } 
    /** 
     *  验证是否用心添加的rule规则,因为新的规则要兼容之前的规则 
     *  $params 这个参数可能会增加新的元素 
     */ 
    public static function addParams($manager, $route, &$params, $ampersand){ 
        foreach ($params as $pk => $pv){ 
            if(!trim($pv)){ 
                unset($params[$pk]); 
            } 
        } 
        $extRules = self::getExtRules(); 
        if(in_array($route, $extRules) && $params){ 
            $iid = isset($params['f']) ? $params['f'] : 0; 
            if($iid){ 
                $ext = self::getCatUrls(); 
                if(in_array($iid, array_keys($ext)) && trim($ext[$iid])){ 
                    unset($params['f']); 
                    unset($params['c']); 
                    $ename = $ext[$iid]; 
                    $params[self::$extParamName] = $ename; 
                } 
            } 
        } 
    } 


    public function __construct() { 
        //注册新的rules 
        $extRules = self::getExtRules(); 
        foreach ($extRules as $pattern => $route){ 
            parent::__construct($route, $pattern); 
        } 
    } 
     
    public function createUrl($manager, $route, $params, $ampersand) { 
        //验证是否用新添加的rule规则 
        self::addParams($manager, $route, $params, $ampersand); 
        return parent::createUrl($manager, $route, $params, $ampersand); 
    } 
     
    public function parseUrl($manager, $request, $pathInfo, $rawPathInfo) { 
//        return parent::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; 
} 
                        /** 
                         * 根据提交的分类,重置$_GET/$_REQUST 
                         */ 
                        if(isset($_GET[self::$extParamName])){ 
                            $fc = self::getFcByPinyin($_GET[self::$extParamName]); 
                            foreach(array('f','c') as $fckey){ 
                                $_REQUEST[$fckey]=$_GET[$fckey]=$fc[$fckey]; 
                                if(isset($this->references[$fckey])) 
                                    $tr[$this->references[$fckey]]=$fc[$fckey]; 
                                else if(isset($this->params[$fckey])) 
                                    $_REQUEST[$fckey]=$_GET[$fckey]=$fc[$fckey]; 
                            } 
                        } 
                        /** 
                         * 完成重置$_GET/$_REQUST 
                         */ 
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; 
} 
} 
?>
然后在main.php配置文件中添加如下代码后就可以用了。


 

'rules' => array( 
    array( 
        'class' => 'webroot.protected.components.urlRules.CategoryUrlRule', 
    ), 
    '<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>', 
),


这里只是为了讲明自定义UrlRule类的大致写法。 

其实上边三个步骤中的函数可以单独写到一个父类中,所有自己扩展的UrlRule类都继承这个父类,而不需每个自定义的UrlRule类都去重写那三个函数 。

 



转载于:https://my.oschina.net/liuxiaobo/blog/202568

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值