URL Mapping (Friendly URLs)

API Manual

The TUrlMapping module allows PRADO to construct and recognize friendly URLs based on specific patterns.

TUrlMapping consists of a list of URL patterns which are used to match against the currently requested URL. The first matching pattern will then be used to decompose the URL into request parameters (accessible via $this->Request['paramname']). The patterns can also be used to construct customized URLs. In this case, the parameters in an applied pattern will be replaced with the corresponding GET variable values.

To use TUrlMapping, one must set the UrlManager property of the THttpRequest module as the TUrlMapping module ID. See following for an example,

<modules>
		<module id="request" class="THttpRequest" UrlManager="friendly-url" />
		<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>
</modules>

The above example is part of the application configuration of the blog demo in the PRADO release. It enables recognition of the following URL formats:

  • /index.php/post/123 is recognized as /index.php?page=Posts.ViewPost&id=123
  • /index.php/archive/200605 is recognized as /index.php?page=Posts.ListPost&time=200605
  • /index.php/category/2 is recognized as /index.php?page=Posts.ListPost&cat=2

The ServiceParameter and ServiceID (the default ID is 'page') set the service parameter and service ID, respectively, of the Request module. The service parameter for the TPageService service is the Page class name, e.g., for an URL "index.php?page=Home", "page" is the service ID and the service parameter is "Home". Other services may use the service parameter and ID differently. See Services for further details.

Info: The TUrlMapping must be configured before the request module resolves the request. This means delcaring the TUrlMapping outside of the <services> element in the application configuration. Specifying the mappings in the per directory config.xml is not supported.

Specifying URL Patterns

TUrlMapping enables recognition of customized URL formats based on a list prespecified of URL patterns. Each pattern is specified in a <url> tag.

The Pattern and Parameters attribute values are regular expression patterns that determine the mapping criteria. The Pattern property takes a regular expression with parameter names enclosed between a left brace '{' and a right brace '}'. The patterns for each parameter can be set using Parameters attribute collection. For example,

<url ServiceParameter="ArticleView" pattern="articles/{year}/{month}/{day}"
	parameters.year="\d{4}" parameters.month="\d{2}" parameters.day="\d+" />

The example is equivalent to the following regular expression (it uses the "named group" feature in regular expressions available in PHP):
<url ServiceParameter="ArticleView"><![CDATA[
	#articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)#u
]]></url>

In the above example, the pattern contains 3 parameters named "year", "month" and "day". The pattern for these parameters are, respectively, "\d{4}" (4 digits), "\d{2}" (2 digits) and "\d+" (1 or more digits). Essentially, the Parameters attribute name and values are used as substrings in replacing the placeholders in the Pattern string to form a complete regular expression string.

For simple (not parameterized) regular expressions you can use the RegularExpression property:
<url ServiceParameter="ArticleView"
	RegularExpression="/articles\/best-of/u" />
Note: If you intended to use the RegularExpression property or regular expressions in CDATA sections, notice that you need to escape the slash, if you are using the slash as regular expressions delimiter.
If you are using the "CDATA section" version all whitespaces like \n, \t, \r and so on will be removed automaticly.

Following from the above pattern example, an URL http://example.com/index.php/articles/2006/07/21 will be matched and valid. However, http://example.com/index.php/articles/2006/07/hello is not valid since the day parameter pattern is not satisfied. In the default TUrlMappingPattern class, the pattern is matched against the PATH_INFO part of the URL only. For example, only the /articles/2006/07/21 portion of the URL is considered.

The mapped request URL is equivalent to index.php?page=ArticleView&year=2006&month=07&day=21. The request parameter values are available through the standard Request object. For example, $this->Request['year'].

The URL mapping are evaluated in order they are placed and only the first pattern that matches the URL will be used. Cascaded mapping can be achieved by placing the URL mappings in particular order. For example, placing the most specific mappings first.

Since version 3.1.4, Prado also provides wildcard patterns to use friendly URLs for a bunch of pages in a directory with a single rule. Therefore you can use the {*} wildcard in your pattern to let Prado know, where to find the ServiceID in your request URL. You can also specify parameters with these patterns if a lot of pages share common parameters.

<url ServiceParameter="Posts.*" pattern="posts/{*}/{id}" parameters.id="\d+" />
<url ServiceParameter="Posts.*" pattern="posts/{*}" />
<url ServiceParameter="Static.Info.*" pattern="info/{*}" />

With these rules, any of the following URLs will be recognized:

  • /index.php/post/ViewPost/123 is recognized as /index.php?page=Posts.ViewPost&id=123
  • /index.php/post/ListPost/123 is recognized as /index.php?page=Posts.ListPost&id=123
  • /index.php/post/ListPost/123 is recognized as /index.php?page=Posts.ListPost&id=123
  • /index.php/post/MyPost is recognized as /index.php?page=Posts.MyPost
  • /index.php/info/Conditions is recognized as /index.php?page=Static.Info.Conditions
  • /index.php/info/About is recognized as /index.php?page=Static.Info.About

As above, put more specific rules before more common rules as the first matching rule will be used.

To make configuration of friendly URLs for multiple pages even easier, you can also use UrlFormat="Path" in combination with wildcard patterns. In fact, this feature only is available in combination with wildcard rules:

<url ServiceParameter="user.admin.*" pattern="admin/{*}" UrlFormat="Path"/>
<url ServiceParameter="*" pattern="{*}" UrlFormat="Path" />

Parameters will get appended to the specified patterns as name/value pairs, separated by a "/". (You can change the separator character with UrlParamSeparator.)

  • /index.php/list/cat/15/month/12 is recognized as /index.php?page=list&cat=15&month=12
  • /index.php/edit/id/12 is recognized as /index.php?page=list&id=12
  • /index.php/show/name/foo is recognized as /index.php?page=show&name=foo
  • /index.php/admin/edit/id/12 is recognized as /index.php?page=user.admin.edit&id=12

Constructing Customized URLs

Since version 3.1.1, TUrlMapping starts to support constructing customized URLs based on the provided patterns. To enable this feature, set TUrlMapping.EnableCustomUrl to true. When THttpRequest.constrcutUrl() is invoked, the actual URL construction work will be delegated to a matching TUrlMappingPattern instance. It replaces the parameters in the pattern with the corresponding GET variables passed to constructUrl().

A matching pattern is one whose ServiceID and ServiceParameter properties are the same as those passed to constructUrl() and whose named parameters are found in the GET variables. For example, constructUrl('Posts.ListPost',array('cat'=>2)) will use the third pattern in the above example.

By default, TUrlMapping will construct URLs prefixed with the currently requesting PHP script path, such as /path/to/index.php/article/3. Users may change this behavior by explicitly specifying the URL prefix through its UrlPrefix property. For example, if the Web server configuration treats index.php as the default script, we can set UrlPrefix as /path/to and the constructed URL will look like /path/to/article/3.

Note: If you use constructUrl() with string parameters that contain slashes ("/") they will get encoded to %2F. By default most Apache installations give a "404 Not found" if a URL contains a %2F. You can add AllowEncodedSlashes On to your VirtualHost configuration to resolve this. (Available since Apache 2.0.46).