在Yii中重寫URL(高級版)


前兩天作了網站SEO方面的URL優化工做。 php

具體要求是:商品分類的URL中須要有這個分類的漢語拼音出現, html

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

(以前的URL大體是這樣的:http://www.abc.com/category/index/f/24/c/279/p.html,其中f參數對應分類id  ) sql

分析:在分類表裏面添加拼音字段;在url生成以前,將f參數轉換成所需的拼音。在解析URL以前,將拼音轉換成對應的分類id。 數據庫

從哪裏開始入手呢,首先想到的是在main.php中的urlManage配置中德rules數組中添加規則, 數組

難題來了,id轉換成拼音是須要查數據庫的,在main.php中查數據庫只能用原生的sql來查詢,不但影響系統的擴展,還會破壞配置文件的整潔性。 app

因而乎,查了一下Yii的API,發現Yii的擴展性作的至關出色,rules參數裏面還能夠傳入數組,而CUrlManager只是遞歸處理了一下這個rules就解決了數組參數。很佩服yii的設計者,複雜問題卻用如此簡單的幾步就解決了(代碼就不貼出來了)。 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()
站在巨人的肩膀上,你才能前進的更快,確實如此。


如今只需簡單幾步就能夠完成任務: 優化

一、建立一個MyUrlRule類,繼承自CUrlRule,(API中說是繼承CBaseUrlRule,既然CUrlRule已經繼承自CBaseUrlRule,且功能很完善,因此此處直接繼承CUrlRule )

二、重寫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類,接下來就是:


一、在構造函數中添加rule;

二、在createUrl()中先修改$params(將id轉換爲pinyin,轉換後若是有多餘的參數,能夠unset掉。);

三、在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類都去重寫那三個函數 。

相關文章
相關標籤/搜索