diff --git a/Classes/Attribute/AsHelper.php b/Classes/Attribute/AsHelper.php
new file mode 100644
index 00000000..ba36ce68
--- /dev/null
+++ b/Classes/Attribute/AsHelper.php
@@ -0,0 +1,41 @@
+
+ *
+ * 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 .
+ */
+
+namespace Fr\Typo3Handlebars\Attribute;
+
+/**
+ * AsHelper
+ *
+ * @author Elias Häußler
+ * @license GPL-2.0-or-later
+ */
+#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
+final readonly class AsHelper
+{
+ public const TAG_NAME = 'handlebars.helper';
+
+ public function __construct(
+ public string $identifier,
+ public ?string $method = null,
+ ) {}
+}
diff --git a/Classes/Cache/HandlebarsCache.php b/Classes/Cache/HandlebarsCache.php
index c1fa5615..f599aae9 100644
--- a/Classes/Cache/HandlebarsCache.php
+++ b/Classes/Cache/HandlebarsCache.php
@@ -23,6 +23,8 @@
namespace Fr\Typo3Handlebars\Cache;
+use Symfony\Component\DependencyInjection\Attribute\AsAlias;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
/**
@@ -31,9 +33,11 @@
* @author Elias Häußler
* @license GPL-2.0-or-later
*/
+#[AsAlias('handlebars.cache')]
class HandlebarsCache implements CacheInterface
{
public function __construct(
+ #[Autowire('@cache.handlebars')]
protected readonly FrontendInterface $cache,
) {}
diff --git a/Classes/Compatibility/View/HandlebarsViewResolver.php b/Classes/Compatibility/View/HandlebarsViewResolver.php
index 1ca84d24..cc91c12d 100644
--- a/Classes/Compatibility/View/HandlebarsViewResolver.php
+++ b/Classes/Compatibility/View/HandlebarsViewResolver.php
@@ -25,6 +25,7 @@
use Fr\Typo3Handlebars\DataProcessing\DataProcessorInterface;
use Psr\Http\Message\ServerRequestInterface;
+use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\GenericViewResolver;
use TYPO3Fluid\Fluid\View\ViewInterface;
@@ -35,6 +36,7 @@
* @author Elias Häußler
* @license GPL-2.0-or-later
*/
+#[Autoconfigure(public: true)]
class HandlebarsViewResolver extends GenericViewResolver
{
/**
diff --git a/Classes/DataProcessing/SimpleProcessor.php b/Classes/DataProcessing/SimpleProcessor.php
index 4de8ad1b..90c3aba1 100644
--- a/Classes/DataProcessing/SimpleProcessor.php
+++ b/Classes/DataProcessing/SimpleProcessor.php
@@ -27,6 +27,7 @@
use Fr\Typo3Handlebars\Renderer\RendererInterface;
use Fr\Typo3Handlebars\Traits\ErrorHandlingTrait;
use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
@@ -35,6 +36,7 @@
* @author Elias Häußler
* @license GPL-2.0-or-later
*/
+#[Autoconfigure(public: true)]
class SimpleProcessor implements DataProcessorInterface
{
use ErrorHandlingTrait;
diff --git a/Classes/Renderer/HandlebarsRenderer.php b/Classes/Renderer/HandlebarsRenderer.php
index 41038fc8..58fd49dd 100644
--- a/Classes/Renderer/HandlebarsRenderer.php
+++ b/Classes/Renderer/HandlebarsRenderer.php
@@ -38,6 +38,9 @@
use LightnCandy\Runtime;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\Attribute\AsAlias;
+use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
@@ -47,6 +50,8 @@
* @author Elias Häußler
* @license GPL-2.0-or-later
*/
+#[AsAlias('handlebars.renderer')]
+#[Autoconfigure(tags: ['handlebars.renderer'])]
class HandlebarsRenderer implements RendererInterface, HelperAwareInterface
{
use HandlebarsHelperTrait;
@@ -57,11 +62,15 @@ class HandlebarsRenderer implements RendererInterface, HelperAwareInterface
* @param array $defaultData
*/
public function __construct(
+ #[Autowire('@handlebars.cache')]
protected readonly CacheInterface $cache,
protected readonly EventDispatcherInterface $eventDispatcher,
protected readonly LoggerInterface $logger,
+ #[Autowire('@handlebars.template_resolver')]
protected readonly TemplateResolverInterface $templateResolver,
+ #[Autowire('@handlebars.partial_resolver')]
protected readonly ?TemplateResolverInterface $partialResolver = null,
+ #[Autowire('%handlebars.default_data%')]
protected array $defaultData = [],
) {
$this->debugMode = $this->isDebugModeEnabled();
diff --git a/Classes/Renderer/Helper/BlockHelper.php b/Classes/Renderer/Helper/BlockHelper.php
index 09655919..b3a56798 100644
--- a/Classes/Renderer/Helper/BlockHelper.php
+++ b/Classes/Renderer/Helper/BlockHelper.php
@@ -23,6 +23,7 @@
namespace Fr\Typo3Handlebars\Renderer\Helper;
+use Fr\Typo3Handlebars\Attribute;
use Fr\Typo3Handlebars\Exception;
use Fr\Typo3Handlebars\Renderer;
@@ -33,12 +34,13 @@
* @license GPL-2.0-or-later
* @see https://github.com/shannonmoeller/handlebars-layouts#block-name
*/
-class BlockHelper implements HelperInterface
+final readonly class BlockHelper implements HelperInterface
{
/**
* @param array $options
* @throws Exception\UnsupportedTypeException
*/
+ #[Attribute\AsHelper('block')]
public function evaluate(string $name, array $options): string
{
$data = $options['_this'];
diff --git a/Classes/Renderer/Helper/ContentHelper.php b/Classes/Renderer/Helper/ContentHelper.php
index 9aef4a8e..971bea46 100644
--- a/Classes/Renderer/Helper/ContentHelper.php
+++ b/Classes/Renderer/Helper/ContentHelper.php
@@ -23,6 +23,7 @@
namespace Fr\Typo3Handlebars\Renderer\Helper;
+use Fr\Typo3Handlebars\Attribute;
use Fr\Typo3Handlebars\Renderer;
use Psr\Log;
@@ -33,16 +34,17 @@
* @license GPL-2.0-or-later
* @see https://github.com/shannonmoeller/handlebars-layouts#content-name-modeappendprependreplace
*/
-class ContentHelper implements HelperInterface
+final readonly class ContentHelper implements HelperInterface
{
public function __construct(
- protected readonly Log\LoggerInterface $logger,
+ private Log\LoggerInterface $logger,
) {}
/**
* @param array $options
* @return string|bool
*/
+ #[Attribute\AsHelper('content')]
public function evaluate(string $name, array $options)
{
$data = $options['_this'];
diff --git a/Classes/Renderer/Helper/ExtendHelper.php b/Classes/Renderer/Helper/ExtendHelper.php
index 5d869885..0b9de3e0 100644
--- a/Classes/Renderer/Helper/ExtendHelper.php
+++ b/Classes/Renderer/Helper/ExtendHelper.php
@@ -23,6 +23,7 @@
namespace Fr\Typo3Handlebars\Renderer\Helper;
+use Fr\Typo3Handlebars\Attribute;
use Fr\Typo3Handlebars\Renderer;
/**
@@ -32,12 +33,13 @@
* @license GPL-2.0-or-later
* @see https://github.com/shannonmoeller/handlebars-layouts#extend-partial-context-keyvalue-
*/
-class ExtendHelper implements HelperInterface
+final readonly class ExtendHelper implements HelperInterface
{
public function __construct(
- protected readonly Renderer\RendererInterface $renderer,
+ private Renderer\RendererInterface $renderer,
) {}
+ #[Attribute\AsHelper('extend')]
public function evaluate(string $name): string
{
// Get helper options
diff --git a/Classes/Renderer/Helper/RenderHelper.php b/Classes/Renderer/Helper/RenderHelper.php
index 1ebfccd4..d4d5c164 100644
--- a/Classes/Renderer/Helper/RenderHelper.php
+++ b/Classes/Renderer/Helper/RenderHelper.php
@@ -23,6 +23,7 @@
namespace Fr\Typo3Handlebars\Renderer\Helper;
+use Fr\Typo3Handlebars\Attribute;
use Fr\Typo3Handlebars\DataProcessing;
use Fr\Typo3Handlebars\Exception;
use Fr\Typo3Handlebars\Renderer;
@@ -37,17 +38,18 @@
* @license GPL-2.0-or-later
* @see https://github.com/frctl/fractal/blob/main/packages/handlebars/src/helpers/render.js
*/
-class RenderHelper implements HelperInterface
+final readonly class RenderHelper implements HelperInterface
{
public function __construct(
- protected readonly Renderer\RendererInterface $renderer,
- protected readonly Core\TypoScript\TypoScriptService $typoScriptService,
- protected readonly Frontend\ContentObject\ContentObjectRenderer $contentObjectRenderer,
+ private Renderer\RendererInterface $renderer,
+ private Core\TypoScript\TypoScriptService $typoScriptService,
+ private Frontend\ContentObject\ContentObjectRenderer $contentObjectRenderer,
) {}
/**
* @throws Exception\InvalidConfigurationException
*/
+ #[Attribute\AsHelper('render')]
public function evaluate(string $name): SafeString
{
// Get helper options
diff --git a/Classes/Renderer/Helper/VarDumpHelper.php b/Classes/Renderer/Helper/VarDumpHelper.php
index a1f57645..abd60f41 100644
--- a/Classes/Renderer/Helper/VarDumpHelper.php
+++ b/Classes/Renderer/Helper/VarDumpHelper.php
@@ -23,7 +23,8 @@
namespace Fr\Typo3Handlebars\Renderer\Helper;
-use TYPO3\CMS\Core\Utility\DebugUtility;
+use Fr\Typo3Handlebars\Attribute;
+use TYPO3\CMS\Core;
/**
* VarDumpHelper
@@ -31,16 +32,17 @@
* @author Elias Häußler
* @license GPL-2.0-or-later
*/
-class VarDumpHelper implements HelperInterface
+final readonly class VarDumpHelper implements HelperInterface
{
/**
* @param array $context
*/
+ #[Attribute\AsHelper('varDump')]
public static function evaluate(array $context): string
{
\ob_start();
- DebugUtility::debug($context['_this']);
+ Core\Utility\DebugUtility::debug($context['_this']);
return (string)\ob_get_clean();
}
diff --git a/Classes/Renderer/Template/TemplatePaths.php b/Classes/Renderer/Template/TemplatePaths.php
index 1524c758..e9285aab 100644
--- a/Classes/Renderer/Template/TemplatePaths.php
+++ b/Classes/Renderer/Template/TemplatePaths.php
@@ -24,6 +24,7 @@
namespace Fr\Typo3Handlebars\Renderer\Template;
use Fr\Typo3Handlebars\Configuration\Extension;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
@@ -51,6 +52,10 @@ class TemplatePaths
*/
public function __construct(
protected readonly ConfigurationManagerInterface $configurationManager,
+ #[Autowire([
+ self::TEMPLATES => '%handlebars.template_root_paths%',
+ self::PARTIALS => '%handlebars.partial_root_paths%',
+ ])]
protected readonly array $viewConfiguration = [],
protected readonly string $type = self::TEMPLATES,
) {}
diff --git a/Configuration/Services.php b/Configuration/Services.php
index 2cbbe088..f55ab794 100644
--- a/Configuration/Services.php
+++ b/Configuration/Services.php
@@ -23,13 +23,28 @@
namespace Fr\Typo3Handlebars\DependencyInjection;
+use Fr\Typo3Handlebars\Attribute\AsHelper;
use Fr\Typo3Handlebars\DependencyInjection\Extension\HandlebarsExtension;
+use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator, ContainerBuilder $container): void {
$container->registerExtension(new HandlebarsExtension());
$container->addCompilerPass(new DataProcessorPass('handlebars.processor', 'handlebars.compatibility_layer'));
- $container->addCompilerPass(new HandlebarsHelperPass('handlebars.helper', 'handlebars.renderer'));
+ $container->addCompilerPass(new HandlebarsHelperPass(AsHelper::TAG_NAME, 'handlebars.renderer'));
$container->addCompilerPass(new FeatureRegistrationPass(), priority: 30);
+
+ $container->registerAttributeForAutoconfiguration(
+ AsHelper::class,
+ static function (ChildDefinition $definition, AsHelper $attribute, \Reflector $reflector): void {
+ $definition->addTag(
+ AsHelper::TAG_NAME,
+ [
+ 'identifier' => $attribute->identifier,
+ 'method' => $attribute->method ?? ($reflector instanceof \ReflectionMethod ? $reflector->getName() : '__invoke'),
+ ],
+ );
+ },
+ );
};
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
index fc4f9d8c..5ce43453 100644
--- a/Configuration/Services.yaml
+++ b/Configuration/Services.yaml
@@ -9,18 +9,12 @@ services:
exclude:
- '../Classes/DependencyInjection/*'
- # Renderer
- handlebars.renderer:
- class: 'Fr\Typo3Handlebars\Renderer\HandlebarsRenderer'
- arguments:
- $templateResolver: '@handlebars.template_resolver'
- $partialResolver: '@handlebars.partial_resolver'
- $cache: '@handlebars.cache'
- $defaultData: '%handlebars.default_data%'
- tags: ['handlebars.renderer']
-
+ Fr\Typo3Handlebars\Cache\CacheInterface:
+ alias: 'handlebars.cache'
Fr\Typo3Handlebars\Renderer\RendererInterface:
alias: 'handlebars.renderer'
+ Fr\Typo3Handlebars\Renderer\Template\TemplateResolverInterface:
+ alias: 'handlebars.template_resolver'
# Template
handlebars.template_resolver:
@@ -33,15 +27,8 @@ services:
arguments:
$templateRootPaths: '@handlebars.template_paths.partial_root_paths'
- Fr\Typo3Handlebars\Renderer\Template\TemplateResolverInterface:
- alias: 'handlebars.template_resolver'
-
handlebars.template_paths:
class: 'Fr\Typo3Handlebars\Renderer\Template\TemplatePaths'
- arguments:
- $viewConfiguration:
- template_root_paths: '%handlebars.template_root_paths%'
- partial_root_paths: '%handlebars.partial_root_paths%'
handlebars.template_paths.template_root_paths:
parent: 'handlebars.template_paths'
arguments:
@@ -51,35 +38,12 @@ services:
arguments:
$type: 'partial_root_paths'
- # Data processor
- Fr\Typo3Handlebars\DataProcessing\SimpleProcessor:
- public: true
-
- # Handlebars Helper
- Fr\Typo3Handlebars\Renderer\Helper\VarDumpHelper:
- tags:
- - name: handlebars.helper
- identifier: 'varDump'
- method: 'evaluate'
-
# Cache
- handlebars.cache:
- class: 'Fr\Typo3Handlebars\Cache\HandlebarsCache'
- arguments:
- $cache: '@cache.handlebars'
-
- Fr\Typo3Handlebars\Cache\CacheInterface:
- alias: 'handlebars.cache'
-
cache.handlebars:
class: TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache']
arguments: ['handlebars']
- # Compatibility
- Fr\Typo3Handlebars\Compatibility\View\HandlebarsViewResolver:
- public: true
-
handlebars:
default_data: []
template:
diff --git a/Tests/Functional/Fixtures/test_extension/Classes/JsonHelper.php b/Tests/Functional/Fixtures/test_extension/Classes/JsonHelper.php
index 75794046..4aabe29f 100644
--- a/Tests/Functional/Fixtures/test_extension/Classes/JsonHelper.php
+++ b/Tests/Functional/Fixtures/test_extension/Classes/JsonHelper.php
@@ -23,6 +23,7 @@
namespace Fr\Typo3Handlebars\TestExtension;
+use Fr\Typo3Handlebars\Attribute;
use Fr\Typo3Handlebars\Renderer;
use LightnCandy\SafeString;
@@ -37,6 +38,7 @@ final class JsonHelper implements Renderer\Helper\HelperInterface
/**
* @param array $context
*/
+ #[Attribute\AsHelper('jsonEncode')]
public function encode(array $context): SafeString
{
return new SafeString(json_encode($context['_this'], JSON_THROW_ON_ERROR));
diff --git a/Tests/Functional/Fixtures/test_extension/Configuration/Services.yaml b/Tests/Functional/Fixtures/test_extension/Configuration/Services.yaml
new file mode 100644
index 00000000..8c54789c
--- /dev/null
+++ b/Tests/Functional/Fixtures/test_extension/Configuration/Services.yaml
@@ -0,0 +1,7 @@
+services:
+ _defaults:
+ autowire: true
+ autoconfigure: true
+
+ Fr\Typo3Handlebars\TestExtension\:
+ resource: '../Classes/*'
diff --git a/Tests/Unit/DependencyInjection/FeatureRegistrationPassTest.php b/Tests/Unit/DependencyInjection/FeatureRegistrationPassTest.php
index 8359f6ea..90a8951c 100644
--- a/Tests/Unit/DependencyInjection/FeatureRegistrationPassTest.php
+++ b/Tests/Unit/DependencyInjection/FeatureRegistrationPassTest.php
@@ -26,6 +26,7 @@
use Fr\Typo3Handlebars as Src;
use Fr\Typo3Handlebars\Tests;
use PHPUnit\Framework;
+use Psr\Container;
use Psr\Log;
use Symfony\Component\Config;
use Symfony\Component\DependencyInjection;
@@ -136,6 +137,9 @@ private function buildContainer(): DependencyInjection\ContainerBuilder
$container->register(Frontend\ContentObject\ContentObjectRenderer::class);
$container->register(Log\LoggerInterface::class, Log\NullLogger::class);
+ // Aliases
+ $container->setAlias(Container\ContainerInterface::class, 'service_container');
+
// Provide dummy extension configuration class
$dummyExtensionConfiguration = new Tests\Unit\Fixtures\Classes\DummyExtensionConfiguration($this->activatedFeatures);
$container->set(Core\Configuration\ExtensionConfiguration::class, $dummyExtensionConfiguration);