---
title: "TemplateResolver"
manual: "Handlebars"
version: "main"
permalink: "https://docs.typo3.org/permalink/cpsit/typo3-handlebars:developer-corner-template-resolver@main"
source: "DeveloperCorner/TemplateResolver.rst"
rendered: "2026-09-29T09:05:57+00:00"
---

# TemplateResolver {#developer-corner-template-resolver}

Implement the
[\\CPSIT\\Typo3Handlebars\\Renderer\\Template\\TemplateResolver](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:cpsit-typo3handlebars-renderer-template-templateresolver@main)
interface to change how template and partial names are resolved to absolute file
paths — for example to support a different directory layout, an additional file
extension, or a database-driven path lookup.

The extension ships two implementations:
`\CPSIT\Typo3Handlebars\Renderer\Template\FlatTemplateResolver` (the
default) and
`\CPSIT\Typo3Handlebars\Renderer\Template\HandlebarsTemplateResolver`.

`\CPSIT\Typo3Handlebars\Renderer\Template\BaseTemplateResolver` implements
`supports()` and provides protected helpers for normalizing root paths and
resolving filenames with `EXT:` syntax. Extending it keeps
implementations concise.

-   **interface TemplateResolver**

    -   *Fully qualified name:* `\CPSIT\Typo3Handlebars\Renderer\Template\TemplateResolver`

    -   **supports(string $fileExtension)**

        Return `true` if this resolver handles the given file extension.

        -   *param string $fileExtension:* File extension without leading dot.
        -   *returntype:* bool

    -   **resolveTemplatePath(string $templatePath, ?string $format = null)**

        Resolve a template name or relative path to its absolute file path.

        -   *param string $templatePath:* Template name or relative path.
        -   *param string|null $format:* Optional file extension override.
        -   *returntype:* string

    -   **resolvePartialPath(string $partialPath, ?string $format = null)**

        Resolve a partial name or relative path to its absolute file path.

        -   *param string $partialPath:* Partial name or relative path.
        -   *param string|null $format:* Optional file extension override.
        -   *returntype:* string

## FlatTemplateResolver {#developer-corner-template-resolver-flat}

`FlatTemplateResolver` is the default implementation. It scans all
configured root paths recursively and builds an in-memory map of every
template file, keyed by its bare filename (without directory). A lookup
therefore succeeds regardless of where in the directory tree the file lives.

Template and partial names must be prefixed with `@` to trigger flat
resolution, optionally with a `--<variant>` suffix that falls back to
the base name (see [Referencing templates and partials](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:templates-names@main) for usage). A name without the
prefix is passed directly to `HandlebarsTemplateResolver` (see below).

When the same filename exists under multiple root paths, the higher-priority
root path wins (see [Template paths](https://docs.typo3.org/permalink/cpsit/typo3-handlebars:template-paths@main)). Within a single root path, files
are sorted by name and the first occurrence is used, matching Fractal's
uniqueness guarantee.

## HandlebarsTemplateResolver {#developer-corner-template-resolver-handlebars}

`HandlebarsTemplateResolver` resolves template and partial names as
paths relative to the configured root paths. Given the name `Blog/List`,
it searches each root path (highest priority first) for a matching file —
for example `Blog/List.hbs`.

This resolver is used as the fallback inside `FlatTemplateResolver`
for any name that does not start with `@`, so both resolution strategies
are active at the same time.

## Example implementation {#developer-corner-template-resolver-example}

**EXT:my_extension/Classes/Renderer/Template/MyTemplateResolver.php**

```php
namespace Vendor\Extension\Renderer\Template;

use CPSIT\Typo3Handlebars\Exception;
use CPSIT\Typo3Handlebars\Renderer\Template\BaseTemplateResolver;
use CPSIT\Typo3Handlebars\Renderer\Template\TemplatePaths;

final readonly class MyTemplateResolver extends BaseTemplateResolver
{
    public function __construct(
        private TemplatePaths $templatePaths,
    ) {}

    public function resolveTemplatePath(string $templatePath, ?string $format = null): string
    {
        [$templateRootPaths] = $this->resolveTemplatePaths($this->templatePaths);

        foreach (array_reverse($templateRootPaths) as $rootPath) {
            $filename = $this->resolveFilename($templatePath, $rootPath, $format ?? 'hbs');

            if (is_file($filename)) {
                return $filename;
            }
        }

        throw new Exception\TemplatePathIsNotResolvable($templatePath);
    }

    public function resolvePartialPath(string $partialPath, ?string $format = null): string
    {
        [, $partialRootPaths] = $this->resolveTemplatePaths($this->templatePaths);

        foreach (array_reverse($partialRootPaths) as $rootPath) {
            $filename = $this->resolveFilename($partialPath, $rootPath, $format ?? 'hbs');

            if (is_file($filename)) {
                return $filename;
            }
        }

        throw new Exception\PartialPathIsNotResolvable($partialPath);
    }
}
```

## Wiring the implementation {#developer-corner-template-resolver-wire}

Register the custom resolver as the implementation of the
`TemplateResolver` interface in your extension's `Services.yaml`:

**Configuration/Services.yaml**

```yaml
services:
  CPSIT\Typo3Handlebars\Renderer\Template\TemplateResolver:
    alias: Vendor\Extension\Renderer\Template\MyTemplateResolver
```
