diff options
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | HISTORY | 2 | ||||
| -rw-r--r-- | framework/Exceptions/messages.txt | 4 | ||||
| -rw-r--r-- | framework/TApplication.php | 2 | ||||
| -rw-r--r-- | framework/Web/THttpRequest.php | 194 | ||||
| -rw-r--r-- | framework/Web/TUrlManager.php | 142 | ||||
| -rw-r--r-- | framework/Web/TUrlMapping.php | 54 | 
7 files changed, 268 insertions, 131 deletions
| diff --git a/.gitattributes b/.gitattributes index 665367a7..751393fa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1922,6 +1922,7 @@ framework/Web/THttpRequest.php -text  framework/Web/THttpResponse.php -text  framework/Web/THttpSession.php -text  framework/Web/THttpUtility.php -text +framework/Web/TUrlManager.php -text  framework/Web/TUrlMapping.php -text  framework/Web/UI/ActiveControls/TActiveButton.php -text  framework/Web/UI/ActiveControls/TActiveControlAdapter.php -text @@ -24,6 +24,7 @@ BUG: TTableCell should render   only when Text is not set and there's no ch  BUG: global state was not saved when redirect() is invoked (Qiang)  BUG: TPager would not display if it was invisible previously (Qiang)  ENH: Ticket#446 - Added TMetaTagCollection.getMetaTagByID method (Qiang) +ENH: Ticket#451 - Modified TUrlMapping to extend from TUrlManager (Qiang)  ENH: Ticket#468 - Added support of using all property tags in skins (Qiang)  ENH: Ticket#471 - Added methods in TAssetManager to expose published path and URL (Qiang)  CHG: Ticket#437 - __autoload is replaced by spl_autoload_register (Qiang) @@ -33,6 +34,7 @@ CHG: TDataGrid now does not set default table styles (Qiang)  CHG: TRepeater does not render <span> anymore for empty item template (Qiang)  CHG: THttpRequest.constructUrl() now encodes ampersand by default (Qiang)  CHG: TDataBoundControl will not throw exception if CurrentPageIndex is out of range (Qiang) +NEW: TUrlManager (Qiang)  Version 3.0.5 October 23, 2006  ============================== diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index 3afc7c3d..dcd3c749 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -48,6 +48,10 @@ securitymanager_mcryptextension_required = Mcrypt PHP extension is required in o  uri_format_invalid						= '{0}' is not a valid URI.
 +httprequest_separator_invalid			= THttpRequest.UrlParamSeparator can only contain a single character.
 +httprequest_urlmanager_inexist			= THttpRequest.UrlManager '{0}' does not point to an existing module.
 +httprequest_urlmanager_invalid			= THttpRequest.UrlManager '{0}' must point to a module extending from TUrlManager.
 +
  httpresponse_bufferoutput_unchangeable	= THttpResponse.BufferOutput cannot be modified after THttpResponse is initialized.
  httpresponse_file_inexistent			= THttpResponse cannot send file '{0}'. The file does not exist.
 diff --git a/framework/TApplication.php b/framework/TApplication.php index ce05893b..be2cce19 100644 --- a/framework/TApplication.php +++ b/framework/TApplication.php @@ -880,6 +880,8 @@ class TApplication extends TComponent  		$request=$this->getRequest();  		$request->setAvailableServices($serviceIDs); +		$request->resolveRequest(); +  		if(($serviceID=$request->getServiceID())===null)  			$serviceID=self::PAGE_SERVICE_ID;  		if(isset($services[$serviceID])) diff --git a/framework/Web/THttpRequest.php b/framework/Web/THttpRequest.php index bb7b4281..47fe1230 100644 --- a/framework/Web/THttpRequest.php +++ b/framework/Web/THttpRequest.php @@ -10,6 +10,8 @@   * @package System.Web
   */
 +Prado::using('System.Web.TUrlManager');
 +
  /**
   * THttpRequest class
   *
 @@ -38,17 +40,26 @@   * takes precedence.
   *
   * To construct a URL that can be recognized by Prado, use {@link constructUrl()}.
 - * THttpRequest also provides the cookies sent by the user, user information such
 - * as his browser capabilities, accepted languages, etc.
 - * Currently, THttpRequest recognizes the following URL format:
 + * The format of the recognizable URLs is determined according to
 + * {@link setUrlManager UrlManager}. By default, the following two formats
 + * are recognized:
   * <code>
 - * /index.php?ServiceID=ServiceParameter
 + * /index.php?ServiceID=ServiceParameter&Name1=Value1&Name2=Value2
 + * /index.php/ServiceID,ServiceParameter/Name1,Value1/Name2,Value2
   * </code>
 - * where ServiceID is as defined in the application configuration (e.g.
 - * the default page service's service ID is 'page').
 - * Therefore, your GET variable names should not conflict with the service
 + * The first format is called 'Get' while the second 'Path', which is specified
 + * via {@link setUrlFormat UrlFormat}. For advanced users who want to use
 + * their own URL formats, they can write customized URL management modules
 + * and install the managers as application modules and set {@link setUrlManager UrlManager}.
 + *
 + * The ServiceID in the above URLs is as defined in the application configuration
 + * (e.g. the default page service's service ID is 'page').
 + * As a consequence, your GET variable names should not conflict with the service
   * IDs that your application supports.
   *
 + * THttpRequest also provides the cookies sent by the user, user information such
 + * as his browser capabilities, accepted languages, etc.
 + *
   * By default, THttpRequest is registered with {@link TApplication} as the
   * request module. It can be accessed via {@link TApplication::getRequest()}.
   *
 @@ -60,13 +71,17 @@  class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
  {
  	/**
 -	 * Separator used to separate GET variable name and value when URL format is Path.
 +	 * @var TUrlManager the URL manager module
  	 */
 -	private $_separator=',';
 +	private $_urlManager=null;
  	/**
 -	 * @var boolean whether the module is initialized
 +	 * @var string the ID of the URL manager module
  	 */
 -	private $_initialized=false;
 +	private $_urlManagerID='';
 +	/**
 +	 * @var string Separator used to separate GET variable name and value when URL format is Path.
 +	 */
 +	private $_separator=',';
  	/**
  	 * @var string requested service ID
  	 */
 @@ -87,7 +102,10 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	 * @var string path info of URL
  	 */
  	private $_pathInfo;
 -
 +	/**
 +	 * @var boolean whether the session ID should be kept in cookie only
 +	 */
 +	private $_cookieOnly=false;
  	private $_urlFormat=THttpRequestUrlFormat::Get;
  	private $_services;
  	private $_requestResolved=false;
 @@ -130,6 +148,20 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	 */
  	public function init($config)
  	{
 +		if(empty($this->_urlManagerID))
 +		{
 +			$this->_urlManager=new TUrlManager;
 +			$this->_urlManager->init(null);
 +		}
 +		else
 +		{
 +			$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
 +			if($this->_urlManager===null)
 +				throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
 +			if(!($this->_urlManager instanceof TUrlManager))
 +				throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
 +		}
 +
  		// Fill in default request info when the script is run in command line
  		if(php_sapi_name()==='cli')
  		{
 @@ -140,6 +172,8 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  			$_SERVER['HTTP_USER_AGENT']='';
  		}
 +		$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
 +
  		// Info about server variables:
  		// PHP_SELF contains real URI (w/ path info, w/o query string)
  		// SCRIPT_NAME is the real URI for the requested script (w/o path info and query string)
 @@ -170,12 +204,6 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  				$_COOKIE=$this->stripSlashes($_COOKIE);
  		}
 -		if($this->getUrlFormat()===THttpRequestUrlFormat::Path && ($pathInfo=trim($this->_pathInfo,'/'))!=='')
 -			$this->_items=array_merge($this->parseUrl(),$_POST);
 -		else
 -			$this->_items=array_merge($_GET,$_POST);
 -
 -		$this->_initialized=true;
  		$this->getApplication()->setRequest($this);
  	}
 @@ -215,6 +243,35 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	}
  	/**
 +	 * @return string the ID of the URL manager module
 +	 */
 +	public function getUrlManager()
 +	{
 +		return $this->_urlManagerID;
 +	}
 +
 +	/**
 +	 * Sets the URL manager module.
 +	 * By default, {@link TUrlManager} is used for managing URLs.
 +	 * You may specify a different module for URL managing tasks
 +	 * by loading it as an application module and setting this property
 +	 * with the module ID.
 +	 * @param string the ID of the URL manager module
 +	 */
 +	public function setUrlManager($value)
 +	{
 +		$this->_urlManagerID=$value;
 +	}
 +
 +	/**
 +	 * @return TUrlManager the URL manager module
 +	 */
 +	public function getUrlManagerModule()
 +	{
 +		return $this->_urlManager;
 +	}
 +
 +	/**
  	 * @return THttpRequestUrlFormat the format of URLs. Defaults to THttpRequestUrlFormat::Get.
  	 */
  	public function getUrlFormat()
 @@ -472,105 +529,37 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	}
  	/**
 -	 * Constructs a URL that is recognizable by Prado.
 -	 * You may override this method to provide your own way of URL formatting.
 -	 * If you do so, you may also need to override {@link parseUrl} so that the URL can be properly parsed.
 -	 * The URL is constructed as the following format:
 -	 * /entryscript.php?serviceID=serviceParameter&get1=value1&...
 -	 * If {@link setUrlFormat UrlFormat} is Path, the following format is used instead:
 -	 * /entryscript.php/serviceID/serviceParameter/get1,value1/get2,value2...
 +	 * Constructs a URL that can be recognized by PRADO.
 +	 * The actual construction work is done by the URL manager module.
 +	 * This method may append session information to the generated URL if needed.
 +	 * You may provide your own URL manager module by setting {@link setUrlManager UrlManager}
 +	 * to provide your own URL scheme.
  	 * @param string service ID
  	 * @param string service parameter
  	 * @param array GET parameters, null if not needed
  	 * @param boolean whether to encode the ampersand in URL, defaults to true.
  	 * @param boolean whether to encode the GET parameters (their names and values), defaults to false.
  	 * @return string URL
 -	 * @see parseUrl
 +	 * @see TUrlManager::constructUrl
  	 */
  	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
  	{
 -		$url=$serviceID.'='.$serviceParam;
 -		$amp=$encodeAmpersand?'&':'&';
 -		if(is_array($getItems) || $getItems instanceof Traversable)
 -		{
 -			if($encodeGetItems)
 -			{
 -				foreach($getItems as $name=>$value)
 -				{
 -					if(is_array($value))
 -					{
 -						$name=urlencode($name.'[]');
 -						foreach($value as $v)
 -							$url.=$amp.$name.'='.urlencode($v);
 -					}
 -					else
 -						$url.=$amp.urlencode($name).'='.urlencode($value);
 -				}
 -			}
 -			else
 -			{
 -				foreach($getItems as $name=>$value)
 -				{
 -					if(is_array($value))
 -					{
 -						foreach($value as $v)
 -							$url.=$amp.$name.'[]='.$v;
 -					}
 -					else
 -						$url.=$amp.$name.'='.$value;
 -				}
 -			}
 -		}
 -		if($this->getUrlFormat()===THttpRequestUrlFormat::Path)
 -		{
 -			$url=strtr($url,array($amp=>'/','?'=>'/','='=>$this->_separator));
 -			if(defined('SID') && SID != '' && !((int)ini_get('session.use_cookies')===1 && ((int)ini_get('session.use_only_cookies')===1)))
 -				$url.='?'.SID;
 -			return $this->getApplicationUrl().'/'.$url;
 -		}
 +		$url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
 +		if(defined('SID') && SID != '' && !$this->_cookieOnly)
 +			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&':'&')) . SID;
  		else
 -		{
 -			if(defined('SID') && SID != '' && !((int)ini_get('session.use_cookies')===1 && ((int)ini_get('session.use_only_cookies')===1)))
 -				$url.=$amp.SID;
 -			return $this->getApplicationUrl().'?'.$url;
 -		}
 +			return $url;
  	}
  	/**
 -	 * Parses the request URL and returns an array of input parameters (including GET variables).
 -	 * This method is invoked when the URL format is Path.
 +	 * Parses the request URL and returns an array of input parameters (excluding GET variables).
  	 * You may override this method to support customized URL format.
  	 * @return array list of input parameters, indexed by parameter names
 -	 * @see constructUrl
 +	 * @see TUrlManager::parseUrl
  	 */
  	protected function parseUrl()
  	{
 -		if($this->_pathInfo!=='')
 -		{
 -			$paths=explode('/',$this->_pathInfo);
 -			$getVariables=$_GET;
 -			$serviceID=null;
 -			foreach($paths as $path)
 -			{
 -				if(($path=trim($path))!=='')
 -				{
 -					if(($pos=strpos($path,$this->_separator))!==false)
 -					{
 -						$name=substr($path,0,$pos);
 -						$value=substr($path,$pos+1);
 -						if(($pos=strpos($name,'[]'))!==false)
 -							$getVariables[substr($name,0,$pos)][]=$value;
 -						else
 -							$getVariables[$name]=$value;
 -					}
 -					else
 -						$getVariables[$path]='';
 -				}
 -			}
 -			return $getVariables;
 -		}
 -		else
 -			return $_GET;
 +		return $this->_urlManager->parseUrl();
  	}
  	/**
 @@ -581,10 +570,11 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	 * You may override this method to provide your own way of service resolution.
  	 * @see constructUrl
  	 */
 -	protected function resolveRequest()
 +	public function resolveRequest()
  	{
  		Prado::trace("Resolving request from ".$_SERVER['REMOTE_ADDR'],'System.Web.THttpRequest');
  		$this->_requestResolved=true;
 +		$this->_items=array_merge($_GET,$this->parseUrl(),$_POST);
  		foreach($this->_services as $id)
  		{
  			if($this->contains($id))
 @@ -625,8 +615,6 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	 */
  	public function getServiceID()
  	{
 -		if(!$this->_requestResolved)
 -			$this->resolveRequest();
  		return $this->_serviceID;
  	}
 @@ -644,8 +632,6 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar  	 */
  	public function getServiceParameter()
  	{
 -		if(!$this->_requestResolved)
 -			$this->resolveRequest();
  		return $this->_serviceParam;
  	}
 diff --git a/framework/Web/TUrlManager.php b/framework/Web/TUrlManager.php new file mode 100644 index 00000000..d7938a47 --- /dev/null +++ b/framework/Web/TUrlManager.php @@ -0,0 +1,142 @@ +<?php
 +/**
 + * TUrlManager class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id $
 + * @package System.Web
 + */
 +
 +/**
 + * TUrlManager class
 + *
 + * TUrlManager is the base class for managing URLs that can be
 + * recognized by PRADO applications. It provides the default implementation
 + * for parsing and constructing URLs.
 + *
 + * Derived classes may override {@link constructUrl} and {@link parseUrl}
 + * to provide customized URL schemes.
 + *
 + * By default, {@link THttpRequest} uses TUrlManager as its URL manager.
 + * If you want to use your customized URL manager, load your manager class
 + * as an application module and set {@link THttpRequest::setUrlManager THttpRequest.UrlManager}
 + * with the ID of your URL manager module.
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Web
 + * @since 3.0.6
 + */
 +class TUrlManager extends TModule
 +{
 +	/**
 +	 * Constructs a URL that can be recognized by PRADO.
 +	 *
 +	 * This method provides the actual implementation used by {@link THttpRequest::constructUrl}.
 +	 * Override this method if you want to provide your own way of URL formatting.
 +	 * If you do so, you may also need to override {@link parseUrl} so that the URL can be properly parsed.
 +	 *
 +	 * The URL is constructed as the following format:
 +	 * /entryscript.php?serviceID=serviceParameter&get1=value1&...
 +	 * If {@link THttpRequest::setUrlFormat THttpRequest.UrlFormat} is 'Path',
 +	 * the following format is used instead:
 +	 * /entryscript.php/serviceID/serviceParameter/get1,value1/get2,value2...
 +	 * @param string service ID
 +	 * @param string service parameter
 +	 * @param array GET parameters, null if not provided
 +	 * @param boolean whether to encode the ampersand in URL
 +	 * @param boolean whether to encode the GET parameters (their names and values)
 +	 * @return string URL
 +	 * @see parseUrl
 +	 */
 +	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
 +	{
 +		$url=$serviceID.'='.$serviceParam;
 +		$amp=$encodeAmpersand?'&':'&';
 +		$request=$this->getRequest();
 +		if(is_array($getItems) || $getItems instanceof Traversable)
 +		{
 +			if($encodeGetItems)
 +			{
 +				foreach($getItems as $name=>$value)
 +				{
 +					if(is_array($value))
 +					{
 +						$name=urlencode($name.'[]');
 +						foreach($value as $v)
 +							$url.=$amp.$name.'='.urlencode($v);
 +					}
 +					else
 +						$url.=$amp.urlencode($name).'='.urlencode($value);
 +				}
 +			}
 +			else
 +			{
 +				foreach($getItems as $name=>$value)
 +				{
 +					if(is_array($value))
 +					{
 +						foreach($value as $v)
 +							$url.=$amp.$name.'[]='.$v;
 +					}
 +					else
 +						$url.=$amp.$name.'='.$value;
 +				}
 +			}
 +		}
 +		if($request->getUrlFormat()===THttpRequestUrlFormat::Path)
 +			return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
 +		else
 +			return $request->getApplicationUrl().'?'.$url;
 +	}
 +
 +	/**
 +	 * Parses the request URL and returns an array of input parameters.
 +	 * This mehtod is automatically invoked by {@link THttpRequest} when
 +	 * handling a user request.
 +	 *
 +	 * In general, this method should parse the path info part of the requesting URL
 +	 * and generate an array of name-value pairs according to some scheme.
 +	 * The current implementation deals with both 'Get' and 'Path' URL formats.
 +	 *
 +	 * You may override this method to support customized URL format.
 +	 * @return array list of input parameters, indexed by parameter names
 +	 * @see constructUrl
 +	 */
 +	public function parseUrl()
 +	{
 +		$request=$this->getRequest();
 +		$pathInfo=trim($request->getPathInfo(),'/');
 +		if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $pathInfo!=='')
 +		{
 +			$separator=$request->getUrlParamSeparator();
 +			$paths=explode('/',$pathInfo);
 +			$getVariables=array();
 +			foreach($paths as $path)
 +			{
 +				if(($path=trim($path))!=='')
 +				{
 +					if(($pos=strpos($path,$separator))!==false)
 +					{
 +						$name=substr($path,0,$pos);
 +						$value=substr($path,$pos+1);
 +						if(($pos=strpos($name,'[]'))!==false)
 +							$getVariables[substr($name,0,$pos)][]=$value;
 +						else
 +							$getVariables[$name]=$value;
 +					}
 +					else
 +						$getVariables[$path]='';
 +				}
 +			}
 +			return $getVariables;
 +		}
 +		else
 +			return array();
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/framework/Web/TUrlMapping.php b/framework/Web/TUrlMapping.php index 5bfd8a42..69af7f2f 100644 --- a/framework/Web/TUrlMapping.php +++ b/framework/Web/TUrlMapping.php @@ -10,6 +10,8 @@   * @package System.Web
   */
 +Prado::using('System.Web.TUrlManager');
 +
  /**
   * TUrlMapping Class
   *
 @@ -17,14 +19,13 @@   * particular service and page class. This module must be configured
   * before a service is initialized, thus this module should be configured
   * globally in the <tt>application.xml</tt> file and before any services.
 - *
 - * The mapping format is as follows.
   * <code>
   *  <module id="friendly-url" class="System.Web.TUrlMapping">
   *    <url ServiceParameter="Posts.ViewPost" pattern="post/{id}/?" parameters.id="\d+" />
   *    <url ServiceParameter="Posts.ListPost" pattern="archive/{time}/?" parameters.time="\d{6}" />
   *    <url ServiceParameter="Posts.ListPost" pattern="category/{cat}/?" parameters.cat="\d+" />
   *  </module>
 + *  <module id="request" class="THttpRequest" UrlManager="friendly-url" />
   * </code>
   *
   * See {@link TUrlMappingPattern} for details regarding the mapping patterns.
 @@ -38,14 +39,22 @@   * The mapping can be load from an external file by specifying a configuration
   * file using the {@link setConfigFile ConfigFile} property.
   *
 + * Since TUrlMapping is a URL manager extending from {@link TUrlManager},
 + * you may override {@link TUrlManager::constructUrl} to support your pattern-based
 + * URL scheme.
 + *
   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   * @version $Id$
   * @package System.Web
   * @since 3.0.5
   */
 -class TUrlMapping extends TModule
 +class TUrlMapping extends TUrlManager
  {
  	/**
 +	 * File extension of external configuration file
 +	 */
 +	const CONFIG_FILE_EXT='.xml';
 +	/**
  	 * @var string default pattern class.
  	 */
  	private $_defaultPatternClass='TUrlMappingPattern';
 @@ -58,10 +67,6 @@ class TUrlMapping extends TModule  	 */
  	private $_matched;
  	/**
 -	 * File extension of external configuration file
 -	 */
 -	const CONFIG_FILE_EXT='.xml';
 -	/**
  	 * @var string external configuration file
  	 */
  	private $_configFile=null;
 @@ -74,12 +79,12 @@ class TUrlMapping extends TModule  	 */
  	public function init($xml)
  	{
 +		parent::init($xml);
  		if($this->getRequest()->getRequestResolved())
  			throw new TConfigurationException('urlpath_dispatch_module_must_be_global');
  		if($this->_configFile!==null)
  			$this->loadConfigFile();
  		$this->loadUrlMappings($xml);
 -		$this->resolveMappings();
  	}
  	/**
 @@ -142,10 +147,14 @@ class TUrlMapping extends TModule  	}
  	/**
 -	 * Using the request URL path, find the first matching pattern. If found
 -	 * the matched pattern parameters are used in the Request object.
 +	 * Parses the request URL and returns an array of input parameters.
 +	 * This method overrides the parent implementation.
 +	 * The input parameters do not include GET and POST variables.
 +	 * This method uses the request URL path to find the first matching pattern. If found
 +	 * the matched pattern parameters are used to return as the input parameters.
 +	 * @return array list of input parameters
  	 */
 -	protected function resolveMappings()
 +	public function parseUrl()
  	{
  		$url = $this->getRequest()->getUrl();
  		foreach($this->_patterns as $pattern)
 @@ -153,12 +162,16 @@ class TUrlMapping extends TModule  			$matches = $pattern->getPatternMatches($url);
  			if(count($matches) > 0)
  			{
 -				$this->changeServiceParameters($pattern);
 -				$this->initializeRequestParameters($matches);
  				$this->_matched=$pattern;
 -				break;
 +				$this->changeServiceParameters($pattern);
 +				$params=array();
 +				foreach($matches as $key=>$value)
 +					if(is_string($key))
 +						$params[$key]=$value;
 +				return $params;
  			}
  		}
 +		return array();
  	}
  	/**
 @@ -170,19 +183,6 @@ class TUrlMapping extends TModule  	}
  	/**
 -	 * @param array initialize the Request with matched parameters.
 -	 */
 -	protected function initializeRequestParameters($matches)
 -	{
 -		$request = $this->getRequest();
 -		foreach($matches as $k => $v)
 -		{
 -			if(!is_int($k))
 -				$request->add($k,$v);
 -		}
 -	}
 -
 -	/**
  	 * @param TUrlMappingPattern change the Request service ID and page class.
  	 */
  	protected function changeServiceParameters($pattern)
 | 
