Skip to content

Commit

Permalink
Merge pull request #393 from CPS-IT/feature/1.x/view
Browse files Browse the repository at this point in the history
[!!!][FEATURE] Introduce `HandlebarsView` and require it in renderers
  • Loading branch information
eliashaeussler authored Jan 15, 2025
2 parents 88f260a + 8827b41 commit 518fa53
Show file tree
Hide file tree
Showing 33 changed files with 973 additions and 169 deletions.
9 changes: 7 additions & 2 deletions Classes/DataProcessing/SimpleProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

use Fr\Typo3Handlebars\Exception\InvalidTemplateFileException;
use Fr\Typo3Handlebars\Renderer\Renderer;
use Fr\Typo3Handlebars\Renderer\Template\View\HandlebarsView;
use Fr\Typo3Handlebars\Traits\ErrorHandlingTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
Expand All @@ -51,8 +52,12 @@ public function __construct(
public function process(string $content, array $configuration): string
{
try {
$templatePath = $this->getTemplatePath($configuration);
return $this->renderer->render($templatePath, $this->contentObjectRenderer?->data ?? []);
$view = new HandlebarsView(
$this->getTemplatePath($configuration),
$this->contentObjectRenderer?->data ?? [],
);

return $this->renderer->render($view);
} catch (InvalidTemplateFileException $exception) {
$this->handleError($exception);
return '';
Expand Down
6 changes: 3 additions & 3 deletions Classes/Event/AfterRenderingEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
final class AfterRenderingEvent
{
public function __construct(
private readonly string $templatePath,
private readonly Renderer\Template\View\HandlebarsView $view,
private string $content,
private readonly Renderer\Renderer $renderer,
) {}

public function getTemplatePath(): string
public function getView(): Renderer\Template\View\HandlebarsView
{
return $this->templatePath;
return $this->view;
}

public function getContent(): string
Expand Down
6 changes: 3 additions & 3 deletions Classes/Event/BeforeRenderingEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ final class BeforeRenderingEvent
* @param array<string|int, mixed> $variables
*/
public function __construct(
private readonly string $templatePath,
private readonly Renderer\Template\View\HandlebarsView $view,
private array $variables,
private readonly Renderer\Renderer $renderer,
) {}

public function getTemplatePath(): string
public function getView(): Renderer\Template\View\HandlebarsView
{
return $this->templatePath;
return $this->view;
}

/**
Expand Down
10 changes: 8 additions & 2 deletions Classes/Exception/PartialPathIsNotResolvable.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@
*/
final class PartialPathIsNotResolvable extends Exception
{
public function __construct(string $path)
public function __construct(string $path, ?string $format = null)
{
if ($format !== null) {
$formatMessage = sprintf(' with format "%s"', $format);
} else {
$formatMessage = '';
}

parent::__construct(
\sprintf('The partial path "%s" cannot be resolved.', $path),
\sprintf('The partial path "%s"%s cannot be resolved.', $path, $formatMessage),
1736254715,
);
}
Expand Down
41 changes: 41 additions & 0 deletions Classes/Exception/TemplateFileIsInvalid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS extension "handlebars".
*
* Copyright (C) 2025 Elias Häußler <e.haeussler@familie-redlich.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace Fr\Typo3Handlebars\Exception;

/**
* TemplateFileIsInvalid
*
* @author Elias Häußler <e.haeussler@familie-redlich.de>
* @license GPL-2.0-or-later
*/
final class TemplateFileIsInvalid extends Exception
{
public function __construct(string $file)
{
parent::__construct(
\sprintf('The template file "%s" is invalid or does not exist.', $file),
1736333208,
);
}
}
41 changes: 41 additions & 0 deletions Classes/Exception/TemplateFormatIsNotSupported.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS extension "handlebars".
*
* Copyright (C) 2025 Elias Häußler <e.haeussler@familie-redlich.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace Fr\Typo3Handlebars\Exception;

/**
* TemplateFormatIsNotSupported
*
* @author Elias Häußler <e.haeussler@familie-redlich.de>
* @license GPL-2.0-or-later
*/
final class TemplateFormatIsNotSupported extends Exception
{
public function __construct(string $format)
{
parent::__construct(
sprintf('The format "%s" is not supported by this template resolver.', $format),
1736349135,
);
}
}
10 changes: 8 additions & 2 deletions Classes/Exception/TemplatePathIsNotResolvable.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@
*/
final class TemplatePathIsNotResolvable extends Exception
{
public function __construct(string $path)
public function __construct(string $path, ?string $format = null)
{
if ($format !== null) {
$formatMessage = \sprintf(' with format "%s"', $format);
} else {
$formatMessage = '';
}

parent::__construct(
\sprintf('The template path "%s" cannot be resolved.', $path),
\sprintf('The template path "%s"%s cannot be resolved.', $path, $formatMessage),
1736254772,
);
}
Expand Down
41 changes: 41 additions & 0 deletions Classes/Exception/ViewIsNotProperlyInitialized.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS extension "handlebars".
*
* Copyright (C) 2025 Elias Häußler <e.haeussler@familie-redlich.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace Fr\Typo3Handlebars\Exception;

/**
* ViewIsNotProperlyInitialized
*
* @author Elias Häußler <e.haeussler@familie-redlich.de>
* @license GPL-2.0-or-later
*/
final class ViewIsNotProperlyInitialized extends Exception
{
public function __construct()
{
parent::__construct(
'The Handlebars view is not properly initialized. Provide either template path or template source.',
1736332788,
);
}
}
55 changes: 28 additions & 27 deletions Classes/Renderer/HandlebarsRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,57 +61,48 @@ public function __construct(
$this->debugMode = $this->isDebugModeEnabled();
}

public function render(string $templatePath, array $data = []): string
public function render(Template\View\HandlebarsView $view): string
{
try {
return $this->processRendering($templatePath, $data);
} catch (Exception\InvalidTemplateFileException | Exception\TemplateCompilationException | Exception\TemplatePathIsNotResolvable $exception) {
return $this->processRendering($view);
} catch (Exception\TemplateCompilationException | Exception\TemplateFileIsInvalid | Exception\TemplateFormatIsNotSupported | Exception\TemplatePathIsNotResolvable | Exception\ViewIsNotProperlyInitialized $exception) {
$this->logger->critical($exception->getMessage(), ['exception' => $exception]);

return '';
}
}

/**
* @param array<string|int, mixed> $variables
* @throws Exception\InvalidTemplateFileException
* @throws Exception\TemplateCompilationException
* @throws Exception\TemplateFileIsInvalid
* @throws Exception\TemplateFormatIsNotSupported
* @throws Exception\TemplatePathIsNotResolvable
* @throws Exception\ViewIsNotProperlyInitialized
*/
protected function processRendering(string $templatePath, array $variables): string
protected function processRendering(Template\View\HandlebarsView $view): string
{
$fullTemplatePath = $this->templateResolver->resolveTemplatePath($templatePath);
$template = file_get_contents($fullTemplatePath);

// Throw exception if template file is invalid
if ($template === false) {
throw new Exception\InvalidTemplateFileException($fullTemplatePath, 1606217313);
}
$compileResult = $this->compile($view);

// Early return if template is empty
if (trim($template) === '') {
if ($compileResult === null) {
return '';
}

// Merge variables with default variables
$mergedVariables = array_merge($this->variableBag->get(), $variables);

// Compile template
$compileResult = $this->compile($template);
$renderer = $this->prepareCompileResult($compileResult);
$mergedVariables = array_merge($this->variableBag->get(), $view->getVariables());

// Dispatch before rendering event
$beforeRenderingEvent = new Event\BeforeRenderingEvent($fullTemplatePath, $mergedVariables, $this);
$beforeRenderingEvent = new Event\BeforeRenderingEvent($view, $mergedVariables, $this);
$this->eventDispatcher->dispatch($beforeRenderingEvent);

// Render content
$renderer = $this->prepareCompileResult($compileResult);
$content = $renderer($beforeRenderingEvent->getVariables(), [
'debug' => Runtime::DEBUG_TAGS_HTML,
'helpers' => $this->helperRegistry->getAll(),
]);

// Dispatch after rendering event
$afterRenderingEvent = new Event\AfterRenderingEvent($fullTemplatePath, $content, $this);
$afterRenderingEvent = new Event\AfterRenderingEvent($view, $content, $this);
$this->eventDispatcher->dispatch($afterRenderingEvent);

return $afterRenderingEvent->getContent();
Expand All @@ -120,16 +111,25 @@ protected function processRendering(string $templatePath, array $variables): str
/**
* Compile given template by LightnCandy compiler.
*
* @param string $template Raw template to be compiled
* @return string The compiled template
* @throws Exception\TemplateCompilationException() if template compilation fails and errors are not yet handled by compiler
* @throws Exception\TemplateFileIsInvalid
* @throws Exception\TemplateFormatIsNotSupported
* @throws Exception\TemplatePathIsNotResolvable
* @throws Exception\ViewIsNotProperlyInitialized
*/
protected function compile(string $template): string
protected function compile(Template\View\HandlebarsView $view): ?string
{
$template = $view->getTemplate($this->templateResolver);

// Early return if template is empty
if (\trim($template) === '') {
return null;
}

// Disable cache if debugging is enabled or caching is disabled
$cache = $this->cache;
if ($this->debugMode || $this->isCachingDisabled()) {
$cache = new Cache\NullCache();
} else {
$cache = $this->cache;
}

// Get compile result from cache
Expand Down Expand Up @@ -239,6 +239,7 @@ protected function getHelperStubs(): array
* @param string $name Name of the partial to be resolved
* @return string|null Partial file contents if partial could be resolved, `null` otherwise
* @throws Exception\PartialPathIsNotResolvable
* @throws Exception\TemplateFormatIsNotSupported
*/
public function resolvePartial(array $context, string $name): ?string
{
Expand Down
6 changes: 4 additions & 2 deletions Classes/Renderer/Helper/ExtendHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ public function render(Context\HelperContext $context): string
$renderingContext['_layoutStack'][] = $handlebarsLayout;

// Merge data with supplied data
$renderData = array_replace_recursive($renderingContext, $customContext, $context->hash);
$variables = array_replace_recursive($renderingContext, $customContext, $context->hash);

// Render layout with merged data
return $this->renderer->render($name, $renderData);
return $this->renderer->render(
new Renderer\Template\View\HandlebarsView($name, $variables),
);
}
}
4 changes: 3 additions & 1 deletion Classes/Renderer/Helper/RenderHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ public function render(Context\HelperContext $context): SafeString
if ($renderUncached) {
$content = $this->registerUncachedTemplateBlock($name, $subContext);
} else {
$content = $this->renderer->render($name, $subContext);
$content = $this->renderer->render(
new Renderer\Template\View\HandlebarsView($name, $subContext),
);
}

return new SafeString($content);
Expand Down
5 changes: 1 addition & 4 deletions Classes/Renderer/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,5 @@
*/
interface Renderer
{
/**
* @param array<string|int, mixed> $data
*/
public function render(string $templatePath, array $data = []): string;
public function render(Template\View\HandlebarsView $view): string;
}
Loading

0 comments on commit 518fa53

Please sign in to comment.