runtime-routing.md 28.9 KB
Newer Older
Qiang Xue committed
1 2
Routing and URL Creation
========================
3

4
When a Yii application starts processing a requested URL, the first step it takes is to parse the URL
Qiang Xue committed
5 6 7 8
into a [route](structure-controllers.md#routes). The route is then used to instantiate the corresponding 
[controller action](structure-controllers.md) to handle the request. This whole process is called *routing*.
 
The reverse process of routing is called *URL creation*, which creates a URL from a given route
9 10
and the associated query parameters. When the created URL is later requested, the routing process can resolve it 
back into the original route and query parameters.
Qiang Xue committed
11 12 13 14
  
The central piece responsible for routing and URL creation is the [[yii\web\UrlManager|URL manager]],
which is registered as the `urlManager` application component. The [[yii\web\UrlManager|URL manager]]
provides the [[yii\web\UrlManager::parseRequest()|parseRequest()]] method to parse an incoming request into
15 16
a route and the associated query parameters and the [[yii\web\UrlManager::createUrl()|createUrl()]] method to
create a URL from a given route and its associated query parameters.
Qiang Xue committed
17 18
 
By configuring the `urlManager` component in the application configuration, you can let your application 
19
recognize arbitrary URL formats without modifying your existing application code. For example, you can 
Qiang Xue committed
20
use the following code to create a URL for the `post/view` action:
21

Qiang Xue committed
22 23 24 25 26 27 28
```php
use yii\helpers\Url;

// Url::to() calls UrlManager::createUrl() to create a URL
$url = Url::to(['post/view', 'id' => 100]);
```

29
Depending on the `urlManager` configuration, the created URL may look like one of the following (or other format). 
30
And if the created URL is requested later, it will still be parsed back into the original route and query parameter value.
Qiang Xue committed
31 32 33 34 35 36 37 38 39 40 41

```
/index.php?r=post/view&id=100
/index.php/post/100
/posts/100
```


## URL Formats <a name="url-formats"></a>

The [[yii\web\UrlManager|URL manager]] supports two URL formats: the default URL format and the pretty URL format.
42

Qiang Xue committed
43
The default URL format uses a query parameter named `r` to represent the route and normal query parameters 
44 45
to represent the query parameters associated with the route. For example, the URL `/index.php?r=post/view&id=100` represents 
the route `post/view` and the `id` query parameter 100. The default URL format does not require any configuration about 
Qiang Xue committed
46 47 48
the [[yii\web\UrlManager|URL manager]] and works in any Web server setup.

The pretty URL format uses the extra path following the entry script name to represent the route and the associated 
49 50
query parameters. For example, the extra path in the URL `/index.php/post/100` is `/post/100` which may represent
the route `post/view` and the `id` query parameter 100 with a proper [[yii\web\UrlManager::rules|URL rule]]. To use
Qiang Xue committed
51 52 53 54 55 56 57 58 59 60
the pretty URL format, you will need to design a set of [[yii\web\UrlManager::rules|URL rules]] according to the actual
requirement about how the URLs should look like.
 
You may switch between the two URL formats by toggling the [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] 
property of the [[yii\web\UrlManager|URL manager]] without changing any other application code.


## Routing <a name="routing"></a>

Routing involves two steps. In the first step, the incoming request is parsed into a route and the associated 
61
query parameters. In the second step, a [controller action](structure-controllers.md) corresponding to the parsed route
Qiang Xue committed
62 63 64
is created to handle the request.

When using the default URL format, parsing a request into a route is as simple as getting the value of a `GET`
65 66 67 68 69
query parameter named `r`. 

When using the pretty URL format, the [[yii\web\UrlManager|URL manager]] will examine the registered
[[yii\web\UrlManager::rules|URL rules]] to find matching one that can resolve the request into a route. 
If such a rule cannot be found, a [[yii\web\NotFoundHttpException]] exception will be thrown. 
Qiang Xue committed
70 71 72 73

Once the request is parsed into a route, it is time to create the controller action identified by the route.
The route is broken down into multiple parts by the slashes in it. For example, `site/index` will be
broken into `site` and `index`. Each part is an ID which may refer to a module, a controller or an action.
74 75
Starting from the first part in the route, the application takes the following steps to create modules (if any),
controller and action:
76

Qiang Xue committed
77 78 79 80 81 82 83 84 85 86 87 88
1. Set the application as the current module.
2. Check if the [[yii\base\Module::controllerMap|controller map]] of the current module contains the current ID.
   If so, a controller object will be created according to the controller configuration found in the map,
   and Step 5 will be taken to handle the rest part of the route.
3. Check if the ID refers to a module listed in the [[yii\base\Module::modules|modules]] property of
   the current module. If so, a module is created according to the configuration found in the module list,
   and Step 2 will be taken to handle the next part of the route under the context of the newly created module.
4. Treat the ID as a controller ID and create a controller object. Do the next step with the rest part of
   the route.
5. The controller looks for the current ID in its [[yii\base\Controller::actions()|action map]]. If found,
   it creates an action according to the configuration found in the map. Otherwise, the controller will
   attempt to create an inline action which is defined by an action method corresponding to the current ID.
89

Qiang Xue committed
90
Among the above steps, if any error occurs, a [[yii\web\NotFoundHttpException]] will be thrown, indicating
91
the failure of the routing process.
92 93 94 95


### Default Route <a name="default-route"></a>

Qiang Xue committed
96
When a request is parsed into an empty route, the so-called *default route* will be used, instead. By default,
Qiang Xue committed
97
the default route is `site/index`,  which refers to the `index` action of the `site` controller. You may 
Qiang Xue committed
98
customize it by configuring the [[yii\web\Application::defaultRoute|defaultRoute]] property of the application
99 100 101
in the application configuration like the following:

```php
Qiang Xue committed
102
[
103 104 105 106 107 108 109 110 111 112 113 114 115
    // ...
    'defaultRoute' => 'main/index',
];
```


### `catchAll` Route <a name="catchall-route"></a>

Sometimes, you may want to put your Web application in maintenance mode temporarily and display the same
informational page for all requests. There are many ways to accomplish this goal. But one of the simplest
ways is to configure the [[yii\web\Application::catchAll]] property like the following in the application configuration:

```php
Qiang Xue committed
116
[
117 118 119 120 121
    // ...
    'catchAll' => ['site/offline'],
];
```

Qiang Xue committed
122 123
With the above configuration, the `site/offline` action will be used to handle all incoming requests.

124
The `catchAll` property should take an array whose first element specifies a route, and
Qiang Xue committed
125
the rest of the elements (name-value pairs) specify the parameters to be [bound to the action](structure-controllers.md#action-parameters).
126 127


Qiang Xue committed
128
## Creating URLs <a name="creating-urls"></a>
129

Qiang Xue committed
130
Yii provides a helper method [[yii\helpers\Url::to()]] to create various kinds of URLs from given routes and 
131
their associated query parameters. For example,
132

Qiang Xue committed
133 134
```php
use yii\helpers\Url;
135

Qiang Xue committed
136 137
// creates a URL to a route: /index.php?r=post/index
echo Url::to(['post/index']);
138

Qiang Xue committed
139 140
// creates a URL to a route with parameters: /index.php?r=post/view&id=100
echo Url::to(['post/view', 'id' => 100]);
141

Qiang Xue committed
142 143 144 145 146 147
// creates an anchored URL: /index.php?r=post/view&id=100#content
echo Url::to(['post/view', 'id' => 100, '#' => 'content']);

// creates an absolute URL: http://www.example.com/index.php?r=post/index
echo Url::to(['post/index'], true);

148
// creates an absolute URL using the https scheme: https://www.example.com/index.php?r=post/index
Qiang Xue committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
echo Url::to(['post/index'], 'https');
```

Note that in the above example, we assume the default URL format is being used. If the pretty URL format is enabled,
the created URLs will be different, according to the [[yii\web\UrlManager::rules|URL rules]] in use. 

The route passed to the [[yii\helpers\Url::to()]] method is context sensitive. It can be either a *relative* route
or an *absolute* route which will be normalized according to the following rules:

- If the route is an empty string, the currently requested [[yii\web\Controller::route|route]] will be used;
- If the route contains no slashes at all, it is considered to be an action ID of the current controller 
  and will be prepended with the [[\yii\web\Controller::uniqueId|uniqueId]] value of the current controller;
- If the route has no leading slash, it is considered to be a route relative to the current module and 
  will be prepended with the [[\yii\base\Module::uniqueId|uniqueId]] value of the current module.

For example, assume the current module is `admin` and the current controller is `post`,

```php
use yii\helpers\Url;

// currently requested route: /index.php?r=admin/post/index
echo Url::to(['']);

// a relative route with action ID only: /index.php?r=admin/post/index
echo Url::to(['index']);

// a relative route: /index.php?r=admin/post/index
echo Url::to(['post/index']);

// an absolute route: /index.php?r=post/index
echo Url::to(['/post/index']);
```

The [[yii\helpers\Url::to()]] method is implemented by calling the [[yii\web\UrlManager::createUrl()|createUrl()]] 
and [[yii\web\UrlManager::createAbsoluteUrl()|createAbsoluteUrl()]] methods of the [[yii\web\UrlManager|URL manager]].
In the next few subsections, we will explain how to configure the [[yii\web\UrlManager|URL manager]] to customize
the format of the created URLs.

The [[yii\helpers\Url::to()]] method also supports creating URLs that are NOT related with particular routes.
Instead of passing an array as its first parameter, you should pass a string in this case. For example,
 
```php
use yii\helpers\Url;

// currently requested URL: /index.php?r=admin/post/index
echo Url::to();

// an aliased URL: http://example.com
Yii::setAlias('@example', 'http://example.com/');
echo Url::to('@example');

// an absolute URL: http://example.com/images/logo.gif
echo Url::to('/images/logo.gif', true);
```

204
Besides the `to()` method, the [[yii\helpers\Url]] helper class also provides several other convenient URL creation 
Qiang Xue committed
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
methods. For example,

```php
use yii\helpers\Url;

// home page URL: /index.php?r=site/index
echo Url::home();

// the base URL, useful if the application is deployed in a sub-folder of the Web root
echo Url::base();

// the canonical URL of the currently requested URL
// see https://en.wikipedia.org/wiki/Canonical_link_element
echo Url::canonical();

// remember the currently requested URL and retrieve it back in later requests
Url::remember();
echo Url::previous();
```


## Using Pretty URLs <a name="using-pretty-urls"></a>

To use pretty URLs, configure the `urlManager` component in the application configuration like the following:

```php
[
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'enableStrictParsing' => true,
            'rules' => [
                // ...
            ],
        ],
    ],
]
```

245 246
The [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] property is mandatory as it toggles the pretty URL format.
The rest of the properties are optional. However, their configuration shown above is most commonly used.
Qiang Xue committed
247 248

* [[yii\web\UrlManager::showScriptName|showScriptName]]: this property determines whether the entry script
249
  should be included in the created URLs. For example, instead of creating a URL `/index.php/post/100`,
250
  by setting this property to be false, a URL `/post/100` will be generated. 
Qiang Xue committed
251 252 253 254 255 256 257 258 259 260
* [[yii\web\UrlManager::enableStrictParsing|enableStrictParsing]]: this property determines whether to enable
  strict request parsing. If strict parsing is enabled, the incoming requested URL must match at least one of 
  the [[yii\web\UrlManager::rules|rules]] in order to be treated as a valid request, or a [[yii\web\NotFoundHttpException]] 
  will be thrown. If strict parsing is disabled, when none of the [[yii\web\UrlManager::rules|rules]] matches
  the requested URL, the path info part of the URL will be treated as the requested route. 
* [[yii\web\UrlManager::rules|rules]]: this property contains a list of rules specifying how to parse and create
  URLs. It is the main property that you should work with in order to create URLs whose format satisfies your
  particular application requirement.

> Note: In order to hide the entry script name in the created URLs, besides setting
larnu committed
261
  [[yii\web\UrlManager::showScriptName|showScriptName]] to be false, you may also need to configure your Web server
Qiang Xue committed
262 263 264 265 266 267 268
  so that it can correctly identify which PHP script should be executed when a requested URL does not explicitly 
  specify one. If you are using Apache Web server, you may refer to the recommended configuration as described in the
  [Installation](start-installation.md#recommended-apache-configuration) section.


### URL Rules <a name="url-rules"></a>

269 270
A URL rule is an instance of [[yii\web\UrlRule]] or its child class. Each URL rule consists of a pattern used 
for matching the path info part of URLs, a route, and a few query parameters. A URL rule can be used to parse a request
271
if its pattern matches the requested URL and a URL rule can be used to create a URL if its route and query parameter 
272 273 274 275 276 277 278 279
names match those that are given. 

When the pretty URL format is enabled, the [[yii\web\UrlManager|URL manager]] uses the URL rules declared in its
[[yii\web\UrlManager::rules|rules]] property to parse incoming requests and create URLs. In particular,
to parse an incoming request, the [[yii\web\UrlManager|URL manager]] examines the rules in the order they are
declared and looks for the *first* rule that matches the requested URL. The matching rule is then used to
parse the URL into a route and its associated parameters. Similarly, to create a URL, the [[yii\web\UrlManager|URL manager]] 
looks for the first rule that matches the given route and parameters and uses that to create a URL.
Qiang Xue committed
280

281 282 283 284 285
You can configure [[yii\web\UrlManager::rules]] as an array with keys being the patterns and values the corresponding
routes. Each pattern-route pair constructs a URL rule. For example, the following [[yii\web\UrlManager::rules|rules]]
configuration declares two URL rules. The first rule matches a URL `posts` and maps it into the route `post/index`.
The second rule matches a URL matching the regular expression `post/(\d+)` and maps it into the route `post/view` and 
a parameter named `id`.
Qiang Xue committed
286 287 288 289 290 291 292 293

```php
[
    'posts' => 'post/index', 
    'post/<id:\d+>' => 'post/view',
]
```

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
> Info: The pattern in a rule is used to match the path info part of a URL. For example, the path info of 
  `/index.php/post/100?source=ad` is `post/100` (the leading and ending slashes are ignored) which matches
  the pattern `post/(\d+)`.

Besides declaring URL rules as pattern-route pairs, you may also declare them as configuration arrays. Each configuration
array is used to configure a single URL rule object. This is often needed when you want to configure other
properties of a URL rule. For example,

```php
[
    // ...other url rules...
    
    [
        'pattern' => 'posts',
        'route' => 'post/index',
        'suffix' => '.json',
    ],
]
```

By default if you do not specify the `class` option for a rule configuration, it will take the default
class [[yii\web\UrlRule]].
Qiang Xue committed
316 317 318 319


### Named Parameters <a name="named-parameters"></a>

320 321 322 323 324 325
A URL rule can be associated with a few named query parameters which are specified in the pattern in the format
of `<ParamName:RegExp>`, where `ParamName` specifies the parameter name and `RegExp` is an optional regular 
expression used to match parameter values. If `RegExp` is not specified, it means the parameter value should be
a string without any slash.

> Note: You can only specify regular expressions for parameters. The rest part of a pattern is considered as plain text.
Qiang Xue committed
326

327 328 329 330
When a rule is used to parse a URL, it will fill the associated parameters with values matching the corresponding
parts of the URL, and these parameters will be made available in `$_GET` later by the `request` application component.
When the rule is used to create a URL, it will take the values of the provided parameters and insert them at the 
places where the parameters are declared.
Qiang Xue committed
331

332
Let's use some examples to illustrate how named parameters work. Assume we have declared the following three URL rules:
Qiang Xue committed
333 334 335 336 337 338 339 340 341

```php
[
    'posts' => 'post/index',
    'post/<id:\d+>' => 'post/view',
    'posts/<year:\d{4}>/<category>' => 'post/index',
]
```

342
When the rules are used to parse URLs:
Qiang Xue committed
343

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
- `/index.php/posts` is parsed into the route `post/index` using the first rule;
- `/index.php/posts/2014/php` is parsed into the route `post/index`, the `year` parameter whose value is 2014
  and the `category` parameter whose value is `php` using the third rule;
- `/index.php/post/100` is parsed into the route `post/view` and the `id` parameter whose value is 100 using
  the second rule;
- `/index.php/posts/php` will cause a [[yii\web\NotFoundHttpException]] when [[yii\web\UrlManager::enableStrictParsing]]
  is true, because it matches none of the patterns. If [[yii\web\UrlManager::enableStrictParsing]] is false (the
  default value), the path info part `posts/php` will be returned as the route.
 
And when the rules are used to create URLs:

- `Url::to(['post/index'])` creates `/index.php/posts` using the first rule;
- `Url::to(['post/index', 'year' => 2014, 'category' => 'php'])` creates `/index.php/posts/2014/php` using the
  third rule;
- `Url::to(['post/view', 'id' => 100])` creates `/index.php/post/100` using the second rule;
- `Url::to(['post/view', 'id' => 100, 'source' => 'ad'])` creates `/index.php/post/100?source=ad` using the second rule.
  Because the `source` parameter is not specified in the rule, it is appended as a query parameter in the created URL.
- `Url::to(['post/index', 'category' => 'php'])` creates `/index.php/post/index?category=php` using none of rules.
  Note that since none of the rules applies, the URL is created by simply appending the route as the path info
  and all parameters as the query string part.
   
Qiang Xue committed
365

366
### Parameterizing Routes <a name="parameterizing-routes"></a>
Qiang Xue committed
367

368 369
You can embed parameter names in the route of a URL rule. This allows a URL rule to be used for matching multiple 
routes. For example, the following rules embed `controller` and `action` parameters in the routes.
Qiang Xue committed
370 371 372 373

```php
[
    '<controller:(post|comment)>/<id:\d+>/<action:(create|update|delete)>' => '<controller>/<action>',
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    '<controller:(post|comment)>/<id:\d+>' => '<controller>/view',
    '<controller:(post|comment)>s' => '<controller>/index',
]
```

To parse a URL `/index.php/comment/100/create`, the first rule will apply, which sets the `controller` parameter to
be `comment` and `action` parameter to be `create`. The route `<controller>/<action>` is thus resolved as `comment/create`.
 
Similarly, to create a URL for the route `comment/index`, the third rule will apply, which creates a URL `/index.php/comments`.

> Info: By parameterizing routes, it is possible to greatly reduce the number of URL rules, which can significantly
  improve the performance of [[yii\web\UrlManager|URL manager]]. 
  
By default, all parameters declared in a rule are required. If a requested URL does not contain a particular parameter, 
or if a URL is being created without a particular parameter, the rule will not apply. To make some of the parameters
optional, you can configure the [[yii\web\UrlRule::defaults|defaults]] property of a rule. Parameters listed in this 
property are optional and will take the specified values when they are not provided. 

In the following rule declaration, the `page` and `tag` parameters are both optional and will take the value of 1 and 
empty string, respectively, when they are not provided. 

```php
[
    // ...other rules...
    [
        'pattern' => 'posts/<page:\d+>/<tag>',
        'route' => 'post/index',
        'defaults' => ['page' => 1, 'tag' => ''],
    ],
Qiang Xue committed
403 404 405
]
```

406 407 408 409 410 411
The above rule can be used to parse or create any of the following URLs:

* `/index.php/posts`: `page` is 1, `tag` is ''.
* `/index.php/posts/2`: `page` is 2, `tag` is ''.
* `/index.php/posts/2/news`: `page` is 2, `tag` is `'news'`.
* `/index.php/posts/news`: `page` is 1, `tag` is `'news'`.
Qiang Xue committed
412

413
Without using optional parameters, you would have to create 4 rules to achieve the same result.
Qiang Xue committed
414 415


416
### Rules with Server Names <a name="rules-with-server-names"></a>
Qiang Xue committed
417

418 419 420 421 422 423 424 425 426 427
It is possible to include Web server names in the patterns of URL rules. This is mainly useful when your application 
should behave differently for different Web server names. For example, the following rules will parse the URL 
`http://admin.example.com/login` into the route `admin/user/login` and `http://www.example.com/login` into `site/login`.

```php
[
    'http://admin.example.com/login' => 'admin/user/login',
    'http://www.example.com/login' => 'site/login',
]
```
Qiang Xue committed
428

429 430
You can also embed parameters in the server names to extract dynamic information from them. For example, the following rule
will parse the URL `http://en.example.com/posts` into the route `post/index` and the parameter `language=en`.
Qiang Xue committed
431 432 433

```php
[
434
    'http://<language:\w+>.example.com/posts' => 'post/index',
Qiang Xue committed
435 436 437
]
```

438
> Note: Rules with server names should NOT include the subfolder of the entry script in their patterns. For example, if the application is under `http://www.example.com/sandbox/blog`, then you should use the pattern
439 440
  `http://www.example.com/posts` instead of `http://www.example.com/sandbox/blog/posts`. This will allow your application
  to be deployed under any directory without the need to change your application code.
Qiang Xue committed
441 442


443
### URL Suffixes <a name="url-suffixes"></a>
Qiang Xue committed
444

445
You may want to add suffixes to the URLs for various purposes. For example, you may add `.html` to the URLs so that they
446 447
look like URLs for static HTML pages; you may also add `.json` to the URLs to indicate the expected content type
of the response. You can achieve this goal by configuring the [[yii\web\UrlManager::suffix]] property like
448
the following in the application configuration:
Qiang Xue committed
449 450

```php
451
[
Qiang Xue committed
452 453
    'components' => [
        'urlManager' => [
454 455 456
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'enableStrictParsing' => true,
Qiang Xue committed
457
            'suffix' => '.html',
458 459 460
            'rules' => [
                // ...
            ],
Qiang Xue committed
461 462
        ],
    ],
463
]
Qiang Xue committed
464 465
```

466
The above configuration will allow the [[yii\web\UrlManager|URL manager]] to recognize requested URLs and also create
467
URLs with `.html` as their suffix.
Qiang Xue committed
468

469
> Tip: You may set `/` as the URL suffix so that the URLs all end with a slash.
Qiang Xue committed
470

471
> Note: When you configure a URL suffix, if a requested URL does not have the suffix, it will be considered as
472
  an unrecognized URL. This is a recommended practice for SEO (search engine optimization).
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
  
Sometimes you may want to use different suffixes for different URLs. This can be achieved by configuring the
[[yii\web\UrlRule::suffix|suffix]] property of individual URL rules. When a URL rule has this property set, it will
override the suffix setting at the [[yii\web\UrlManager|URL manager]] level. For example, the following configuration
contains a customized URL rule which uses `.json` as its suffix instead of the global one `.html`.

```php
[
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'enableStrictParsing' => true,
            'suffix' => '.html',
            'rules' => [
                // ...
                [
                    'pattern' => 'posts',
                    'route' => 'post/index',
                    'suffix' => '.json',
                ],
            ],
        ],
    ],
]
```
Qiang Xue committed
499 500


501
### HTTP Methods <a name="http-methods"></a>
Qiang Xue committed
502

503 504 505 506 507
When implementing RESTful APIs, it is commonly needed that the same URL be parsed into different routes according to
the HTTP methods being used. This can be easily achieved by prefixing the supported HTTP methods to the patterns of
the rules. If a rule supports multiple HTTP methods, separate the method names with commas. For example, the following
rules have the same pattern `post/<id:\d+>` with different HTTP method support. A request for `PUT post/100` will
be parsed into `post/create`, while a request for `GET post/100` will be parsed into `post/view`.
Qiang Xue committed
508 509

```php
510 511 512 513 514 515
[
    'PUT,POST post/<id:\d+>' => 'post/create',
    'DELETE post/<id:\d+>' => 'post/delete',
    'post/<id:\d+>' => 'post/view',
]
```
Qiang Xue committed
516

517 518
> Note: If a URL rule contains HTTP method(s) in its pattern, the rule will only be used for parsing purpose.
  It will be skipped when the [[yii\web\UrlManager|URL manager]] is called to create URLs.
Qiang Xue committed
519

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
> Tip: To simplify the routing of RESTful APIs, Yii provides a special URL rule class [[yii\rest\UrlRule]]
  which is very efficient and supports some fancy features such as automatic pluralization of controller IDs.
  For more details, please refer to the [Routing](rest-routing.md) section about developing RESTful APIs.


### Customizing Rules <a name="customizing-rules"></a>

In the previous examples, URL rules are mainly declared in terms of pattern-route pairs. This is a commonly used
shortcut format. In certain scenarios, you may want to customize a URL rule by configuring its other properties, such
as [[yii\web\UrlRule::suffix]]. This can be done by using a full configuration array to specify a rule. The following
example is extracted from the [URL Suffixes](#url-suffixes) subsection,

```php
[
    // ...other url rules...
    
    [
        'pattern' => 'posts',
        'route' => 'post/index',
        'suffix' => '.json',
Qiang Xue committed
540
    ],
541
]
Qiang Xue committed
542 543
```

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
> Info: By default if you do not specify the `class` option for a rule configuration, it will take the default
  class [[yii\web\UrlRule]].
  

### Adding Rules Dynamically <a name="adding-rules"></a>

URL rules can be dynamically added to the [[yii\web\UrlManager|URL manager]]. This is often needed by redistributable 
[modules](structure-modules.md) which want to manage their own URL rules. In order for the dynamically added rules
to take effect during the routing process, you should add them during the [bootstrapping](runtime-bootstrapping.md)
stage. For modules, this means they should implement [[yii\base\BootstrapInterface]] and add the rules in the
[[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] method like the following:

```php
public function bootstrap($app)
{
    $app->getUrlManager()->addRules([
        // rule declarations here
    ], false);
}
```

Note that you should also list these modules in [[yii\web\Application::bootstrap]] so that they can participate the
[bootstrapping](runtime-bootstrapping.md) process.


### Creating Rule Classes <a name="creating-rules"></a>

Despite the fact that the default [[yii\web\UrlRule]] class is flexible enough for the majority of projects, there 
are situations when you have to create your own rule classes. For example, in a car dealer Web site, you may want 
to support the URL format like `/Manufacturer/Model`, where both `Manufacturer` and `Model` must match some data
stored in a database table. The default rule class will not work here because it relies on statically declared patterns.

We can create the following URL rule class to solve this problem.
Qiang Xue committed
577 578 579 580

```php
namespace app\components;

surgat committed
581 582
use yii\web\UrlRuleInterface;
use yii\base\Object;
Qiang Xue committed
583

surgat committed
584
class CarUrlRule extends Object implements UrlRuleInterface
Qiang Xue committed
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
{

    public function createUrl($manager, $route, $params)
    {
        if ($route === 'car/index') {
            if (isset($params['manufacturer'], $params['model'])) {
                return $params['manufacturer'] . '/' . $params['model'];
            } elseif (isset($params['manufacturer'])) {
                return $params['manufacturer'];
            }
        }
        return false;  // this rule does not apply
    }

    public function parseRequest($manager, $request)
    {
        $pathInfo = $request->getPathInfo();
        if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
            // check $matches[1] and $matches[3] to see
            // if they match a manufacturer and a model in the database
            // If so, set $params['manufacturer'] and/or $params['model']
            // and return ['car/index', $params]
        }
        return false;  // this rule does not apply
    }
}
```

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
And use the new rule class in the [[yii\web\UrlManager::rules]] configuration:

```php
[
    // ...other rules...
    
    [
        'class' => 'app\components\CarUrlRule', 
        // ...configure other properties...
    ],
]
```


## Performance Consideration <a name="performance-consideration"></a>

When developing a complex Web application, it is important to optimize URL rules so that it takes less time to parse
requests and create URLs.

632
By using parameterized routes, you may reduce the number of URL rules, which can significantly improve performance.
633 634

When parsing or creating URLs, [[yii\web\UrlManager|URL manager]] examines URL rules in the order they are declared.
635
Therefore, you may consider adjusting the order of the URL rules so that more specific and/or more commonly used rules are placed before less used ones.
636

637 638 639
If some URL rules share the same prefix in their patterns or routes, you may consider using [[yii\web\GroupUrlRule]]
so that they can be more efficiently examined by [[yii\web\UrlManager|URL manager]] as a group. This is often the case
when your application is composed by modules, each having its own set of URL rules with module ID as their common prefixes.