---
title: "Data processor"
manual: "Handlebars"
version: "main"
permalink: "https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:data-processor@main"
source: "Usage/DataProcessor.rst"
rendered: "2026-09-29T09:18:02+00:00"
---

# Data processor {#data-processor}

> [!NOTE]
> This is the full reference for the data processor. If you just want to get a form
> rendering, start with [Quick start](https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:quick-start@main) instead.

The `process-form` data processor is the core of the extension. It resolves
each key in its TypoScript configuration through content objects in the context of the
top-level renderable (`FormRuntime`), producing a plain PHP array that becomes the
Handlebars template context.

The data processor is registered under the identifier `process-form` and can
be used inside a `dataProcessing` block:

```typoscript
plugin.tx_form.handlebarsForms.default {
    dataProcessing {
        10 = process-form
        10 {
            # processor configuration
        }
    }
}
```

---

-   [Key resolution](https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:key-resolution@main)
-   [Content object configuration](https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:content-object-configuration@main)
-   [Conditions](https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:conditions@main)
-   [TypoScript references](https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:typoscript-references@main)
-   [Renderable context](https://docs.typo3.org/permalink/cpsit/typo3-handlebars-forms:renderable-context@main)

## Key resolution {#process-form-key-resolution}

The processor iterates all keys in its configuration block and resolves each one by
the following rules, applied in order:

1.  **Array value (no string sibling)** – the sub-tree is processed recursively. The
    result is stored as a nested array under the key name (without trailing dot).
1.  **String value matching a registered content object** – the content object is
    rendered with the dotted sub-tree as its configuration. The return value is stored
    under the key name.
1.  **String value not matching any content object** – the raw string is stored as-is.

These rules mean the structure of the TypoScript block directly mirrors the structure
of the resulting PHP array:

```typoscript
10 = process-form
10 {
    # Rule 1: nested array
    formData {
        id = HBS_TAG
        id.attribute = id

        method = HBS_TAG
        method.attribute = method
    }

    # Rule 2: content object
    label = HBS_LABEL

    # Rule 3: literal string
    staticKey = staticValue
}
```

Produces:

```php
[
    'formData' => [
        'id'     => '…',   // resolved by HBS_TAG
        'method' => '…',   // resolved by HBS_TAG
    ],
    'label'     => '…',    // resolved by HBS_LABEL
    'staticKey' => 'staticValue',
]
```

> [!NOTE]
> A key is only written to the output array if its resolved value is not `null`.
> Content objects that cannot resolve a value (e.g. `HBS_TAG` used on a
> view model that is not a `TagAwareViewModel`) return `null` and the key is
> silently omitted.

## Content object configuration {#process-form-content-object-config}

Configuration for a content object is placed in the dotted sub-tree below the key:

```typoscript
id = HBS_TAG
id.attribute = id

subject = HBS_PROPERTY
subject.path = type
subject.subject = renderable
```

The dotted sub-tree also supports `stdWrap`, which is applied to the
resolved value after the content object returns:

```typoscript
label = HBS_LABEL
label.stdWrap.case = upper
```

## Conditions {#process-form-conditions}

`if` is supported at two levels and behaves like the built-in
[TypoScript function](https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/Functions/If.html#if).

It can be placed directly in the processor configuration (or in any nested sub-tree).
When the condition evaluates to `false`, the entire block is skipped and
`null` is returned for its parent key:

```typoscript
fields = HBS_RENDERABLES
fields {
    Fieldset {
        if.isTrue = 0
    }
}
```

The `currentValue` extension in `if` allows the condition to
be evaluated against a value resolved by the processor itself rather than a static
TypoScript value. It accepts a content object expression using the same syntax as the
main configuration:

```typoscript
someField {
    if {
        currentValue = HBS_PROPERTY
        currentValue.path = required
        isTrue.current = 1
    }

    label = HBS_LABEL

    value = HBS_TAG
    value.attribute = value
}
```

## TypoScript references {#process-form-ts-references}

TypoScript copy (`<`) and reference (`=<`) operators are
fully supported. References are resolved before any key in a block is processed,
so the merged configuration is what the content objects see:

```typoscript
Email < .Text

navItems = HBS_NAVIGATION
navItems {
    previousPage {
        # ...
    }
    nextPage < .previousPage
    submit < .previousPage
}

fields =< plugin.tx_form.handlebarsForms.default.dataProcessing.10.fields
```

## Renderable context {#process-form-renderable-context}

Each key in the processor configuration is resolved in the context of the current
renderable. At the top level this is the `FormRuntime` (i.e. the whole form).
When `HBS_RENDERABLES` iterates children, each child key is resolved in
the context of that child renderable and its view model.

The active renderable and view model are accessible to all `HBS_*` content
objects through the `ValueResolutionContext` they receive. This is what allows
`HBS_TAG` to read from the rendered tag of the *current* element rather
than a global one, and why the same `HBS_LABEL` call returns a different
label for each iteration of `HBS_RENDERABLES`.
