diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66af5d35d..948f85a30 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@
- Chg #271: Remove deprecated methods `withDefaultExtension()` and `getDefaultExtension()` from `ViewInterface` (@vjik)
- Chg #271: Rename configuration parameter `defaultExtension` to `fallbackExtension` (@vjik)
- Chg #272: Add variadic parameter `$default` to `ViewInterface::getParameter()` (@vjik)
+- Bug #273: Fix empty string and "0" keys in `WebView` methods: `registerCss()`, `registerStyleTag()`,
+ `registerCssFile()`, `registerJs()`, `registerScriptTag()` and `registerJsFile()` (@vjik)
+- Enh #273: Use more specific psalm types in results of `WebView` methods: `getLinkTags()`, `getCss()`, `getCssFiles()`,
+ `getJs()` and `getJsFiles()` (@vjik)
## 10.0.0 June 28, 2024
diff --git a/psalm.xml b/psalm.xml
index b48c894ef..d091d59c2 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -15,6 +15,5 @@
-
diff --git a/psalm83.xml b/psalm83.xml
index ee80eb36d..4fc7490e9 100644
--- a/psalm83.xml
+++ b/psalm83.xml
@@ -15,7 +15,6 @@
-
diff --git a/src/State/WebViewState.php b/src/State/WebViewState.php
index e262d9a48..b5509aa96 100644
--- a/src/State/WebViewState.php
+++ b/src/State/WebViewState.php
@@ -41,7 +41,7 @@ final class WebViewState
/**
* @var array The registered link tags.
- * @psalm-var array
+ * @psalm-var array>
*
* @see registerLink()
* @see registerLinkTag()
@@ -50,7 +50,7 @@ final class WebViewState
/**
* @var array The registered CSS code blocks.
- * @psalm-var array
+ * @psalm-var array>
*
* {@see registerCss()}
*/
@@ -58,7 +58,7 @@ final class WebViewState
/**
* @var array The registered CSS files.
- * @psalm-var array
+ * @psalm-var array>
*
* {@see registerCssFile()}
*/
@@ -66,7 +66,7 @@ final class WebViewState
/**
* @var array The registered JS code blocks
- * @psalm-var array
+ * @psalm-var array>
*
* {@see registerJs()}
*/
@@ -74,7 +74,7 @@ final class WebViewState
/**
* @var array The registered JS files.
- * @psalm-var array
+ * @psalm-var array>
*
* {@see registerJsFile()}
*/
@@ -98,7 +98,7 @@ public function getMetaTags(): array
/**
* @return array The registered link tags.
- * @psalm-return array
+ * @psalm-return array>
*/
public function getLinkTags(): array
{
@@ -107,7 +107,7 @@ public function getLinkTags(): array
/**
* @return array The registered CSS code blocks.
- * @psalm-return array
+ * @psalm-return array>
*/
public function getCss(): array
{
@@ -116,7 +116,7 @@ public function getCss(): array
/**
* @return array The registered CSS files.
- * @psalm-return array
+ * @psalm-return array>
*/
public function getCssFiles(): array
{
@@ -125,7 +125,7 @@ public function getCssFiles(): array
/**
* @return array The registered JS code blocks
- * @psalm-return array
+ * @psalm-return array>
*/
public function getJs(): array
{
@@ -134,7 +134,7 @@ public function getJs(): array
/**
* @return array The registered JS files.
- * @psalm-return array
+ * @psalm-return array>
*/
public function getJsFiles(): array
{
@@ -224,9 +224,9 @@ public function registerLinkTag(Link $link, int $position = WebView::POSITION_HE
* Registers a CSS code block.
*
* @param string $css The content of the CSS code block to be registered.
- * @param string|null $key The key that identifies the CSS code block. If null, it will use $css as the key.
- * If two CSS code blocks are registered with the same key, the latter will overwrite the former.
* @param array $attributes The HTML attributes for the {@see Style} tag.
+ * @param string|null $key The key that identifies the CSS code block. If `null`, it will use `$css` as the key.
+ * If two CSS code blocks are registered with the same key, the latter will overwrite the former.
*/
public function registerCss(
string $css,
@@ -234,8 +234,7 @@ public function registerCss(
array $attributes = [],
?string $key = null
): void {
- $key = $key ?: md5($css);
- $this->css[$position][$key] = $attributes === [] ? $css : Html::style($css, $attributes);
+ $this->css[$position][$key ?? md5($css)] = $attributes === [] ? $css : Html::style($css, $attributes);
}
/**
@@ -266,8 +265,7 @@ public function registerCssFromFile(
*/
public function registerStyleTag(Style $style, int $position = WebView::POSITION_HEAD, ?string $key = null): void
{
- $key = $key ?: md5($style->render());
- $this->css[$position][$key] = $style;
+ $this->css[$position][$key ?? md5($style->render())] = $style;
}
/**
@@ -280,20 +278,20 @@ public function registerStyleTag(Style $style, int $position = WebView::POSITION
* @param string $url The CSS file to be registered.
* @param array $options the HTML attributes for the link tag. Please refer to {@see \Yiisoft\Html\Html::cssFile()}
* for the supported options.
- * @param string|null $key The key that identifies the CSS script file. If null, it will use $url as the key.
+ * @param string|null $key The key that identifies the CSS script file. If `null`, it will use `$url` as the key.
* If two CSS files are registered with the same key, the latter will overwrite the former.
*/
public function registerCssFile(
string $url,
int $position = WebView::POSITION_HEAD,
array $options = [],
- string $key = null
+ ?string $key = null
): void {
if (!$this->isValidCssPosition($position)) {
throw new InvalidArgumentException('Invalid position of CSS file.');
}
- $this->cssFiles[$position][$key ?: $url] = Html::cssFile($url, $options)->render();
+ $this->cssFiles[$position][$key ?? $url] = Html::cssFile($url, $options)->render();
}
/**
@@ -337,13 +335,12 @@ public function addCssStrings(array $cssStrings): void
* - {@see WebView::POSITION_END}: at the end of the body section. This is the default value.
* - {@see WebView::POSITION_LOAD}: executed when HTML page is completely loaded.
* - {@see WebView::POSITION_READY}: executed when HTML document composition is ready.
- * @param string|null $key The key that identifies the JS code block. If null, it will use $js as the key.
+ * @param string|null $key The key that identifies the JS code block. If `null`, it will use `$js` as the key.
* If two JS code blocks are registered with the same key, the latter will overwrite the former.
*/
public function registerJs(string $js, int $position = WebView::POSITION_END, ?string $key = null): void
{
- $key = $key ?: md5($js);
- $this->js[$position][$key] = $js;
+ $this->js[$position][$key ?? md5($js)] = $js;
}
/**
@@ -353,8 +350,7 @@ public function registerJs(string $js, int $position = WebView::POSITION_END, ?s
*/
public function registerScriptTag(Script $script, int $position = WebView::POSITION_END, ?string $key = null): void
{
- $key = $key ?: md5($script->render());
- $this->js[$position][$key] = $script;
+ $this->js[$position][$key ?? md5($script->render())] = $script;
}
/**
@@ -389,7 +385,7 @@ public function registerJsFile(
throw new InvalidArgumentException('Invalid position of JS file.');
}
- $this->jsFiles[$position][$key ?: $url] = Html::javaScriptFile($url, $options)->render();
+ $this->jsFiles[$position][$key ?? $url] = Html::javaScriptFile($url, $options)->render();
}
/**
diff --git a/tests/WebViewTest.php b/tests/WebViewTest.php
index 9735afdd6..bc33027f5 100644
--- a/tests/WebViewTest.php
+++ b/tests/WebViewTest.php
@@ -118,6 +118,27 @@ public function testRegisterJsFileWithPosition(string $expected, int $position):
$this->assertStringContainsString($expected, $html);
}
+ public function testRegisterJsFileWithKeyEdgeCase(): void
+ {
+ $webView = TestHelper::createWebView()
+ ->registerJsFile('main.js')
+ ->registerJsFile('main.js', key: '')
+ ->registerJsFile('main.js', key: '0')
+ ->registerJsFile('main.js', key: 'four');
+
+ $html = $webView->render('positions.php');
+
+ $this->assertStringContainsString(
+ <<
+
+
+ [/ENDBODY]
+ HTML,
+ $html
+ );
+ }
+
public function testRegisterStyleTag(): void
{
$webView = TestHelper::createWebView();
@@ -136,6 +157,31 @@ public function testRegisterStyleTag(): void
$this->assertSame($expected, $html);
}
+ public function testRegisterStyleTagEdgeCase(): void
+ {
+ $style = Html::style('H1 { color: red; }');
+ $webView = TestHelper::createWebView()
+ ->registerStyleTag($style)
+ ->registerStyleTag($style, key: '')
+ ->registerStyleTag($style, key: '0')
+ ->registerStyleTag($style, key: 'test');
+
+ $html = $webView->render('positions.php');
+
+ $expected = <<render()}
+ {$style->render()}
+ {$style->render()}
+ {$style->render()}[/HEAD]
+ [BEGINBODY][/BEGINBODY]
+ [ENDBODY][/ENDBODY]
+ [ENDPAGE][/ENDPAGE]
+ CODE;
+
+ $this->assertSame($expected, $html);
+ }
+
public static function dataRegisterCssFile(): array
{
return [
@@ -159,6 +205,25 @@ public function testRegisterCssFile(string $url): void
$this->assertStringContainsString('[HEAD][/HEAD]', $html);
}
+ public function testRegisterCssFileEdgeCase(): void
+ {
+ $webView = TestHelper::createWebView()
+ ->registerCssFile('main.css')
+ ->registerCssFile('main.css', options: ['data-x' => '1'], key: '')
+ ->registerCssFile('main.css', options: ['data-x' => '2'], key: '0');
+
+ $html = $webView->render('positions.php');
+
+ $this->assertStringContainsString(
+ <<
+
+ [/HEAD]
+ HTML,
+ $html
+ );
+ }
+
public function testRegisterCssFileWithInvalidPosition(): void
{
$webView = TestHelper::createWebView();
@@ -329,6 +394,26 @@ public function testRegisterCss(string $expected, ?int $position): void
$this->assertStringContainsString($expected, $html);
}
+ public function testRegisterCssWithKeyEdgeCase(): void
+ {
+ $webView = TestHelper::createWebView()
+ ->registerCss('.red{color:red;}')
+ ->registerCss('.red{color:red;}', key: '')
+ ->registerCss('.red{color:red;}', key: '0')
+ ->registerCss('.red{color:red;}', key: 'red');
+
+ $html = $webView->render('positions.php');
+
+ $this->assertStringContainsString(
+ <<assertSame($expected, $html);
}
+ public function testRegisterScriptTagWithKeyEdgeCase(): void
+ {
+ $script = Html::script('alert(1);');
+ $webView = TestHelper::createWebView()
+ ->registerScriptTag($script)
+ ->registerScriptTag($script, key: '')
+ ->registerScriptTag($script, key: '0')
+ ->registerScriptTag($script, key: 'four');
+
+ $html = $webView->render('positions.php');
+
+ $expected = <<render()}
+ {$script->render()}
+ {$script->render()}
+ {$script->render()}[/ENDBODY]
+ [ENDPAGE][/ENDPAGE]
+ HTML;
+
+ $this->assertSame($expected, $html);
+ }
+
public function testRegisterJsAndRegisterScriptTag(): void
{
$webView = TestHelper::createWebView();
@@ -525,6 +635,27 @@ public function testRegisterJsAndRegisterScriptTagWithAjax(): void
$this->assertSame($expected, $html);
}
+ public function testRegisterJsWithKeyEdgeCase(): void
+ {
+ $webView = TestHelper::createWebView()
+ ->registerJs('alert(1);')
+ ->registerJs('alert(1);', key: '')
+ ->registerJs('alert(1);', key: '0')
+ ->registerJs('alert(1);', key: 'four');
+
+ $html = $webView->render('positions.php');
+
+ $this->assertStringContainsString(
+ <<alert(1);
+ alert(1);
+ alert(1);
+ alert(1);
+ JS,
+ $html
+ );
+ }
+
public function testAddCssFiles(): void
{
$webView = TestHelper::createWebView();