前两天作了网站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类都去重写那三个函数 。