Skip to content

Commit 573d557

Browse files
authored
feat(view): add view processors (#1011)
1 parent 6c7dfae commit 573d557

File tree

6 files changed

+91
-0
lines changed

6 files changed

+91
-0
lines changed

src/Tempest/View/src/Renderers/TempestViewRenderer.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
namespace Tempest\View\Renderers;
66

77
use Stringable;
8+
use Tempest\Container\Container;
89
use Tempest\Support\Html\HtmlString;
910
use Tempest\View\Exceptions\ViewCompilationError;
1011
use Tempest\View\Exceptions\ViewVariableIsReserved;
1112
use Tempest\View\GenericView;
1213
use Tempest\View\View;
1314
use Tempest\View\ViewCache;
15+
use Tempest\View\ViewConfig;
1416
use Tempest\View\ViewRenderer;
1517
use Throwable;
1618

@@ -24,6 +26,8 @@ final class TempestViewRenderer implements ViewRenderer
2426
public function __construct(
2527
private readonly TempestViewCompiler $compiler,
2628
private readonly ViewCache $viewCache,
29+
private readonly ViewConfig $viewConfig,
30+
private readonly Container $container,
2731
) {
2832
}
2933

@@ -48,6 +52,8 @@ public function render(string|View $view): string
4852
compiledView: fn () => $this->cleanupCompiled($this->compiler->compile($view)),
4953
);
5054

55+
$view = $this->processView($view);
56+
5157
return $this->renderCompiled($view, $path);
5258
}
5359

@@ -80,6 +86,18 @@ private function cleanupCompiled(string $compiled): string
8086
return $compiled->toString();
8187
}
8288

89+
private function processView(View $view): View
90+
{
91+
foreach ($this->viewConfig->viewProcessors as $viewProcessorClass) {
92+
/** @var \Tempest\View\ViewProcessor $viewProcessor */
93+
$viewProcessor = $this->container->get($viewProcessorClass);
94+
95+
$view = $viewProcessor->process($view);
96+
}
97+
98+
return $view;
99+
}
100+
83101
private function renderCompiled(View $_view, string $_path): string
84102
{
85103
$this->currentView = $_view;

src/Tempest/View/src/ViewConfig.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,19 @@ public function __construct(
1515
/** @var array<array-key, class-string<\Tempest\View\ViewComponent>|\Tempest\View\ViewComponent> */
1616
public array $viewComponents = [],
1717

18+
/** @var class-string<\Tempest\View\ViewProcessor>[] */
19+
public array $viewProcessors = [],
20+
1821
/** @var class-string<\Tempest\View\ViewRenderer> */
1922
public string $rendererClass = TempestViewRenderer::class,
2023
) {
2124
}
2225

26+
public function addViewProcessor(ClassReflector $viewProcessor): void
27+
{
28+
$this->viewProcessors[] = $viewProcessor->getName();
29+
}
30+
2331
public function addViewComponent(string $name, ClassReflector|AnonymousViewComponent $viewComponent): void
2432
{
2533
if (! str_starts_with($name, 'x-')) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Tempest\View;
4+
5+
interface ViewProcessor
6+
{
7+
public function process(View $view): View;
8+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Tempest\View;
4+
5+
use Tempest\Discovery\Discovery;
6+
use Tempest\Discovery\DiscoveryLocation;
7+
use Tempest\Discovery\IsDiscovery;
8+
use Tempest\Reflection\ClassReflector;
9+
10+
final class ViewProcessorDiscovery implements Discovery
11+
{
12+
use IsDiscovery;
13+
14+
public function __construct(
15+
private readonly ViewConfig $viewConfig,
16+
) {
17+
}
18+
19+
public function discover(DiscoveryLocation $location, ClassReflector $class): void
20+
{
21+
if (! $class->implements(ViewProcessor::class)) {
22+
return;
23+
}
24+
25+
$this->discoveryItems->add($location, [$class->getName()]);
26+
}
27+
28+
public function apply(): void
29+
{
30+
foreach ($this->discoveryItems as [$className]) {
31+
$viewProcessor = new ClassReflector($className);
32+
33+
$this->viewConfig->addViewProcessor($viewProcessor);
34+
}
35+
}
36+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Tests\Tempest\Fixtures\Views;
4+
5+
use Tempest\View\View;
6+
use Tempest\View\ViewProcessor;
7+
8+
final readonly class TestViewProcessor implements ViewProcessor
9+
{
10+
public function process(View $view): View
11+
{
12+
return $view->data(global: 'test');
13+
}
14+
}

tests/Integration/View/TempestViewRendererTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,4 +514,11 @@ public function test_html_tags(): void
514514
$this->assertStringContainsString('<body', $html);
515515
$this->assertStringContainsString('<!-- test comment -->', $html);
516516
}
517+
518+
public function test_view_processors(): void
519+
{
520+
$html = $this->render('<div>{{ $global }}</div>');
521+
522+
$this->assertStringEqualsStringIgnoringLineEndings('<div>test</div>', $html);
523+
}
517524
}

0 commit comments

Comments
 (0)