Creating URL rules for static pages
A website typically contains some static pages. Usually, they include /about
, /contact
, /tos
, and so on, and it is common to handle these pages in a single controller action. Let's find a way to create URL rules for these types of pages.
Getting ready
- Create a fresh Yii application using
yiic webapp
as described in the official guide and find yourprotected/config/main.php
file. It should contain the following:// application components 'components'=>array( … // uncomment the following to enable URLs in path-format /* 'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ), ),
- Delete everything from
rules
as we are going to start from scratch. - In your
protected/controllers
directory, createWebsiteController.php
with the following code:class WebsiteController extends CController { public function actionPage($alias) { echo "Page is $alias."; } }
- Configure your application server to use clean URLs. If you are using Apache with
mod_rewrite
andAllowOverride
turned on, you should add the following lines to the.htaccess
file under yourwebroot
folder:Options +FollowSymLinks IndexIgnore */* RewriteEngine on # if a directory or a file exists, use it directly RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # otherwise forward it to index.php RewriteRule . index.php
How to do it...
The most straightforward way is to define a rule for each page, as follows:
'<alias:about>' => 'website/page', '<alias:contact>' => 'website/page', '<alias:tos>' => 'website/page',
Using regular expressions, we can compact it to a single rule:
'<alias:(about|contact|tos)>' => 'website/page',
Now, what if we want the URL to be /tos
and an alias
parameter to be terms_of_service
?
No problem, we can use default parameters to achieve it:
'tos' => array('website/page', 'defaultParams' => array('alias' => 'terms_of_service')),
OK. What if we have many pages and want to be able to dynamically create pages without adding more rules or changing existing ones?
We can achieve this with the following rule:
'<alias>' => 'website/page'
As this rule matches everything, we need to place it last, so it won't affect all other rules. In addition, default rules with one slug, such as controller name, will stop working. To overcome this issue, we need to add default rules, which we deleted in the Getting ready section of this recipe.
How it works...
Let's read the rules we just wrote.
'<alias:about>' => 'website/page',
If the URL is /about
, then pass it as the alias
parameter to website/page
.
'<alias:(about|contact|tos)>' => 'website/page',
If the URL is /about
or /contact
or /tos
, then pass it as the alias
parameter to website/page
.
'tos' => array('website/page', 'defaultParams' => array('alias' => 'terms_of_service')),
When the URL is /tos
, pass terms_of_service
as the alias
parameter value.
This rule is a bit special because it uses the default parameter option. The default parameter allows you to set a value that will be used if a parameter with a name specified is omitted. When you need to specify an option for the rule, you should use an array
notation:
'pattern' => array('internal/route', 'option' => 'value', 'option' => 'value', …),
As the last step we've re-added default rules:
'<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
These are matching common URLs such as /user/123
, /user/edit/123
, or /user/add
. The reason for adding these again is the fact that the <alias>
rule matches everything. That means the URL manager will always stop at this rule and will never try to apply a default convention. In order to get it back we should put default rules before <alias>
.
See also
- The Configuring URL rules recipe
- The Using regular expressions in URL rules recipe