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:
* `http://www.example.com/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
`createUrl` method, the controller version is context sensitive:
In order to simplify URL creation there is [[yii\helpers\Url]] helper that is able to do the following:
```php
echo $this->createUrl(''); // currently active route
echo $this->createUrl(['view', 'id' => 'contact']); // same controller, different action
echo $this->createUrl('post/index'); // same module, different controller and action
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 $this->createurl(['/date-time/fast-forward', 'id' => 105]); // url for action the case sensitive controller, `DateTimeController::actionFastForward`
use yii\helpers\Url;
echo Url::to(''); // currently active URL
echo Url::toRoute(['view', 'id' => 'contact']); // same controller, different action
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
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
----------------
......@@ -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 `$this->createUrl(['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/list')` generates `/index.php/posts`. The first rule is applied.
- Calling `Url::toRoute(['post/read', 'id' => 100])` generates `/index.php/post/100`. The second rule is applied.
- Calling `Url::toRoute(['post/read', 'year' => 2008, 'title' => 'a sample post'])` generates
`/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.
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
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
`Yii::$app->request->getQueryParam('id')`).
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
`Yii::$app->request->get('id')`).
### Parameterizing Routes
......
......@@ -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 #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 #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 `ActiveRecord::getPopulatedRelations()` to `getRelatedRecords()` (qiangxue)
- Chg: Renamed `attributeName` and `className` to `targetAttribute` and `targetClass` for `UniqueValidator` and `ExistValidator` (qiangxue)
......@@ -231,7 +235,6 @@ Yii Framework 2 Change Log
- New #1956: Implemented test fixture framework (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 #2630: Added `yii\helpers\Url` (samdark)
- New: Yii framework now comes with core messages in multiple languages
- New: Added yii\codeception\DbTestCase (qiangxue)
......
......@@ -26,6 +26,14 @@ class BaseUrl
* @param array|string $route route as a string or route and parameters in form of
* ['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.
*
* @param string $schema URI schema to use. If specified absolute URL with the schema specified is returned.
......@@ -39,10 +47,36 @@ class BaseUrl
throw new InvalidParamException('$route should contain at least one element.');
}
if (Yii::$app->controller instanceof \yii\web\Controller) {
return $schema === null ? Yii::$app->controller->createUrl($route) : Yii::$app->controller->createAbsoluteUrl($route, $schema);
} else {
$route[0] = static::getNormalizedRoute($route[0]);
}
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
* @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`.
*/
public function remember($url = '', $name = null)
public static function remember($url = '', $name = null)
{
if ($url === '') {
$url = Yii::$app->getRequest()->getUrl();
......@@ -127,7 +161,7 @@ class BaseUrl
* @param string $name Name used to remember URL. Defaults to `yii\web\User::returnUrlParam`.
* @return string URL
*/
public function previous($name = null)
public static function previous($name = null)
{
if ($name === null) {
return Yii::$app->getUser()->getReturnUrl();
......@@ -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
* @param string $schema URI schema to use. If specified absolute URL with the schema specified is returned.
* @return string home URL
*/
public function home($schema = null)
public static function home($schema = null)
{
if ($schema === null) {
return Yii::$app->getHomeUrl();
......
......@@ -28,7 +28,7 @@ class Controller extends \yii\base\Controller
*/
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 = [];
......@@ -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.
* 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