Changeset 2101

Show
Ignore:
Timestamp:
08/02/2007 08:49:49 AM
Author:
xue
Message:

Fixed #681

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/HISTORY

    r2100 r2101  
    1111ENH: Ticket#667 - Added TFeedService.ContentType property (Qiang) 
    1212ENH: Ticket#678 - Improved DateTimeFormatInfo performance (Stever) 
     13ENH: Ticket#681 - TUrlMapping can construct custom URLs now (Qiang) 
    1314ENH: Added THead requirement check (Qiang) 
    1415CHG: GeSHi is replaced with Text_Highlighter (Christophe) 
  • trunk/framework/Exceptions/messages.txt

    r2096 r2101  
    419419cachesession_cachemodule_inexistent             = TCacheHttpSession.CacheModuleID '{0}' points to a non-existent module. 
    420420cachesession_cachemodule_invalid                = TCacheHttpSession.CacheModuleID '{0}' points to a module that does not implement ICache interface. 
     421 
     422urlmapping_urlmappingpattern_required   = TUrlMapping can only contain TUrlMappingPattern or its child classes. 
     423urlmappingpattern_serviceparameter_required = TUrlMappingPattern.ServiceParameter is required for pattern '{0}'. 
  • trunk/framework/Web/TUrlMapping.php

    r2020 r2101  
    1212 
    1313Prado::using('System.Web.TUrlManager'); 
     14Prado::using('System.Collections.TAttributeCollection'); 
    1415 
    1516/** 
     
    2122 * globally in the <tt>application.xml</tt> file and before any services. 
    2223 * <code> 
     24 *  <module id="request" class="THttpRequest" UrlManager="friendly-url" /> 
    2325 *  <module id="friendly-url" class="System.Web.TUrlMapping"> 
    2426 *    <url ServiceParameter="Posts.ViewPost" pattern="post/{id}/?" parameters.id="\d+" /> 
     
    2628 *    <url ServiceParameter="Posts.ListPost" pattern="category/{cat}/?" parameters.cat="\d+" /> 
    2729 *  </module> 
    28  *  <module id="request" class="THttpRequest" UrlManager="friendly-url" /> 
    2930 * </code> 
    3031 * 
     
    3738 * in particular order. For example, placing the most specific mappings first. 
    3839 * 
    39  * The mapping can be load from an external file by specifying a configuration 
     40 * The mapping can be loaded from an external file by specifying a configuration 
    4041 * file using the {@link setConfigFile ConfigFile} property. 
    4142 * 
     
    4344 * you may override {@link TUrlManager::constructUrl} to support your pattern-based 
    4445 * URL scheme. 
     46 * 
     47 * From PRADO v3.1.1, TUrlMapping also provides support to construct URLs according to 
     48 * the specified the pattern. You may enable this functionality by setting {@link setEnableCustomUrl EnableCustomUrl} to true. 
     49 * When you call THttpRequest::constructUrl() (or via TPageService::constructUrl()), 
     50 * TUrlMapping will examine the available URL mapping patterns using their {@link getServiceParameter ServiceParameter} 
     51 * and {@link getPattern Pattern} properties. A pattern is applied if its 
     52 * {@link getServiceParameter ServiceParameter} matches the service parameter passed 
     53 * to constructUrl() and every parameter in the {@link getPattern Pattern} is found 
     54 * in the GET variables. 
    4555 * 
    4656 * @author Wei Zhuo <weizhuo[at]gmail[dot]com> 
     
    5666        const CONFIG_FILE_EXT='.xml'; 
    5767        /** 
    58          * @var string default pattern class. 
    59          */ 
    60         private $_defaultPatternClass='TUrlMappingPattern'; 
    61         /** 
    6268         * @var TUrlMappingPattern[] list of patterns. 
    6369         */ 
     
    7177         */ 
    7278        private $_configFile=null; 
     79        /** 
     80         * @var boolean whether to enable custom contructUrl 
     81         */ 
     82        private $_customUrl=false; 
     83        /** 
     84         * @var array rules for constructing URLs 
     85         */ 
     86        private $_constructRules=array(); 
     87 
     88        private $_urlPrefix=''; 
    7389 
    7490        /** 
     
    86102                        $this->loadConfigFile(); 
    87103                $this->loadUrlMappings($xml); 
     104                if($this->_urlPrefix==='') 
     105                        $this->_urlPrefix=$this->getRequest()->getApplicationUrl(); 
     106                $this->_urlPrefix=rtrim($this->_urlPrefix,'/'); 
    88107        } 
    89108 
     
    106125 
    107126        /** 
     127         * Returns a value indicating whether to enable custom constructUrl. 
     128         * If true, constructUrl() will make use of the URL mapping rules to 
     129         * construct valid URLs. 
     130         * @return boolean whether to enable custom constructUrl. Defaults to false. 
     131         */ 
     132        public function getEnableCustomUrl() 
     133        { 
     134                return $this->_customUrl; 
     135        } 
     136 
     137        /** 
     138         * Sets a value indicating whether to enable custom constructUrl. 
     139         * If true, constructUrl() will make use of the URL mapping rules to 
     140         * construct valid URLs. 
     141         * @param boolean whether to enable custom constructUrl. 
     142         */ 
     143        public function setEnableCustomUrl($value) 
     144        { 
     145                $this->_customUrl=TPropertyValue::ensureBoolean($value); 
     146        } 
     147 
     148        /** 
     149         * @return string the part that will be prefixed to the constructed URLs. Defaults to the requested script path (e.g. /path/to/index.php for a URL http://hostname/path/to/index.php) 
     150         */ 
     151        public function getUrlPrefix() 
     152        { 
     153                return $this->_urlPrefix; 
     154        } 
     155 
     156        /** 
     157         * @param string the part that will be prefixed to the constructed URLs. This is used by constructUrl() when EnableCustomUrl is set true. 
     158         * @see getUrlPrefix 
     159         */ 
     160        public function setUrlPrefix($value) 
     161        { 
     162                $this->_urlPrefix=$value; 
     163        } 
     164 
     165        /** 
    108166         * @return string external configuration file. Defaults to null. 
    109167         */ 
     
    134192                { 
    135193                        $properties=$url->getAttributes(); 
    136                         $class=$properties->remove('class'); 
    137                         if($class===null) 
    138                                 $class = $this->_defaultPatternClass; 
    139                         $pattern = Prado::createComponent($class); 
     194                        if(($class=$properties->remove('class'))===null) 
     195                                $class='TUrlMappingPattern'; 
     196                        $pattern = Prado::createComponent($class,$this); 
    140197                        if(!($pattern instanceof TUrlMappingPattern)) 
    141                                 throw new TConfigurationException('urlpath_dispatch_invalid_pattern_class'); 
     198                                throw new TConfigurationException('urlmapping_urlmappingpattern_required'); 
    142199                        foreach($properties as $name=>$value) 
    143200                                $pattern->setSubproperty($name,$value); 
    144201                        $this->_patterns[] = $pattern; 
    145202                        $pattern->init($url); 
     203 
     204                        $key=$pattern->getServiceID().':'.$pattern->getServiceParameter(); 
     205                        $this->_constructRules[$key][]=$pattern; 
    146206                } 
    147207        } 
     
    176236 
    177237        /** 
     238         * Constructs a URL that can be recognized by PRADO. 
     239         * 
     240         * This method provides the actual implementation used by {@link THttpRequest::constructUrl}. 
     241         * Override this method if you want to provide your own way of URL formatting. 
     242         * If you do so, you may also need to override {@link parseUrl} so that the URL can be properly parsed. 
     243         * 
     244         * The URL is constructed as the following format: 
     245         * /entryscript.php?serviceID=serviceParameter&get1=value1&... 
     246         * If {@link THttpRequest::setUrlFormat THttpRequest.UrlFormat} is 'Path', 
     247         * the following format is used instead: 
     248         * /entryscript.php/serviceID/serviceParameter/get1,value1/get2,value2... 
     249         * @param string service ID 
     250         * @param string service parameter 
     251         * @param array GET parameters, null if not provided 
     252         * @param boolean whether to encode the ampersand in URL 
     253         * @param boolean whether to encode the GET parameters (their names and values) 
     254         * @return string URL 
     255         * @see parseUrl 
     256         * @since 3.1.1 
     257         */ 
     258        public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems) 
     259        { 
     260                if(!$this->_customUrl || !(is_array($getItems) || ($getItems instanceof Traversable))) 
     261                        return parent::constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems); 
     262 
     263                $key=$serviceID.':'.$serviceParam; 
     264                if(isset($this->_constructRules[$key])) 
     265                { 
     266                        foreach($this->_constructRules[$key] as $rule) 
     267                        { 
     268                                if($rule->supportCustomUrl($getItems)) 
     269                                        return $rule->constructUrl($getItems,$encodeAmpersand,$encodeGetItems); 
     270                        } 
     271                } 
     272                return parent::constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems); 
     273        } 
     274 
     275        /** 
    178276         * @return TUrlMappingPattern the matched pattern, null if not found. 
    179277         */ 
     
    252350         * @var string url pattern to match. 
    253351         */ 
    254         private $_pattern
     352        private $_pattern=''
    255353        /** 
    256354         * @var TMap parameter regular expressions. 
     
    260358         * @var string regular expression pattern. 
    261359         */ 
    262         private $_regexp
     360        private $_regexp=''
    263361        /** 
    264362         * @var boolean case sensitive matching, default is true 
     
    266364        private $_caseSensitive=true; 
    267365 
    268         public function __construct() 
    269         { 
    270                 $this->_parameters = Prado::createComponent('System.Collections.TAttributeCollection'); 
     366        private $_customUrl=true; 
     367 
     368        private $_manager; 
     369 
     370        public function __construct(TUrlManager $manager) 
     371        { 
     372                $this->_manager=$manager; 
     373                $this->_parameters=new TAttributeCollection; 
     374                $this->_parameters->setCaseSensitive(true); 
     375        } 
     376 
     377        public function getManager() 
     378        { 
     379                return $this->_manager; 
    271380        } 
    272381 
     
    278387        public function init($config) 
    279388        { 
    280                 $body = trim($config->getValue()); 
    281                 if(strlen($body)>0) 
     389                if(($body=trim($config->getValue()))!=='') 
    282390                        $this->setRegularExpression($body); 
    283                 if(is_null($this->_serviceParameter)) 
    284                 { 
    285                         throw new TConfigurationException( 
    286                                 'dispatcher_url_service_parameter_missing', $this->getPattern()); 
    287                 } 
     391                if($this->_serviceParameter===null) 
     392                        throw new TConfigurationException('urlmappingpattern_serviceparameter_required', $this->getPattern()); 
    288393        } 
    289394 
     
    358463 
    359464        /** 
    360          * @return string url pattern to match. 
     465         * @return string url pattern to match. Defaults to ''. 
    361466         */ 
    362467        public function getPattern() 
     
    413518        public function getPatternMatches($url) 
    414519        { 
    415                 $path = $url->getPath(); 
    416520                $matches=array(); 
    417                 $pattern = $this->getRegularExpression(); 
    418                 if($pattern === null) 
    419                         $pattern = $this->getParameterizedPattern(); 
    420                 preg_match($pattern, $path, $matches); 
     521                if(($pattern=$this->getRegularExpression())==='') 
     522                        $pattern=$this->getParameterizedPattern(); 
     523                preg_match($pattern,$url->getPath(),$matches); 
    421524                return $matches; 
    422525        } 
     
    432535                return $modifiers; 
    433536        } 
     537 
     538        /** 
     539         * Returns a value indicating whether to use this pattern to construct URL. 
     540         * @return boolean whether to enable custom constructUrl. Defaults to true. 
     541         * @since 3.1.1 
     542         */ 
     543        public function getEnableCustomUrl() 
     544        { 
     545                return $this->_customUrl; 
     546        } 
     547 
     548        /** 
     549         * Sets a value indicating whether to enable custom constructUrl using this pattern 
     550         * @param boolean whether to enable custom constructUrl. 
     551         */ 
     552        public function setEnableCustomUrl($value) 
     553        { 
     554                $this->_customUrl=TPropertyValue::ensureBoolean($value); 
     555        } 
     556 
     557        /** 
     558         * @param array list of GET items to be put in the constructed URL 
     559         * @return boolean whether this pattern IS the one for constructing the URL with the specified GET items. 
     560         * @since 3.1.1 
     561         */ 
     562        public function supportCustomUrl($getItems) 
     563        { 
     564                if(!$this->_customUrl || $this->getPattern()==='') 
     565                        return false; 
     566                foreach($this->_parameters as $key=>$value) 
     567                        if(!isset($getItems[$key])) 
     568                                return false; 
     569 
     570                return true; 
     571        } 
     572 
     573        /** 
     574         * Constructs a URL using this pattern. 
     575         * @param array list of GET variables 
     576         * @param boolean whether the ampersand should be encoded in the constructed URL 
     577         * @param boolean whether the GET variables should be encoded in the constructed URL 
     578         * @return string the constructed URL 
     579         * @since 3.1.1 
     580         */ 
     581        public function constructUrl($getItems,$encodeAmpersand,$encodeGetItems) 
     582        { 
     583                $extra=array(); 
     584                $replace=array(); 
     585                // for the GET variables matching the pattern, put them in the URL path 
     586                foreach($getItems as $key=>$value) 
     587                { 
     588                        if($encodeGetItems) 
     589                                $value=urlencode($value); 
     590                        if($this->_parameters->contains($key)) 
     591                                $replace['{'.$key.'}']=$value; 
     592                        else 
     593                                $extra[$key]=$value; 
     594                } 
     595 
     596                $url=$this->_manager->getUrlPrefix().'/'.trim(strtr($this->getPattern(),$replace),'/'); 
     597 
     598                // for the rest of the GET variables, put them in the query string 
     599                if(count($extra)>0) 
     600                { 
     601                        $url2=''; 
     602                        $amp=$encodeAmpersand?'&amp;':'&'; 
     603                        if($encodeGetItems) 
     604                        { 
     605                                foreach($extra as $name=>$value) 
     606                                { 
     607                                        if(is_array($value)) 
     608                                        { 
     609                                                $name=urlencode($name.'[]'); 
     610                                                foreach($value as $v) 
     611                                                        $url2.=$amp.$name.'='.urlencode($v); 
     612                                        } 
     613                                        else 
     614                                                $url2.=$amp.urlencode($name).'='.urlencode($value); 
     615                                } 
     616                        } 
     617                        else 
     618                        { 
     619                                foreach($extra as $name=>$value) 
     620                                { 
     621                                        if(is_array($value)) 
     622                                        { 
     623                                                foreach($value as $v) 
     624                                                        $url2.=$amp.$name.'[]='.$v; 
     625                                        } 
     626                                        else 
     627                                                $url2.=$amp.$name.'='.$value; 
     628                                } 
     629                        } 
     630                        $url=$url.'?'.substr($url2,strlen($amp)); 
     631                } 
     632                return $url; 
     633        } 
    434634} 
    435635