From 9d56179e9d446a9271c8090a63153ae18a740d03 Mon Sep 17 00:00:00 2001 From: Bizley Date: Sun, 4 Jul 2021 11:03:19 +0200 Subject: [PATCH] Updated asUrl method to not introduce BC break (#18742) --- framework/CHANGELOG.md | 2 +- framework/helpers/BaseUrl.php | 6 +-- framework/i18n/Formatter.php | 29 ++++++------ tests/framework/i18n/FormatterTest.php | 84 +++++++++++++++++++++++++++------- 4 files changed, 85 insertions(+), 36 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 33afc93..d8a665e 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -12,8 +12,8 @@ Yii Framework 2 Change Log - Enh #18676: Added method `yii\helpers\BaseFileHelper::changeOwnership()` and properties `newFileMode`/`newFileOwnership` in `yii\console\controllers\BaseMigrateController` (rhertogh) - Bug #18678: Fix `yii\caching\DbCache` to use configured cache table name instead of the default one in case of MSSQL varbinary column type detection (aidanbek) - Enh #18695: Added `yii\web\Cookie::SAME_SITE_NONE` constant (rhertogh) +- Enh #18712: Added `scheme` option for `$options` argument for `yii\i18n\Formatter::asUrl()` (bizley) - Enh #18707: Changed the base error handler to not expose `$_SERVER` details unless `YII_DEBUG` is enabled (coolgoose) -- Enh #18712: Added `$scheme` option to `yii\i18n\Formatter::asUrl()` (bizley) - Bug #18648: Fix `yii\web\Request` to properly handle HTTP Basic Auth headers (olegbaturin) - Enh #18726: Added `yii\helpers\Json::$prettyPrint` (rhertogh) diff --git a/framework/helpers/BaseUrl.php b/framework/helpers/BaseUrl.php index 4b44551..4da728e 100644 --- a/framework/helpers/BaseUrl.php +++ b/framework/helpers/BaseUrl.php @@ -232,12 +232,12 @@ class BaseUrl } /** - * Normalize URL by ensuring that it use specified scheme. + * Normalize the URL by ensuring it uses specified scheme. * - * If URL is relative or scheme is not string, normalization is skipped. + * If the URL is relative or the scheme is not a string, normalization is skipped. * * @param string $url the URL to process - * @param string $scheme the URI scheme used in URL (e.g. `http` or `https`). Use empty string to + * @param string $scheme the URI scheme used in the URL (e.g. `http` or `https`). Use an empty string to * create protocol-relative URL (e.g. `//example.com/path`) * @return string the processed URL * @since 2.0.11 diff --git a/framework/i18n/Formatter.php b/framework/i18n/Formatter.php index 3f8c33d..9728c2f 100644 --- a/framework/i18n/Formatter.php +++ b/framework/i18n/Formatter.php @@ -18,9 +18,11 @@ use Yii; use yii\base\Component; use yii\base\InvalidArgumentException; use yii\base\InvalidConfigException; +use yii\helpers\ArrayHelper; use yii\helpers\FormatConverter; use yii\helpers\Html; use yii\helpers\HtmlPurifier; +use yii\helpers\Url; /** * Formatter provides a set of commonly used data formatting methods. @@ -576,31 +578,26 @@ class Formatter extends Component /** * Formats the value as a hyperlink. * @param mixed $value the value to be formatted. - * @param array $options the tag options in terms of name-value pairs. See [[Html::a()]]. - * @param bool|string $scheme the URI scheme to use in the formatted hyperlink (available since 2.0.43): - * - * - `false (default)`: adding non-secure protocol scheme if there is none added already - * - `true`: adding secure protocol scheme if there is none added already - * - string: adding the specified scheme (either `http`, `https` or empty string - * for protocol-relative URL) if there is none added already - * + * @param array $options the tag options in terms of name-value pairs. See [[Html::a()]]. Since 2.0.43 there is + * a special option available `scheme` - if set it won't be passed to [[Html::a()]] but it will control the URL + * protocol part of the link by normalizing URL and ensuring that it uses specified scheme. See [[Url::ensureScheme()]]. + * If `scheme` is not set the original behavior is preserved which is to add "http://" prefix when "://" string is + * not found in the $value. * @return string the formatted result. */ - public function asUrl($value, $options = [], $scheme = false) + public function asUrl($value, $options = []) { if ($value === null) { return $this->nullDisplay; } $url = $value; - - if (strpos($url, '://') === false) { - if ($scheme === false || $scheme === 'http') { + $scheme = ArrayHelper::remove($options, 'scheme'); + if ($scheme === null) { + if (strpos($url, '://') === false) { $url = 'http://' . $url; - } elseif ($scheme === true || $scheme === 'https') { - $url = 'https://' . $url; - } elseif ($scheme === '') { - $url = '//' . $url; } + } else { + $url = Url::ensureScheme($url, $scheme); } return Html::a(Html::encode($value), $url, $options); diff --git a/tests/framework/i18n/FormatterTest.php b/tests/framework/i18n/FormatterTest.php index d51b351..300f2b7 100644 --- a/tests/framework/i18n/FormatterTest.php +++ b/tests/framework/i18n/FormatterTest.php @@ -216,27 +216,79 @@ class FormatterTest extends TestCase { $value = 'http://www.yiiframework.com/'; $this->assertSame("$value", $this->formatter->asUrl($value)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], false)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], true)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], 'http')); - $this->assertSame("$value", $this->formatter->asUrl($value, [], 'https')); - $this->assertSame("$value", $this->formatter->asUrl($value, [], '')); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => null])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => false])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => 'http'])); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => 'https']) + ); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => '']) + ); $value = 'https://www.yiiframework.com/'; $this->assertSame("$value", $this->formatter->asUrl($value)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], false)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], true)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], 'http')); - $this->assertSame("$value", $this->formatter->asUrl($value, [], 'https')); - $this->assertSame("$value", $this->formatter->asUrl($value, [], '')); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => false])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => null])); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => 'http']) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => 'https'])); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => '']) + ); $value = 'www.yiiframework.com/'; - $this->assertSame("$value", $this->formatter->asUrl($value)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], false)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], true)); - $this->assertSame("$value", $this->formatter->asUrl($value, [], 'http')); - $this->assertSame("$value", $this->formatter->asUrl($value, [], 'https')); - $this->assertSame("$value", $this->formatter->asUrl($value, [], '')); + $this->assertSame( + "$value", + $this->formatter->asUrl($value) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => false])); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => null]) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => 'http'])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => 'https'])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => ''])); + + $value = '//www.yiiframework.com/'; + $this->assertSame( + "$value", // invalid but this is how it works + $this->formatter->asUrl($value) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => false])); + $this->assertSame( + "$value", // invalid but this is how it works + $this->formatter->asUrl($value, ['scheme' => null]) + ); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => 'http']) + ); + $this->assertSame( + "$value", + $this->formatter->asUrl($value, ['scheme' => 'https']) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => ''])); + + $value = '/books/about/yii'; + $this->assertSame( + "$value", // invalid but this is how it works + $this->formatter->asUrl($value) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => false])); + $this->assertSame( + "$value", // invalid but this is how it works + $this->formatter->asUrl($value, ['scheme' => null]) + ); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => 'http'])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => 'https'])); + $this->assertSame("$value", $this->formatter->asUrl($value, ['scheme' => ''])); $value = 'https://www.yiiframework.com/?name=test&value=5"'; $this->assertSame(