Commit 2b842ecc by Alexander Makarov

Moded URL management methods from controller to Url helper, updated docs

parent 1276970c
...@@ -51,20 +51,30 @@ examples may also output: ...@@ -51,20 +51,30 @@ examples may also output:
* `http://www.example.com/blog/post/index/` * `http://www.example.com/blog/post/index/`
* `http://www.example.com/index.php?r=blog/post/index` * `http://www.example.com/index.php?r=blog/post/index`
Inside a web application controller, you can use the controller's `createUrl` shortcut method. Unlike the global In order to simplify URL creation there is [[yii\helpers\Url]] helper that is able to do the following:
`createUrl` method, the controller version is context sensitive:
```php ```php
echo $this->createUrl(''); // currently active route use yii\helpers\Url;
echo $this->createUrl(['view', 'id' => 'contact']); // same controller, different action
echo $this->createUrl('post/index'); // same module, different controller and action echo Url::to(''); // currently active URL
echo $this->createUrl('/site/index'); // absolute route no matter what controller is making this call
echo $this->createurl('hi-tech'); // url for the case sensitive action `actionHiTech` of the current controller echo Url::toRoute(['view', 'id' => 'contact']); // same controller, different action
echo $this->createurl(['/date-time/fast-forward', 'id' => 105]); // url for action the case sensitive controller, `DateTimeController::actionFastForward` echo Url::toRoute('post/index'); // same module, different controller and action
echo Url::toRoute('/site/index'); // absolute route no matter what controller is making this call
echo Url::toRoute('hi-tech'); // url for the case sensitive action `actionHiTech` of the current controller
echo Url::toRoute(['/date-time/fast-forward', 'id' => 105]); // url for action the case sensitive controller, `DateTimeController::actionFastForward`
echo Url::to('@web'); // get URL from alias
echo Url::canonical(); // get canonical URL for the curent page
echo Url::home(); // get home URL
Url::remember(); // save URL to be used later
Url::previous(); // get previously saved URL
``` ```
> **Tip**: In order to generate URL with a hashtag, for example `/index.php?r=site/page&id=100#title`, you need to > **Tip**: In order to generate URL with a hashtag, for example `/index.php?r=site/page&id=100#title`, you need to
specify the parameter named `#` using `$this->createUrl(['post/read', 'id' => 100, '#' => 'title'])`. specify the parameter named `#` using `Url::to(['post/read', 'id' => 100, '#' => 'title'])`.
Customizing URLs Customizing URLs
---------------- ----------------
...@@ -114,21 +124,25 @@ Let's use some examples to explain how URL rules work. We assume that our rule s ...@@ -114,21 +124,25 @@ Let's use some examples to explain how URL rules work. We assume that our rule s
] ]
``` ```
- Calling `$this->createUrl('post/list')` generates `/index.php/posts`. The first rule is applied. - Calling `Url::toRoute('post/list')` generates `/index.php/posts`. The first rule is applied.
- Calling `$this->createUrl(['post/read', 'id' => 100])` generates `/index.php/post/100`. The second rule is applied. - Calling `Url::toRoute(['post/read', 'id' => 100])` generates `/index.php/post/100`. The second rule is applied.
- Calling `$this->createUrl(['post/read', 'year' => 2008, 'title' => 'a sample post'])` generates - Calling `Url::toRoute(['post/read', 'year' => 2008, 'title' => 'a sample post'])` generates
`/index.php/post/2008/a%20sample%20post`. The third rule is applied. `/index.php/post/2008/a%20sample%20post`. The third rule is applied.
- Calling `$this->createUrl('post/read')` generates `/index.php/post/read`. None of the rules is applied, convention is used - Calling `Url::toRoute('post/read')` generates `/index.php/post/read`. None of the rules is applied, convention is used
instead. instead.
In summary, when using `createUrl` to generate a URL, the route and the `GET` parameters passed to the method are used to In summary, when using `createUrl` to generate a URL, the route and the `GET` parameters passed to the method are used to
decide which URL rule to be applied. If every parameter associated with a rule can be found in the `GET` parameters passed decide which URL rule to be applied. If every parameter associated with a rule can be found in the `GET` parameters passed
to `createUrl`, and if the route of the rule also matches the route parameter, the rule will be used to generate the URL. to `createUrl`, and if the route of the rule also matches the route parameter, the rule will be used to generate the URL.
If the `GET` parameters passed to `createUrl` are more than those required by a rule, the additional parameters will appear in the query string. For example, if we call `$this->createUrl('post/read', ['id' => 100, 'year' => 2008])`, we will obtain `/index.php/post/100?year=2008`. If the `GET` parameters passed to `Url::toRoute` are more than those required by a rule, the additional parameters will
appear in the query string. For example, if we call `Url::toRoute(['post/read', 'id' => 100, 'year' => 2008])`, we will
obtain `/index.php/post/100?year=2008`.
As we mentioned earlier, the other purpose of URL rules is to parse the requesting URLs. Naturally, this is an inverse process of URL creation. For example, when a user requests for `/index.php/post/100`, the second rule in the above example will apply, which resolves in the route `post/read` and the `GET` parameter `['id' => 100]` (accessible via As we mentioned earlier, the other purpose of URL rules is to parse the requesting URLs. Naturally, this is an inverse
`Yii::$app->request->getQueryParam('id')`). process of URL creation. For example, when a user requests for `/index.php/post/100`, the second rule in the above example
will apply, which resolves in the route `post/read` and the `GET` parameter `['id' => 100]` (accessible via
`Yii::$app->request->get('id')`).
### Parameterizing Routes ### Parameterizing Routes
......
...@@ -191,7 +191,11 @@ Yii Framework 2 Change Log ...@@ -191,7 +191,11 @@ Yii Framework 2 Change Log
- Chg #2544: Changed `DetailView`'s `name:format:label` to `attribute:format:label` to match `GridView` (samdark) - Chg #2544: Changed `DetailView`'s `name:format:label` to `attribute:format:label` to match `GridView` (samdark)
- Chg #2603: `yii\base\ErrorException` now extends `\ErrorException` (samdark) - Chg #2603: `yii\base\ErrorException` now extends `\ErrorException` (samdark)
- Chg #2629: `Module::controllerPath` is now read only, and all controller classes must be namespaced under `Module::controllerNamespace`. (qiangxue) - Chg #2629: `Module::controllerPath` is now read only, and all controller classes must be namespaced under `Module::controllerNamespace`. (qiangxue)
- Chg #2630: `yii\heplers\Html::url` removed (samdark) - Chg #2630: API changes for URLs generation (samdark, qiangxue, cebe)
- Added `yii\helpers\Url`.
- Removed `yii\heplers\Html::url`, use `yii\helpers\Url::to` instead.
- Removed `yii\web\Controller::createUrl` and `yii\web\Controller::createAbsoluteUrl`, use `yii\helpers::toRoute` instead.
- Removed `yii\web\Controller::getCanonicalUrl`, use `yii\helpers::canonical` instead.
- Chg: Renamed `yii\jui\Widget::clientEventsMap` to `clientEventMap` (qiangxue) - Chg: Renamed `yii\jui\Widget::clientEventsMap` to `clientEventMap` (qiangxue)
- Chg: Renamed `ActiveRecord::getPopulatedRelations()` to `getRelatedRecords()` (qiangxue) - Chg: Renamed `ActiveRecord::getPopulatedRelations()` to `getRelatedRecords()` (qiangxue)
- Chg: Renamed `attributeName` and `className` to `targetAttribute` and `targetClass` for `UniqueValidator` and `ExistValidator` (qiangxue) - Chg: Renamed `attributeName` and `className` to `targetAttribute` and `targetClass` for `UniqueValidator` and `ExistValidator` (qiangxue)
...@@ -231,7 +235,6 @@ Yii Framework 2 Change Log ...@@ -231,7 +235,6 @@ Yii Framework 2 Change Log
- New #1956: Implemented test fixture framework (qiangxue) - New #1956: Implemented test fixture framework (qiangxue)
- New #2149: Added `yii\base\DynamicModel` to support ad-hoc data validation (qiangxue) - New #2149: Added `yii\base\DynamicModel` to support ad-hoc data validation (qiangxue)
- New #2360: Added `AttributeBehavior` and `BlameableBehavior`, and renamed `AutoTimestamp` to `TimestampBehavior` (lucianobaraglia, qiangxue) - New #2360: Added `AttributeBehavior` and `BlameableBehavior`, and renamed `AutoTimestamp` to `TimestampBehavior` (lucianobaraglia, qiangxue)
- New #2630: Added `yii\helpers\Url` (samdark)
- New: Yii framework now comes with core messages in multiple languages - New: Yii framework now comes with core messages in multiple languages
- New: Added yii\codeception\DbTestCase (qiangxue) - New: Added yii\codeception\DbTestCase (qiangxue)
......
...@@ -26,6 +26,14 @@ class BaseUrl ...@@ -26,6 +26,14 @@ class BaseUrl
* @param array|string $route route as a string or route and parameters in form of * @param array|string $route route as a string or route and parameters in form of
* ['route', 'param1' => 'value1', 'param2' => 'value2']. * ['route', 'param1' => 'value1', 'param2' => 'value2'].
* *
* If there is a controller running relative routes are recognized:
*
* - If the route is an empty string, the current [[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 [[uniqueId]];
* - 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 module's uniqueId.
*
* In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used. * In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used.
* *
* @param string $schema URI schema to use. If specified absolute URL with the schema specified is returned. * @param string $schema URI schema to use. If specified absolute URL with the schema specified is returned.
...@@ -39,10 +47,36 @@ class BaseUrl ...@@ -39,10 +47,36 @@ class BaseUrl
throw new InvalidParamException('$route should contain at least one element.'); throw new InvalidParamException('$route should contain at least one element.');
} }
if (Yii::$app->controller instanceof \yii\web\Controller) { if (Yii::$app->controller instanceof \yii\web\Controller) {
return $schema === null ? Yii::$app->controller->createUrl($route) : Yii::$app->controller->createAbsoluteUrl($route, $schema); $route[0] = static::getNormalizedRoute($route[0]);
} else { }
return $schema === null ? Yii::$app->getUrlManager()->createUrl($route) : Yii::$app->getUrlManager()->createAbsoluteUrl($route, $schema); return $schema === null ? Yii::$app->getUrlManager()->createUrl($route) : Yii::$app->getUrlManager()->createAbsoluteUrl($route, $schema);
} }
/**
* Normalizes route making it suitable for UrlManager. Absolute routes are staying as is
* while relative routes are converted to absolute routes.
*
* A relative route is a route without a leading slash, such as "view", "post/view".
*
* - If the route is an empty string, the current [[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 [[uniqueId]];
* - 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 module's uniqueId.
*
* @param string $route the route. This can be either an absolute route or a relative route.
* @return string normalized route suitable for UrlManager
*/
private static function getNormalizedRoute($route)
{
if (strpos($route, '/') === false) {
// empty or an action ID
$route = $route === '' ? Yii::$app->controller->getRoute() : Yii::$app->controller->getUniqueId() . '/' . $route;
} elseif ($route[0] !== '/') {
// relative to module
$route = ltrim(Yii::$app->controller->module->getUniqueId() . '/' . $route, '/');
}
return $route;
} }
/** /**
...@@ -108,7 +142,7 @@ class BaseUrl ...@@ -108,7 +142,7 @@ class BaseUrl
* @param string $url URL to remember. Default is current URL. * @param string $url URL to remember. Default is current URL.
* @param string $name Name to use to remember URL. Defaults to `yii\web\User::returnUrlParam`. * @param string $name Name to use to remember URL. Defaults to `yii\web\User::returnUrlParam`.
*/ */
public function remember($url = '', $name = null) public static function remember($url = '', $name = null)
{ {
if ($url === '') { if ($url === '') {
$url = Yii::$app->getRequest()->getUrl(); $url = Yii::$app->getRequest()->getUrl();
...@@ -127,7 +161,7 @@ class BaseUrl ...@@ -127,7 +161,7 @@ class BaseUrl
* @param string $name Name used to remember URL. Defaults to `yii\web\User::returnUrlParam`. * @param string $name Name used to remember URL. Defaults to `yii\web\User::returnUrlParam`.
* @return string URL * @return string URL
*/ */
public function previous($name = null) public static function previous($name = null)
{ {
if ($name === null) { if ($name === null) {
return Yii::$app->getUser()->getReturnUrl(); return Yii::$app->getUser()->getReturnUrl();
...@@ -137,13 +171,22 @@ class BaseUrl ...@@ -137,13 +171,22 @@ class BaseUrl
} }
/** /**
* Returns canonical URL for the current page * Returns the canonical URL of the currently requested page.
* The canonical URL is constructed using current controller's [[yii\web\Controller::route]] and
* [[yii\web\Controller::actionParams]]. You may use the following code in the layout view to add a link tag
* about canonical URL:
*
* ```php
* $this->registerLinkTag(['rel' => 'canonical', 'href' => Url::canonical()]);
* ```
* *
* @return string canonical URL * @return string the canonical URL of the currently requested page
*/ */
public function canonical() public static function canonical()
{ {
return Yii::$app->controller->getCanonicalUrl(); $params = Yii::$app->controller->actionParams;
$params[0] = Yii::$app->controller->getRoute();
return Yii::$app->getUrlManager()->createAbsoluteUrl($params);
} }
/** /**
...@@ -152,7 +195,7 @@ class BaseUrl ...@@ -152,7 +195,7 @@ class BaseUrl
* @param string $schema URI schema to use. If specified absolute URL with the schema specified is returned. * @param string $schema URI schema to use. If specified absolute URL with the schema specified is returned.
* @return string home URL * @return string home URL
*/ */
public function home($schema = null) public static function home($schema = null)
{ {
if ($schema === null) { if ($schema === null) {
return Yii::$app->getHomeUrl(); return Yii::$app->getHomeUrl();
......
...@@ -28,7 +28,7 @@ class Controller extends \yii\base\Controller ...@@ -28,7 +28,7 @@ class Controller extends \yii\base\Controller
*/ */
public $enableCsrfValidation = true; public $enableCsrfValidation = true;
/** /**
* @var array the parameters bound to the current action. This is mainly used by [[getCanonicalUrl()]]. * @var array the parameters bound to the current action.
*/ */
public $actionParams = []; public $actionParams = [];
...@@ -119,101 +119,6 @@ class Controller extends \yii\base\Controller ...@@ -119,101 +119,6 @@ class Controller extends \yii\base\Controller
} }
/** /**
* Normalizes route making it suitable for UrlManager. Absolute routes are staying as is
* while relative routes are converted to absolute routes.
*
* A relative route is a route without a leading slash, such as "view", "post/view".
*
* - If the route is an empty string, the current [[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 [[uniqueId]];
* - 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 module's uniqueId.
*
* @param string $route the route. This can be either an absolute route or a relative route.
* @return string normalized route suitable for UrlManager
*/
protected function getNormalizedRoute($route)
{
if (strpos($route, '/') === false) {
// empty or an action ID
$route = $route === '' ? $this->getRoute() : $this->getUniqueId() . '/' . $route;
} elseif ($route[0] !== '/') {
// relative to module
$route = ltrim($this->module->getUniqueId() . '/' . $route, '/');
}
return $route;
}
/**
* Creates a relative URL using the given route and parameters.
*
* This method enhances [[UrlManager::createUrl()]] by supporting relative routes.
* A relative route is a route without a leading slash, such as "view", "post/view".
*
* - If the route is an empty string, the current [[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 [[uniqueId]];
* - 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 module's uniqueId.
*
* After this route conversion, the method calls [[UrlManager::createUrl()]] to create a URL.
*
* @param string|array $params route as a string or route and parameters in form of ['route', 'param1' => 'value1', 'param2' => 'value2']
* @return string the created relative URL
*/
public function createUrl($params)
{
$params = (array)$params;
$params[0] = $this->getNormalizedRoute($params[0]);
return Yii::$app->getUrlManager()->createUrl($params);
}
/**
* Creates an absolute URL using the given route and parameters.
*
* This method enhances [[UrlManager::createAbsoluteUrl()]] by supporting relative routes.
* A relative route is a route without a leading slash, such as "view", "post/view".
*
* - If the route is an empty string, the current [[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 [[uniqueId]];
* - 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 module's uniqueId.
*
* After this route conversion, the method calls [[UrlManager::createUrl()]] to create a URL.
*
* @param string|array $params route as a string or route and parameters in form of ['route', 'param1' => 'value1', 'param2' => 'value2']
* @param string $schema the schema to use for the url. e.g. 'http' or 'https'. If not specified
* the schema of the current request will be used.
* @return string the created absolute URL
*/
public function createAbsoluteUrl($params, $schema = null)
{
$params = (array)$params;
$params[0] = $this->getNormalizedRoute($params[0]);
return Yii::$app->getUrlManager()->createAbsoluteUrl($params, $schema);
}
/**
* Returns the canonical URL of the currently requested page.
* The canonical URL is constructed using [[route]] and [[actionParams]]. You may use the following code
* in the layout view to add a link tag about canonical URL:
*
* ~~~
* $this->registerLinkTag(['rel' => 'canonical', 'href' => Yii::$app->controller->canonicalUrl]);
* ~~~
*
* @return string the canonical URL of the currently requested page
*/
public function getCanonicalUrl()
{
$params = $this->actionParams;
$params[0] = $this->getRoute();
return Yii::$app->getUrlManager()->createAbsoluteUrl($params);
}
/**
* Redirects the browser to the specified URL. * Redirects the browser to the specified URL.
* This method is a shortcut to [[Response::redirect()]]. * This method is a shortcut to [[Response::redirect()]].
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment