Commit 348dfa78 by Alexander Makarov

Merge pull request #2676 from yiisoft/url-helper

#2630: `yii\heplers\Html::url` moved to new `yii\helpers\Url::create`
parents 19989353 2ceab799
...@@ -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
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\bootstrap\BootstrapAsset; use yii\bootstrap\BootstrapAsset;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
/** /**
...@@ -135,7 +136,7 @@ class SideNavWidget extends \yii\bootstrap\Widget ...@@ -135,7 +136,7 @@ class SideNavWidget extends \yii\bootstrap\Widget
$label = $this->encodeLabels ? Html::encode($item['label']) : $item['label']; $label = $this->encodeLabels ? Html::encode($item['label']) : $item['label'];
// $options = ArrayHelper::getValue($item, 'options', []); // $options = ArrayHelper::getValue($item, 'options', []);
$items = ArrayHelper::getValue($item, 'items'); $items = ArrayHelper::getValue($item, 'items');
$url = Html::url(ArrayHelper::getValue($item, 'url', '#')); $url = Url::to(ArrayHelper::getValue($item, 'url', '#'));
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', []); $linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
Html::addCssClass($linkOptions, 'list-group-item'); Html::addCssClass($linkOptions, 'list-group-item');
......
...@@ -9,6 +9,7 @@ namespace yii\authclient\widgets; ...@@ -9,6 +9,7 @@ namespace yii\authclient\widgets;
use yii\base\Widget; use yii\base\Widget;
use Yii; use Yii;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
use yii\authclient\ClientInterface; use yii\authclient\ClientInterface;
...@@ -195,7 +196,7 @@ class Choice extends Widget ...@@ -195,7 +196,7 @@ class Choice extends Widget
$this->autoRender = false; $this->autoRender = false;
$url = $this->getBaseAuthUrl(); $url = $this->getBaseAuthUrl();
$url[$this->clientIdGetParamName] = $provider->getId(); $url[$this->clientIdGetParamName] = $provider->getId();
return Html::url($url); return Url::to($url);
} }
/** /**
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* @var string $tag * @var string $tag
* @var string $position * @var string $position
*/ */
use yii\helpers\Html; use yii\helpers\Url;
$minJs = <<<EOD $minJs = <<<EOD
document.getElementById('yii-debug-toolbar').style.display = 'none'; document.getElementById('yii-debug-toolbar').style.display = 'none';
...@@ -28,7 +28,7 @@ $url = $firstPanel->getUrl(); ...@@ -28,7 +28,7 @@ $url = $firstPanel->getUrl();
?> ?>
<div id="yii-debug-toolbar" class="yii-debug-toolbar-<?= $position ?>"> <div id="yii-debug-toolbar" class="yii-debug-toolbar-<?= $position ?>">
<div class="yii-debug-toolbar-block title"> <div class="yii-debug-toolbar-block title">
<a href="<?= Html::url(['index']) ?>"> <a href="<?= Url::to(['index']) ?>">
<img width="29" height="30" alt="" src="<?= \yii\debug\Module::getYiiLogo() ?>"> <img width="29" height="30" alt="" src="<?= \yii\debug\Module::getYiiLogo() ?>">
Yii Debugger Yii Debugger
</a> </a>
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
use yii\bootstrap\ButtonDropdown; use yii\bootstrap\ButtonDropdown;
use yii\bootstrap\ButtonGroup; use yii\bootstrap\ButtonGroup;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
/** /**
...@@ -19,7 +20,7 @@ $this->title = 'Yii Debugger'; ...@@ -19,7 +20,7 @@ $this->title = 'Yii Debugger';
<div id="yii-debug-toolbar" class="yii-debug-toolbar-top"> <div id="yii-debug-toolbar" class="yii-debug-toolbar-top">
<div class="yii-debug-toolbar-block title"> <div class="yii-debug-toolbar-block title">
<a href="<?= Html::url(['index']) ?>"> <a href="<?= Url::to(['index']) ?>">
<img width="29" height="30" alt="" src="<?= \yii\debug\Module::getYiiLogo() ?>"> <img width="29" height="30" alt="" src="<?= \yii\debug\Module::getYiiLogo() ?>">
Yii Debugger Yii Debugger
</a> </a>
......
...@@ -9,6 +9,7 @@ namespace yii\elasticsearch; ...@@ -9,6 +9,7 @@ namespace yii\elasticsearch;
use yii\debug\Panel; use yii\debug\Panel;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\log\Logger; use yii\log\Logger;
use yii\helpers\Html; use yii\helpers\Html;
use yii\web\View; use yii\web\View;
...@@ -83,7 +84,7 @@ EOD; ...@@ -83,7 +84,7 @@ EOD;
}, },
]); ]);
} }
$ajaxUrl = Html::url(['elasticsearch-query', 'logId' => $logId, 'tag' => $this->tag]); $ajaxUrl = Url::to(['elasticsearch-query', 'logId' => $logId, 'tag' => $this->tag]);
\Yii::$app->view->registerJs(<<<JS \Yii::$app->view->registerJs(<<<JS
$('#elastic-link-$i').on('click', function() { $('#elastic-link-$i').on('click', function() {
var result = $('#elastic-result-$i'); var result = $('#elastic-result-$i');
......
...@@ -9,6 +9,7 @@ namespace yii\jui; ...@@ -9,6 +9,7 @@ namespace yii\jui;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
/** /**
...@@ -120,7 +121,7 @@ class Tabs extends Widget ...@@ -120,7 +121,7 @@ class Tabs extends Widget
throw new InvalidConfigException("The 'label' option is required."); throw new InvalidConfigException("The 'label' option is required.");
} }
if (isset($item['url'])) { if (isset($item['url'])) {
$url = Html::url($item['url']); $url = Url::to($item['url']);
} else { } else {
if (!isset($item['content'])) { if (!isset($item['content'])) {
throw new InvalidConfigException("The 'content' or 'url' option is required."); throw new InvalidConfigException("The 'content' or 'url' option is required.");
......
...@@ -12,8 +12,8 @@ namespace yii\smarty; ...@@ -12,8 +12,8 @@ namespace yii\smarty;
use Yii; use Yii;
use Smarty; use Smarty;
use yii\base\View; use yii\base\View;
use yii\helpers\Html;
use yii\base\ViewRenderer as BaseViewRenderer; use yii\base\ViewRenderer as BaseViewRenderer;
use yii\helpers\Url;
/** /**
* SmartyViewRenderer allows you to use Smarty templates in views. * SmartyViewRenderer allows you to use Smarty templates in views.
...@@ -70,7 +70,7 @@ class ViewRenderer extends BaseViewRenderer ...@@ -70,7 +70,7 @@ class ViewRenderer extends BaseViewRenderer
array_unshift($params, $params['route']) ; array_unshift($params, $params['route']) ;
unset($params['route']); unset($params['route']);
return Html::url($params); return Url::to($params);
} }
/** /**
......
...@@ -12,7 +12,7 @@ namespace yii\twig; ...@@ -12,7 +12,7 @@ namespace yii\twig;
use Yii; use Yii;
use yii\base\View; use yii\base\View;
use yii\base\ViewRenderer as BaseViewRenderer; use yii\base\ViewRenderer as BaseViewRenderer;
use yii\helpers\Html; use yii\helpers\Url;
/** /**
* TwigViewRenderer allows you to use Twig templates in views. * TwigViewRenderer allows you to use Twig templates in views.
...@@ -122,7 +122,7 @@ class ViewRenderer extends BaseViewRenderer ...@@ -122,7 +122,7 @@ class ViewRenderer extends BaseViewRenderer
})); }));
$this->twig->addFunction('path', new \Twig_Function_Function(function ($path, $args = []) { $this->twig->addFunction('path', new \Twig_Function_Function(function ($path, $args = []) {
return Html::url(array_merge([$path], $args)); return Url::to(array_merge([$path], $args));
})); }));
$this->twig->addGlobal('app', \Yii::$app); $this->twig->addGlobal('app', \Yii::$app);
......
...@@ -193,6 +193,11 @@ Yii Framework 2 Change Log ...@@ -193,6 +193,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: 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)
......
...@@ -9,6 +9,7 @@ namespace yii\captcha; ...@@ -9,6 +9,7 @@ namespace yii\captcha;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
use yii\helpers\Json; use yii\helpers\Json;
use yii\widgets\InputWidget; use yii\widgets\InputWidget;
...@@ -106,7 +107,7 @@ class Captcha extends InputWidget ...@@ -106,7 +107,7 @@ class Captcha extends InputWidget
protected function getClientOptions() protected function getClientOptions()
{ {
$options = [ $options = [
'refreshUrl' => Html::url(['/' . $this->captchaAction, CaptchaAction::REFRESH_GET_VAR => 1]), 'refreshUrl' => Url::to(['/' . $this->captchaAction, CaptchaAction::REFRESH_GET_VAR => 1]),
'hashKey' => "yiiCaptcha/{$this->captchaAction}", 'hashKey' => "yiiCaptcha/{$this->captchaAction}",
]; ];
return $options; return $options;
......
...@@ -11,6 +11,7 @@ use Yii; ...@@ -11,6 +11,7 @@ use Yii;
use Closure; use Closure;
use yii\base\Formatter; use yii\base\Formatter;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
use yii\helpers\Json; use yii\helpers\Json;
use yii\widgets\BaseListView; use yii\widgets\BaseListView;
...@@ -218,7 +219,7 @@ class GridView extends BaseListView ...@@ -218,7 +219,7 @@ class GridView extends BaseListView
} }
return [ return [
'filterUrl' => Html::url($filterUrl), 'filterUrl' => Url::to($filterUrl),
'filterSelector' => $filterSelector, 'filterSelector' => $filterSelector,
]; ];
} }
......
...@@ -205,7 +205,7 @@ class BaseHtml ...@@ -205,7 +205,7 @@ class BaseHtml
if (!isset($options['rel'])) { if (!isset($options['rel'])) {
$options['rel'] = 'stylesheet'; $options['rel'] = 'stylesheet';
} }
$options['href'] = static::url($url); $options['href'] = Url::to($url);
return static::tag('link', '', $options); return static::tag('link', '', $options);
} }
...@@ -221,7 +221,7 @@ class BaseHtml ...@@ -221,7 +221,7 @@ class BaseHtml
*/ */
public static function jsFile($url, $options = []) public static function jsFile($url, $options = [])
{ {
$options['src'] = static::url($url); $options['src'] = Url::to($url);
return static::tag('script', '', $options); return static::tag('script', '', $options);
} }
...@@ -241,7 +241,7 @@ class BaseHtml ...@@ -241,7 +241,7 @@ class BaseHtml
*/ */
public static function beginForm($action = '', $method = 'post', $options = []) public static function beginForm($action = '', $method = 'post', $options = [])
{ {
$action = static::url($action); $action = Url::to($action);
$hiddenInputs = []; $hiddenInputs = [];
...@@ -311,7 +311,7 @@ class BaseHtml ...@@ -311,7 +311,7 @@ class BaseHtml
public static function a($text, $url = null, $options = []) public static function a($text, $url = null, $options = [])
{ {
if ($url !== null) { if ($url !== null) {
$options['href'] = static::url($url); $options['href'] = Url::to($url);
} }
return static::tag('a', $text, $options); return static::tag('a', $text, $options);
} }
...@@ -346,7 +346,7 @@ class BaseHtml ...@@ -346,7 +346,7 @@ class BaseHtml
*/ */
public static function img($src, $options = []) public static function img($src, $options = [])
{ {
$options['src'] = static::url($src); $options['src'] = Url::to($src);
if (!isset($options['alt'])) { if (!isset($options['alt'])) {
$options['alt'] = ''; $options['alt'] = '';
} }
...@@ -1528,48 +1528,6 @@ class BaseHtml ...@@ -1528,48 +1528,6 @@ class BaseHtml
} }
/** /**
* Normalizes the input parameter to be a valid URL.
*
* If the input parameter
*
* - is an empty string: the currently requested URL will be returned;
* - is a non-empty string: it will first be processed by [[Yii::getAlias()]]. If the result
* is an absolute URL, it will be returned without any change further; Otherwise, the result
* will be prefixed with [[\yii\web\Request::baseUrl]] and returned.
* - is an array: the first array element is considered a route, while the rest of the name-value
* pairs are treated as the parameters to be used for URL creation using [[\yii\web\Controller::createUrl()]].
* For example: `['post/index', 'page' => 2]`, `['index']`.
* In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used.
*
* @param array|string $url the parameter to be used to generate a valid URL
* @return string the normalized URL
* @throws InvalidParamException if the parameter is invalid.
*/
public static function url($url)
{
if (is_array($url)) {
if (isset($url[0])) {
if (Yii::$app->controller instanceof \yii\web\Controller) {
return Yii::$app->controller->createUrl($url);
} else {
return Yii::$app->getUrlManager()->createUrl($url);
}
} else {
throw new InvalidParamException('The array specifying a URL must contain at least one element.');
}
} elseif ($url === '') {
return Yii::$app->getRequest()->getUrl();
} else {
$url = Yii::getAlias($url);
if ($url !== '' && ($url[0] === '/' || $url[0] === '#' || strpos($url, '://') || !strncmp($url, './', 2))) {
return $url;
} else {
return Yii::$app->getRequest()->getBaseUrl() . '/' . $url;
}
}
}
/**
* Adds a CSS class to the specified options. * Adds a CSS class to the specified options.
* If the CSS class is already in the options, it will not be added again. * If the CSS class is already in the options, it will not be added again.
* @param array $options the options to be modified. * @param array $options the options to be modified.
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\helpers;
use yii\base\InvalidParamException;
use Yii;
/**
* BaseUrl provides concrete implementation for [[Url]].
*
* Do not use BaseUrl. Use [[Url]] instead.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class BaseUrl
{
/**
* Returns URL for a route.
*
* @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 [[\yii\web\Controller::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 [[\yii\web\Controller::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 boolean|string $schema URI schema to use:
*
* - `false`: relative URL. Default behavior.
* - `true`: absolute URL with the current scheme.
* - string: absolute URL with string value used as schema.
*
* @return string the normalized URL
* @throws InvalidParamException if the parameter is invalid.
*/
public static function toRoute($route, $schema = false)
{
$route = (array)$route;
if (Yii::$app->controller instanceof \yii\web\Controller) {
$route[0] = static::getNormalizedRoute($route[0]);
}
if ($schema) {
if ($schema === true) {
$schema = null;
}
$url = Yii::$app->getUrlManager()->createAbsoluteUrl($route, $schema);
} else {
$url = Yii::$app->getUrlManager()->createUrl($route);
}
return $url;
}
/**
* 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 [[\yii\web\Controller::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 [[\yii\web\Controller::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;
}
/**
* Creates a link specified by the input parameter.
*
* If the input parameter
*
* - is an array: the first array element is considered a route, while the rest of the name-value
* pairs are treated as the parameters to be used for URL creation using [[toRoute]].
* For example: `['post/index', 'page' => 2]`, `['index']`.
* In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used.
* - is an empty string: the currently requested URL will be returned;
* - is a non-empty string: it will first be processed by [[Yii::getAlias()]]. If the result
* is an absolute URL, it will be returned either without any change or, if schema was specified, with schema
* replaced; Otherwise, the result will be prefixed with [[\yii\web\Request::baseUrl]] and returned.
*
* @param array|string $url the parameter to be used to generate a valid URL
* @param boolean|string $schema URI schema to use:
*
* - `false`: relative URL. Default behavior.
* - `true`: absolute URL with the current scheme.
* - string: absolute URL with string value used as schema.
*
* @return string the normalized URL
* @throws InvalidParamException if the parameter is invalid.
*/
public static function to($url = '', $schema = false)
{
if (is_array($url)) {
return static::toRoute($url, $schema);
} elseif ($url === '') {
if ($schema) {
$url = Yii::$app->getRequest()->getAbsoluteUrl();
} else {
$url = Yii::$app->getRequest()->getUrl();
}
} else {
$url = Yii::getAlias($url);
if (strpos($url, '://') === false) {
if ($url === '' || ($url[0] !== '/' && $url[0] !== '#' && strncmp($url, './', 2))) {
$url = Yii::$app->getRequest()->getBaseUrl() . '/' . $url;
}
if ($schema) {
$url = Yii::$app->getRequest()->getHostInfo() . $url;
}
}
}
if ($schema && $schema !== true) {
$pos = strpos($url, '://');
if ($pos !== false) {
$url = $schema . substr($url, $pos);
}
}
return $url;
}
/**
* Remembers URL passed
*
* @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 static function remember($url = '', $name = null)
{
if ($url === '') {
$url = Yii::$app->getRequest()->getUrl();
}
if ($name === null) {
Yii::$app->getUser()->setReturnUrl($url);
} else {
Yii::$app->getSession()->set($name, $url);
}
}
/**
* Returns URL previously saved with remember method
*
* @param string $name Name used to remember URL. Defaults to `yii\web\User::returnUrlParam`.
* @return string URL
*/
public static function previous($name = null)
{
if ($name === null) {
return Yii::$app->getUser()->getReturnUrl();
} else {
return Yii::$app->getSession()->get($name);
}
}
/**
* 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 the canonical URL of the currently requested page
*/
public static function canonical()
{
$params = Yii::$app->controller->actionParams;
$params[0] = Yii::$app->controller->getRoute();
return Yii::$app->getUrlManager()->createAbsoluteUrl($params);
}
/**
* Returns home URL
*
* @param boolean|string $schema URI schema to use:
*
* - `false`: relative URL. Default behavior.
* - `true`: absolute URL with the current scheme.
* - string: absolute URL with string value used as schema.
*
* @return string home URL
*/
public static function home($schema = false)
{
if ($schema) {
$url = Yii::$app->getRequest()->getHostInfo() . Yii::$app->getHomeUrl();
if ($schema !== true) {
$pos = strpos($url, '://');
$url = $schema . substr($url, $pos);
}
} else {
$url = Yii::$app->getHomeUrl();
}
return $url;
}
}
\ No newline at end of file
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\helpers;
/**
* Url provides a set of static methods for managing URLs.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class Url extends BaseUrl
{
}
\ No newline at end of file
...@@ -9,7 +9,7 @@ namespace yii\web; ...@@ -9,7 +9,7 @@ namespace yii\web;
use Yii; use Yii;
use yii\base\InlineAction; use yii\base\InlineAction;
use yii\helpers\Html; use yii\helpers\Url;
/** /**
* Controller is the base class of web controllers. * Controller is the base class of web controllers.
...@@ -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()]].
* *
...@@ -241,7 +146,7 @@ class Controller extends \yii\base\Controller ...@@ -241,7 +146,7 @@ class Controller extends \yii\base\Controller
*/ */
public function redirect($url, $statusCode = 302) public function redirect($url, $statusCode = 302)
{ {
return Yii::$app->getResponse()->redirect(Html::url($url), $statusCode); return Yii::$app->getResponse()->redirect(Url::to($url), $statusCode);
} }
/** /**
......
...@@ -10,8 +10,8 @@ namespace yii\web; ...@@ -10,8 +10,8 @@ namespace yii\web;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\helpers\Url;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
use yii\helpers\Html;
use yii\helpers\Json; use yii\helpers\Json;
use yii\helpers\Security; use yii\helpers\Security;
use yii\helpers\StringHelper; use yii\helpers\StringHelper;
...@@ -673,7 +673,7 @@ class Response extends \yii\base\Response ...@@ -673,7 +673,7 @@ class Response extends \yii\base\Response
// ensure the route is absolute // ensure the route is absolute
$url[0] = '/' . ltrim($url[0], '/'); $url[0] = '/' . ltrim($url[0], '/');
} }
$url = Html::url($url); $url = Url::to($url);
if (strpos($url, '/') === 0 && strpos($url, '//') !== 0) { if (strpos($url, '/') === 0 && strpos($url, '//') !== 0) {
$url = Yii::$app->getRequest()->getHostInfo() . $url; $url = Yii::$app->getRequest()->getHostInfo() . $url;
} }
......
...@@ -292,9 +292,9 @@ class UrlManager extends Component ...@@ -292,9 +292,9 @@ class UrlManager extends Component
$params = (array)$params; $params = (array)$params;
$url = $this->createUrl($params); $url = $this->createUrl($params);
if (strpos($url, '://') === false) { if (strpos($url, '://') === false) {
$url = $this->getHostInfo($schema) . $url; $url = $this->getHostInfo() . $url;
} }
if ($schema !== null && ($pos = strpos($url, '://')) !== false) { if ($schema && ($pos = strpos($url, '://')) !== false) {
$url = $schema . substr($url, $pos); $url = $schema . substr($url, $pos);
} }
return $url; return $url;
......
...@@ -10,6 +10,7 @@ namespace yii\widgets; ...@@ -10,6 +10,7 @@ namespace yii\widgets;
use Yii; use Yii;
use yii\base\Widget; use yii\base\Widget;
use yii\base\Model; use yii\base\Model;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
use yii\helpers\Json; use yii\helpers\Json;
use yii\web\JsExpression; use yii\web\JsExpression;
...@@ -194,7 +195,7 @@ class ActiveForm extends Widget ...@@ -194,7 +195,7 @@ class ActiveForm extends Widget
'ajaxDataType' => $this->ajaxDataType, 'ajaxDataType' => $this->ajaxDataType,
]; ];
if ($this->validationUrl !== null) { if ($this->validationUrl !== null) {
$options['validationUrl'] = Html::url($this->validationUrl); $options['validationUrl'] = Url::to($this->validationUrl);
} }
foreach (['beforeSubmit', 'beforeValidate', 'afterValidate'] as $name) { foreach (['beforeSubmit', 'beforeValidate', 'afterValidate'] as $name) {
if (($value = $this->$name) !== null) { if (($value = $this->$name) !== null) {
......
...@@ -10,6 +10,7 @@ namespace yii\widgets; ...@@ -10,6 +10,7 @@ namespace yii\widgets;
use Yii; use Yii;
use yii\base\Widget; use yii\base\Widget;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
/** /**
...@@ -218,7 +219,7 @@ class Menu extends Widget ...@@ -218,7 +219,7 @@ class Menu extends Widget
if (isset($item['url'])) { if (isset($item['url'])) {
$template = ArrayHelper::getValue($item, 'template', $this->linkTemplate); $template = ArrayHelper::getValue($item, 'template', $this->linkTemplate);
return strtr($template, [ return strtr($template, [
'{url}' => Html::url($item['url']), '{url}' => Url::to($item['url']),
'{label}' => $item['label'], '{label}' => $item['label'],
]); ]);
} else { } else {
......
<?php
namespace yiiunit\framework\helpers;
use yii\base\Action;
use yii\base\Module;
use yii\helpers\Url;
use yii\web\Controller;
use yiiunit\TestCase;
/**
* UrlTest
*/
class UrlTest extends TestCase
{
protected function setUp()
{
parent::setUp();
$this->mockApplication([
'components' => [
'request' => [
'class' => 'yii\web\Request',
'scriptUrl' => '/base/index.php',
'hostInfo' => 'http://example.com/',
'url' => '/base/index.php&r=site/current&id=42'
],
],
], '\yii\web\Application');
}
/**
* Mocks controller action with parameters
*
* @param string $controllerId
* @param string $actionId
* @param string $moduleID
* @param array $params
*/
protected function mockAction($controllerId, $actionId, $moduleID = null, $params = [])
{
\Yii::$app->controller = $controller = new Controller($controllerId, \Yii::$app);
$controller->actionParams = $params;
$controller->action = new Action($actionId, $controller);
if ($moduleID !== null) {
$controller->module = new Module($moduleID);
}
}
protected function removeMockedAction()
{
\Yii::$app->controller = null;
}
public function testToRoute()
{
$this->mockAction('page', 'view', null, ['id' => 10]);
// If the route is an empty string, the current route will be used;
$this->assertEquals('/base/index.php?r=page/view', Url::toRoute(''));
$this->assertEquals('http://example.com/base/index.php?r=page/view', Url::toRoute('', true));
$this->assertEquals('https://example.com/base/index.php?r=page/view', Url::toRoute('', 'https'));
// 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;
$this->assertEquals('/base/index.php?r=page/edit', Url::toRoute('edit'));
$this->assertEquals('/base/index.php?r=page/edit&id=20', Url::toRoute(['edit', 'id' => 20]));
$this->assertEquals('http://example.com/base/index.php?r=page/edit&id=20', Url::toRoute(['edit', 'id' => 20], true));
$this->assertEquals('https://example.com/base/index.php?r=page/edit&id=20', Url::toRoute(['edit', 'id' => 20], 'https'));
// 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.
$this->mockAction('default', 'index', 'stats');
$this->assertEquals('/base/index.php?r=stats/user/view', Url::toRoute('user/view'));
$this->assertEquals('/base/index.php?r=stats/user/view&id=42', Url::toRoute(['user/view', 'id' => 42]));
$this->assertEquals('http://example.com/base/index.php?r=stats/user/view&id=42', Url::toRoute(['user/view', 'id' => 42], true));
$this->assertEquals('https://example.com/base/index.php?r=stats/user/view&id=42', Url::toRoute(['user/view', 'id' => 42], 'https'));
// In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used.
$this->removeMockedAction();
$this->assertEquals('/base/index.php?r=site/view', Url::toRoute('site/view'));
$this->assertEquals('http://example.com/base/index.php?r=site/view', Url::toRoute('site/view', true));
$this->assertEquals('https://example.com/base/index.php?r=site/view', Url::toRoute('site/view', 'https'));
$this->assertEquals('/base/index.php?r=site/view&id=37', Url::toRoute(['site/view', 'id' => 37]));
}
public function testTo()
{
// is an array: the first array element is considered a route, while the rest of the name-value
// pairs are treated as the parameters to be used for URL creation using Url::toRoute.
$this->mockAction('page', 'view', null, ['id' => 10]);
$this->assertEquals('/base/index.php?r=page/edit&id=20', Url::to(['edit', 'id' => 20]));
$this->assertEquals('/base/index.php?r=page/edit', Url::to(['edit']));
$this->assertEquals('/base/index.php?r=page/view', Url::to(['']));
$this->assertEquals('http://example.com/base/index.php?r=page/edit&id=20', Url::to(['edit', 'id' => 20], true));
$this->assertEquals('http://example.com/base/index.php?r=page/edit', Url::to(['edit'], true));
$this->assertEquals('http://example.com/base/index.php?r=page/view', Url::to([''], true));
$this->assertEquals('https://example.com/base/index.php?r=page/edit&id=20', Url::to(['edit', 'id' => 20], 'https'));
$this->assertEquals('https://example.com/base/index.php?r=page/edit', Url::to(['edit'], 'https'));
$this->assertEquals('https://example.com/base/index.php?r=page/view', Url::to([''], 'https'));
//In case there is no controller, [[\yii\web\UrlManager::createUrl()]] will be used.
$this->removeMockedAction();
$this->assertEquals('/base/index.php?r=edit&id=20', Url::to(['edit', 'id' => 20]));
$this->assertEquals('/base/index.php?r=edit', Url::to(['edit']));
$this->assertEquals('/base/index.php?r=', Url::to(['']));
$this->assertEquals('http://example.com/base/index.php?r=edit&id=20', Url::to(['edit', 'id' => 20], true));
$this->assertEquals('http://example.com/base/index.php?r=edit', Url::to(['edit'], true));
$this->assertEquals('http://example.com/base/index.php?r=', Url::to([''], true));
$this->assertEquals('https://example.com/base/index.php?r=edit&id=20', Url::to(['edit', 'id' => 20], 'https'));
$this->assertEquals('https://example.com/base/index.php?r=edit', Url::to(['edit'], 'https'));
$this->assertEquals('https://example.com/base/index.php?r=', Url::to([''], 'https'));
// is an empty string: the currently requested URL will be returned;
$this->mockAction('page', 'view', null, ['id' => 10]);
$this->assertEquals('/base/index.php&r=site/current&id=42', Url::to(''));
$this->assertEquals('http://example.com/base/index.php&r=site/current&id=42', Url::to('', true));
$this->assertEquals('https://example.com/base/index.php&r=site/current&id=42', Url::to('', 'https'));
$this->removeMockedAction();
// is a non-empty string: it will first be processed by [[Yii::getAlias()]]. If the result
// is an absolute URL, it will be returned either without any change or, if schema was specified, with schema
// replaced; Otherwise, the result will be prefixed with [[\yii\web\Request::baseUrl]] and returned.
\Yii::setAlias('@web1', 'http://test.example.com/test/me1');
\Yii::setAlias('@web2', 'test/me2');
\Yii::setAlias('@web3', '');
\Yii::setAlias('@web4', '/test');
\Yii::setAlias('@web5', '#test');
$this->assertEquals('http://test.example.com/test/me1', Url::to('@web1'));
$this->assertEquals('http://test.example.com/test/me1', Url::to('@web1', true));
$this->assertEquals('https://test.example.com/test/me1', Url::to('@web1', 'https'));
$this->assertEquals('/base/test/me2', Url::to('@web2'));
$this->assertEquals('http://example.com/base/test/me2', Url::to('@web2', true));
$this->assertEquals('https://example.com/base/test/me2', Url::to('@web2', 'https'));
$this->assertEquals('/base/', Url::to('@web3'));
$this->assertEquals('http://example.com/base/', Url::to('@web3', true));
$this->assertEquals('https://example.com/base/', Url::to('@web3', 'https'));
$this->assertEquals('/test', Url::to('@web4'));
$this->assertEquals('http://example.com/test', Url::to('@web4', true));
$this->assertEquals('https://example.com/test', Url::to('@web4', 'https'));
$this->assertEquals('#test', Url::to('@web5'));
$this->assertEquals('http://example.com#test', Url::to('@web5', true));
$this->assertEquals('https://example.com#test', Url::to('@web5', 'https'));
}
public function testHome()
{
$this->assertEquals('/base/index.php', Url::home());
$this->assertEquals('http://example.com/base/index.php', Url::home(true));
$this->assertEquals('https://example.com/base/index.php', Url::home('https'));
}
public function testCanonical()
{
$this->mockAction('page', 'view', null, ['id' => 10]);
$this->assertEquals('http://example.com/base/index.php?r=page/view&id=10', Url::canonical());
$this->removeMockedAction();
}
}
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