Skip to content

Commit

Permalink
Add layout specific injections (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik authored May 14, 2024
1 parent d3c4a9a commit d323372
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Enh #79: Add debug collector for yiisoft/yii-debug (@xepozz)
- Bug #82: Fixed find for layout file due to compatibility with `yiisoft/view` (@rustamwin)
- Enh #99: Make `viewPath` in `ViewRenderer` constructor optional (@vjik)
- New #102: Add layout specific injections (@vjik)

## 6.0.0 February 16, 2023

Expand Down
33 changes: 33 additions & 0 deletions src/LayoutSpecificInjections.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Yii\View;

final class LayoutSpecificInjections
{
/**
* @var object[]
*/
private array $injections;

public function __construct(
private string $layout,
object ...$injections
) {
$this->injections = $injections;
}

/**
* @return object[]
*/
public function getInjections(): array
{
return $this->injections;
}

public function getLayout(): string
{
return $this->layout;
}
}
59 changes: 36 additions & 23 deletions src/ViewRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,9 @@ public function renderPartial(string $view, array $parameters = []): DataRespons
*
* @psalm-param array<string, mixed> $parameters
*
* @throws RuntimeException If the view cannot be resolved.
* @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.
* @return string The rendering result.
*/
public function renderAsString(string $view, array $parameters = []): string
Expand All @@ -174,10 +173,9 @@ public function renderAsString(string $view, array $parameters = []): string
*
* @psalm-param array<string, mixed> $parameters
*
* @throws RuntimeException If the view cannot be resolved.
* @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.
* @return string The rendering result.
*/
public function renderPartialAsString(string $view, array $parameters = []): string
Expand Down Expand Up @@ -293,7 +291,6 @@ public function withLocale(string $locale): self
* @throws RuntimeException If the view cannot be resolved.
* @throws Throwable If an error occurred during rendering.
* @throws ViewNotFoundException If the view file does not exist.
*
* @return string The rendering result.
*/
private function renderProxy(
Expand Down Expand Up @@ -348,12 +345,10 @@ private function renderProxy(
private function getCommonParameters(): array
{
$parameters = [];
foreach ($this->injections as $injection) {
if ($injection instanceof CommonParametersInjectionInterface) {
$parameters = array_merge($parameters, $injection->getCommonParameters());
}
foreach ($this->getInjections($this->layout, CommonParametersInjectionInterface::class) as $injection) {
$parameters[] = $injection->getCommonParameters();
}
return $parameters;
return array_merge(...$parameters);
}

/**
Expand All @@ -366,12 +361,10 @@ private function getCommonParameters(): array
private function getLayoutParameters(): array
{
$parameters = [];
foreach ($this->injections as $injection) {
if ($injection instanceof LayoutParametersInjectionInterface) {
$parameters = array_merge($parameters, $injection->getLayoutParameters());
}
foreach ($this->getInjections($this->layout, LayoutParametersInjectionInterface::class) as $injection) {
$parameters[] = $injection->getLayoutParameters();
}
return $parameters;
return array_merge(...$parameters);
}

/**
Expand All @@ -382,12 +375,10 @@ private function getLayoutParameters(): array
private function getMetaTags(): array
{
$tags = [];
foreach ($this->injections as $injection) {
if ($injection instanceof MetaTagsInjectionInterface) {
$tags = array_merge($tags, $injection->getMetaTags());
}
foreach ($this->getInjections($this->layout, MetaTagsInjectionInterface::class) as $injection) {
$tags[] = $injection->getMetaTags();
}
return $tags;
return array_merge(...$tags);
}

/**
Expand All @@ -398,12 +389,34 @@ private function getMetaTags(): array
private function getLinkTags(): array
{
$tags = [];
foreach ($this->getInjections($this->layout, LinkTagsInjectionInterface::class) as $injection) {
$tags[] = $injection->getLinkTags();
}
return array_merge(...$tags);
}

/**
* @psalm-template T
* @psalm-param class-string<T> $injectionInterface
* @psalm-return list<T>
*/
private function getInjections(?string $layout, string $injectionInterface): array
{
$result = [];
foreach ($this->injections as $injection) {
if ($injection instanceof LinkTagsInjectionInterface) {
$tags = array_merge($tags, $injection->getLinkTags());
if ($injection instanceof $injectionInterface) {
$result[] = $injection;
continue;

Check warning on line 409 in src/ViewRenderer.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.2-ubuntu-latest

Escaped Mutant for Mutator "Continue_": --- Original +++ New @@ @@ foreach ($this->injections as $injection) { if ($injection instanceof $injectionInterface) { $result[] = $injection; - continue; + break; } if ($injection instanceof LayoutSpecificInjections && $injection->getLayout() === $layout) { foreach ($injection->getInjections() as $layoutInjection) {
}
if ($injection instanceof LayoutSpecificInjections && $injection->getLayout() === $layout) {
foreach ($injection->getInjections() as $layoutInjection) {
if ($layoutInjection instanceof $injectionInterface) {
$result[] = $layoutInjection;
}
}
}
}
return $tags;
return $result;
}

/**
Expand Down
34 changes: 34 additions & 0 deletions tests/ViewRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use Yiisoft\View\WebView;
use Yiisoft\Yii\View\Exception\InvalidLinkTagException;
use Yiisoft\Yii\View\Exception\InvalidMetaTagException;
use Yiisoft\Yii\View\LayoutSpecificInjections;
use Yiisoft\Yii\View\MetaTagsInjectionInterface;
use Yiisoft\Yii\View\Tests\Support\FakeCntrl;
use Yiisoft\Yii\View\Tests\Support\FakeController;
use Yiisoft\Yii\View\Tests\Support\InvalidLinkTagInjection;
Expand Down Expand Up @@ -480,6 +482,38 @@ public function testWithoutViewPath(): void
$viewRenderer->getViewPath();
}

public function testLayoutSpecificInjections(): void
{
$renderer = $this
->getRenderer()
->withLayout('@views/nested-layout/layout')
->withInjections(
new LayoutSpecificInjections(
'@views/nested-layout/layout',
new TitleInjection(),
),
new LayoutSpecificInjections(
'@views/layout',
new TestInjection(),
),
new class () implements MetaTagsInjectionInterface {
public function getMetaTags(): array
{
return [
['charset' => 'windows-1251'],
];
}
}
);

$response = $renderer->render('empty');

$this->assertSame(
'<html><head><title>Hello</title><meta charset="windows-1251"></head><body><h1>Hello</h1></body></html>',
(string) $response->getBody(),
);
}

public function testImmutability(): void
{
$original = $this->getRenderer();
Expand Down
1 change: 1 addition & 0 deletions tests/views/nested-layout/head.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@

echo '<head>';
echo '<title>' . $title . '</title>';
$this->head();
echo '</head>';
2 changes: 2 additions & 0 deletions tests/views/nested-layout/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
* @var string $title
*/

$this->beginPage();
echo '<html>';
echo $this->render('head');
echo '<body>';
echo '<h1>' . $title . '</h1>';
echo $content;
echo '</body>';
echo '</html>';
$this->endPage();

0 comments on commit d323372

Please sign in to comment.