Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 7.4.2 under development

- Enh #150: Minor refactor regular expression for controller name extractor (@vjik)
- Enh #161: Throw `InvalidArgumentException` with a clear message when an empty view name is passed to `WebViewRenderer` render methods (@samdark)

## 7.4.1 March 18, 2026

Expand Down
22 changes: 22 additions & 0 deletions src/WebViewRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Yii\View\Renderer;

use InvalidArgumentException;
use LogicException;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
Expand Down Expand Up @@ -113,10 +114,13 @@ public function getViewPath(): string
*
* @psalm-param array<string, mixed> $parameters
*
* @throws InvalidArgumentException If the view name is empty.
* @return ResponseInterface The response instance.
*/
public function render(string $view, array $parameters = []): ResponseInterface
{
$this->assertViewNameIsNotEmpty($view);

$commonParameters = $this->getCommonParameters();
$layoutParameters = $this->getLayoutParameters();
$metaTags = $this->getMetaTags();
Expand Down Expand Up @@ -151,6 +155,7 @@ public function render(string $view, array $parameters = []): ResponseInterface
*
* @psalm-param array<string, mixed> $parameters
*
* @throws InvalidArgumentException If the view name is empty.
* @return ResponseInterface The response instance.
*/
public function renderPartial(string $view, array $parameters = []): ResponseInterface
Expand All @@ -176,10 +181,13 @@ public function renderPartial(string $view, array $parameters = []): ResponseInt
* @throws Throwable If an error occurred during rendering.
* @throws ViewNotFoundException If the view file does not exist.
* @throws RuntimeException If the view cannot be resolved.
* @throws InvalidArgumentException If the view name is empty.
* @return string The rendering result.
*/
public function renderAsString(string $view, array $parameters = []): string
{
$this->assertViewNameIsNotEmpty($view);

return $this->renderProxy(
$view,
$parameters,
Expand All @@ -202,6 +210,7 @@ public function renderAsString(string $view, array $parameters = []): string
* @throws Throwable If an error occurred during rendering.
* @throws ViewNotFoundException If the view file does not exist.
* @throws RuntimeException If the view cannot be resolved.
* @throws InvalidArgumentException If the view name is empty.
* @return string The rendering result.
*/
public function renderPartialAsString(string $view, array $parameters = []): string
Expand Down Expand Up @@ -382,6 +391,19 @@ private function renderProxy(
->render($layout, ['content' => $content]);
}

/**
* @throws InvalidArgumentException If the view name is empty.
*/
private function assertViewNameIsNotEmpty(string $view): void
{
if ($view === '') {
throw new InvalidArgumentException(
'The view name must not be empty. To return a response without a view, such as JSON, '
. 'use an appropriate response factory instead.',
);
}
}

/**
* Gets injection common parameters merged with parameters specified during rendering.
*
Expand Down
36 changes: 36 additions & 0 deletions tests/WebViewRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use HttpSoft\Message\ResponseFactory;
use HttpSoft\Message\StreamFactory;
use InvalidArgumentException;
use LogicException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -486,6 +487,41 @@ public function testWithoutViewPath(): void
$viewRenderer->getViewPath();
}

public static function dataEmptyViewName(): iterable
{
yield 'render' => ['render'];
yield 'renderPartial' => ['renderPartial'];
yield 'renderAsString' => ['renderAsString'];
yield 'renderPartialAsString' => ['renderPartialAsString'];
}

#[DataProvider('dataEmptyViewName')]
public function testEmptyViewName(string $method): void
{
$renderer = $this->getRenderer();

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
'The view name must not be empty. To return a response without a view, such as JSON, '
. 'create it with a response factory instead.',
);
$renderer->$method('');
}

public function testEmptyViewNameWithoutViewPath(): void
{
$renderer = new WebViewRenderer(
new ResponseFactory(),
new StreamFactory(),
new Aliases(),
new WebView(__DIR__, new SimpleEventDispatcher()),
);

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The view name must not be empty.');
$renderer->render('');
}

public function testLazyLoadingInjection(): void
{
$container = new SimpleContainer([
Expand Down
Loading