Get current matcher url rule, not route

Hello,

I’ve developed a extension for Yii that would apply certain SEO parameters to the page based on the URL rule that was matched by the urlManager.

In order to do that I’ve did the following steps:

  1. Modify rules from main.php config file and specify each of them as arrays and add another parameter to that array named ‘metaRule’.

Example:




array (

  'site/search',

  'pattern' => 'search/loc-<location>/type-<type>',

  'metaRule' => 'TypeLocationMetaRule',

),



The TypeLocationMetaRule name will refer to a class that will return title, meta desc, and so on.




<?php


class TypeLocationMetaRule extends BaseMetaRule {

  public function getBaseTitle() {

    return $this->getMetaValue('TypeLocationMetaRule.title');

  }

  public function getBaseDescription() {

    return $this->getMetaValue('TypeLocationMetaRule.description');

  }

  public function getBaseKeywords() {

    return $this->getMetaValue('TypeLocationMetaRule.keywords');

  }

  public function getBaseH1() {

    return $this->getMetaValue('TypeLocationMetaRule.H1');

  }

}



  1. Modified CUrlRule and added new property named ‘metaRule’

  2. Modified CUrlManager and added a new property named ‘metaRule’

  3. Modified CUrlManager’s rules processing method so that when finding the rule that maches the url, get that route’s metaRule name and assign it to the CUrlManager

  4. Now I can do Yii::app()->getUrlManager()->metaRule to know that when someone visited the page that matches ‘search/loc-<location>/type-<type>’ they will provide me the meta rule name TypeLocationMetaRule and I can use that to identify what SEO parameters to assign to the page.

The “problem” is that in order to accomplish the above I’ve created a UrlManager component but instead of extending CUrlManager I’ve totally overwritten CUrlManager, basically it’s a copy of the original CUrlManager file with some modifications.

I did this because I could not find the way to correctly override the CUrlManager’s parseUrl() method in order to identify the rule that was matched.

As for the CUrlRule I think that could have been overriden with no problem but since I’ve overwritten the whole CUrlManager component I’ve also modified CUrlRule in the same place.

So can someone suggest a way to correctly accomplish this "matched rule detection" in a decent way by extending CUrlManager and not overriding it?

Leaving here the full code of my class. I know it’s quite dirty but it is because It’s a mix between a language extension named MLUrlManager and my modifications needed for matching the detected rule.

Btw. What do you think about this technique?

My requirement was: On a real estate portal, identify the "type of search" based on the "type of url", and then apply correct SEO parameters. There were about 11 different url rules for different types of search listing, by city, by district, by property type, by operation, and combinations of those params.




class MLUrlManager extends CApplicationComponent

{

	const CACHE_KEY='Yii.CUrlManager.rules';

	const GET_FORMAT='get';

	const PATH_FORMAT='path';

  

  public $metaRule=null;

  

  /**

     * @var languages list

     */

    public $languages = array();


    public $defaultLang= 'en';


    private $_currentUrl = '';


	/**

	 * @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.

	 * @since 1.1.8

	 */

	public $urlRuleClass='CUrlRule';


	private $_urlFormat=self::GET_FORMAT;

	private $_rules=array();

	private $_baseUrl;


  

  /*

     * returns the current link with the set language for CHtml::link()

     * @param $language language string

     * @return array

     */

    public function changeLanguage($language) {

        if ($this->_currentUrl)

            $this->_currentUrl = '/'.$this->_currentUrl;

        $newUrl = array($this->_currentUrl);

        $newUrl = CMap::mergeArray($newUrl,$_GET);

        if(in_array($language,$this->languages)) {

            $newUrl['language'] = $language;

        }

        return $newUrl;

    }


    /*

     * returns the current url with the set language

     * @param $language language string

     * @return string

     */

    public function createLanguageUrl($language) {

        if ($this->_currentUrl)

            $this->_currentUrl = '/'.$this->_currentUrl;

        $get = $_GET;

        if(in_array($language,$this->languages)) {

            $get['language'] = $language;

        }

        return Yii::app()->createUrl($this->_currentUrl,$get);

    }


    /*

     * returns the current absolute url with the set language

     * @param $language language string

     * @return string

     */

    public function createAbsoluteLanguageUrl($language) {

        if ($this->_currentUrl)

            $this->_currentUrl = '/'.$this->_currentUrl;

        $get = $_GET;

        if(in_array($language,$this->languages)) {

            $get['language'] = $language;

        }

        return Yii::app()->createAbsoluteUrl($this->_currentUrl,$get);

    }


    /*

     * returns languages list array

     * @return array

     */

    public function listLanguage() {

        $list = array();

        foreach ($this->languages as $language) {

            $list[$language] = $this->changeLanguage($language);

        }

        return $list;

    }


	/**

	 * Initializes the application component.

	 */

	public function init()

