Skip to content

Commit

Permalink
feat(view): add twig support (#841)
Browse files Browse the repository at this point in the history
Co-authored-by: Brent Roose <[email protected]>
  • Loading branch information
dinhquochan and brendt authored Dec 11, 2024
1 parent 09ced7a commit 0f47a80
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 1 deletion.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"rector/rector": "^2.0-rc2",
"spatie/phpunit-snapshot-assertions": "^5.1.6",
"spaze/phpstan-disallowed-calls": "^4.0",
"symplify/monorepo-builder": "^11.2"
"symplify/monorepo-builder": "^11.2",
"twig/twig": "^3.16"
},
"replace": {
"tempest/auth": "self.version",
Expand Down
36 changes: 36 additions & 0 deletions src/Tempest/View/src/Renderers/TwigConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Tempest\View\Renderers;

final readonly class TwigConfig
{
/**
* @see \Twig\Environment::__construct()
*/
public function __construct(
public array $viewPaths = [],
public ?string $cachePath = null,
public bool $debug = false,
public string $charset = 'utf-8',
public bool $strictVariables = false,
public string $autoescape = 'html',
public ?bool $autoReload = null,
public int $optimizations = -1,
) {
}

public function toArray(): array
{
return [
'debug' => $this->debug,
'charset' => $this->charset,
'strict_variables' => $this->strictVariables,
'autoescape' => $this->autoescape,
'cache' => $this->cachePath ?: false,
'auto_reload' => $this->autoReload,
'optimizations' => $this->optimizations,
];
}
}
33 changes: 33 additions & 0 deletions src/Tempest/View/src/Renderers/TwigInitializer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Tempest\View\Renderers;

use Tempest\Container\Container;
use Tempest\Container\DynamicInitializer;
use Tempest\Container\Singleton;
use Tempest\Reflection\ClassReflector;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

final readonly class TwigInitializer implements DynamicInitializer
{
public function canInitialize(ClassReflector $class): bool
{
if (! class_exists(Environment::class)) {
return false;
}

return $class->getName() === Environment::class;
}

#[Singleton]
public function initialize(ClassReflector $class, Container $container): object
{
$twigConfig = $container->get(TwigConfig::class);
$twigLoader = new FilesystemLoader($twigConfig->viewPaths);

return new Environment($twigLoader, $twigConfig->toArray());
}
}
25 changes: 25 additions & 0 deletions src/Tempest/View/src/Renderers/TwigViewRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Tempest\View\Renderers;

use Tempest\View\View;
use Tempest\View\ViewRenderer;
use Twig\Environment;

final readonly class TwigViewRenderer implements ViewRenderer
{
public function __construct(private Environment $twig)
{
}

public function render(View|string|null $view): string
{
if ($view === null) {
return '';
}

return trim($this->twig->render($view->getPath(), $view->getData()));
}
}
41 changes: 41 additions & 0 deletions tests/Integration/View/TwigViewRendererTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Tests\Tempest\Integration\View;

use Tempest\View\Renderers\TwigConfig;
use Tempest\View\Renderers\TwigViewRenderer;
use Tempest\View\ViewConfig;
use Tempest\View\ViewRenderer;
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
use function Tempest\view;

/**
* @internal
*/
final class TwigViewRendererTest extends FrameworkIntegrationTestCase
{
public function test_twig(): void
{
$viewConfig = $this->container->get(ViewConfig::class);

$viewConfig->rendererClass = TwigViewRenderer::class;

$this->container->config(new TwigConfig(
viewPaths: [__DIR__ . '/twig'],
cachePath: __DIR__ . '/../../../.cache/tempest/twig/cache',
));

$renderer = $this->container->get(ViewRenderer::class);

$html = $renderer->render(view('index.twig', ...['foo' => 'bar']));

$this->assertStringEqualsStringIgnoringLineEndings(<<<HTML
<html>
<span>bar</span>
</html>
HTML
, $html);
}
}
3 changes: 3 additions & 0 deletions tests/Integration/View/twig/base.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html>
{% block content %}{% endblock %}
</html>
5 changes: 5 additions & 0 deletions tests/Integration/View/twig/index.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends "base.twig" %}

{% block content %}
<span>{{ foo }}</span>
{% endblock %}

0 comments on commit 0f47a80

Please sign in to comment.