	{

    

    

    

    if (!$this->languages)

            $this->languages = array(Yii::app()->language);


        $languages=$this->languages;


//        $key = array_search($this->defaultLang,$languages);

//        if($key!==false) {

//            unset($languages[$key]);

//        }




        $langReg = implode('|',$languages);

        $newRules = array();

        foreach ($this->rules as $reg => $rule) {

            if ($reg === 'robots.txt') {

              $newRules[$reg] = $rule;

            } elseif (is_string($rule)) {

              $newRules['<language:'.$langReg.'>/'.$reg] = $rule;

            } elseif (is_array($rule)) { // special handling for rules defined as array

              $rule['pattern']='<language:'.$langReg.'>/'.$rule['pattern'];

              $newRules[$reg] = $rule;

            }

        }

//        $newRules['<language:'.$langReg.'>'] = Yii::app()->defaultController;


        


        $this->rules=  $newRules;


//        Tools::print_pre($this->rules);

//        die();


    

    

		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.

	 * @since 1.1.4

	 */

	public function addRules($rules,$append=true)

	{

		if ($append)

		{

			foreach($rules as $pattern=>$route)

				$this->_rules[]=$this->createUrlRule($route,$pattern);

		}

		else

		{

			$rules=array_reverse($rules);

			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

	 * @since 1.1.0

	 */

	protected function createUrlRule($route,$pattern)

	{

		if(is_array($route) && isset($route['class']))

			return $route;

		else

		{

			$urlRuleClass=Yii::import($this->urlRuleClass,true);

			return new $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='&')

	{

    

    

    if (!isset($params['language'])) {

        $params['language'] = Yii::app()->language;

    }


    // special condition in case of search urls so it removes empty fields before building the url

    // so this way it will match with the right url rule instead of generating a broken url rule with empty values

    if ($route=='site/search') {

      foreach ($params as $k => $v) {

        if (empty($v)) {

          unset($params[$k]);

        }

      }

    }

    

    

		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;

			}

			elseif(($query=$this->createPathInfo($params,'=',$ampersand))!=='')

				$url.='?'.$query;

			return $url;

		}

	}


	/**

	 * 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)

	{

		

    

    $this->_currentUrl = $this->parseUrlBase($request);

        if (isset($_GET['language'])&&in_array($_GET['language'],$this->languages)) {

            Yii::app()->language = $_GET['language'];

//            Yii::app()->user->setState('language',$_GET['language']);

        } else {

//            if (Yii::app()->user->hasState('language'))

//                Yii::app()->language = Yii::app()->user->getState('language');

//            else if (isset(Yii::app()->request->cookies['language']))

//                Yii::app()->language = Yii::app()->request->cookies['language']->value;

        }

        return $this->_currentUrl;

    

	}

  

  public function parseUrlBase($request) {

    

//    CVarDumper::dump($request, 10, true);

//    die();

    

    if($this->getUrlFormat()===self::PATH_FORMAT)

		{

      

			$rawPathInfo=$request->getPathInfo();

			$pathInfo=$this->removeUrlSuffix($rawPathInfo,$this->urlSuffix);

			foreach($this->_rules as $i=>$rule)

			{

        $tmpRule=$rule;

				if(is_array($rule))

					$this->_rules[$i]=$rule=Yii::createComponent($rule);

				if(($r=$rule->parseUrl($this,$request,$pathInfo,$rawPathInfo))!==false) {

          

          if (Yii::app()->getUrlManager()->metaRule===null && $tmpRule->metaRule !== null) {

            Yii::app()->getUrlManager()->metaRule=$tmpRule->metaRule;

          }


          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;

		}

		elseif(isset($_GET[$this->routeVar]))

			return $_GET[$this->routeVar];

		elseif(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

	 * @since 1.1.1

	 */

	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>

 * @package system.web

 * @since 1.1.8

 */

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 CUrlManager $manager the URL manager

	 * @param CHttpRequest $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>

 * @package system.web

 * @since 1.0

 */

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.

	 * @since 1.1.0

	 */

	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.

	 * @since 1.1.7

	 */

	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.

	 * @since 1.1.7

	 */

	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;

  

  public $metaRule;


	/**

	 * 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', 'metaRule') 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['/']='\\/';

		$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://',<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='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 CUrlManager $manager the URL manager

	 * @param CHttpRequest $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;

				elseif(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;

	}

  

  

  

  

}



I think I’ve just figured out a way to get the matched rule very quickly and without modifying anything in the UrlManager component.

I think I could maybe use the defaultParams property of the rule and simply provide there a param with a name that I can later identify as the "type of url".

http://www.yiiframework.com/doc/guide/1.1/en/topics.url#user-friendly-urls

http://www.yiiframework.com/doc/api/1.1/CUrlRule#defaultParams-detail

Man this would be so much easier. I hope it does not affect url creation. I mean I hope I won’t have to provide those default params in order to be able to create the url.

I’ll test it and see!