This extension documentation is published under the
CC BY-NC-SA 4.0
(Creative Commons) license.
An extension for TYPO3 CMS that provides form rendering with Handlebars,
based on the EXT:handlebars extension. It is designed to provide rendering
options for all default form elements shipped by EXT:form, while rendering for
custom form elements can be easily configured using dedicated interface implementations.
Introduction
A quick overview about the main features provided by this extension.
Installation
Instructions on how to install this extension, and which TYPO3 and PHP versions
are currently supported.
Configuration
Learn how to configure the extension in various ways. This includes site
configuration and TypoScript configuration.
Usage
This section describes how to use this extension in various ways.
Developer corner
A quick overview about all relevant classes provided by this extension.
Migration
Required migration steps when upgrading the extension to a new major version.
Introduction
What does it do?
The extension provides a way to render forms built with the
TYPO3 Form Framework. It allows rendering of
generic forms, defined by a comprehensive TypoScript rendering definition.
This definition can be extended to a specific form to allow customizating the
output of various forms. In addition, the extension allows to modify the
build mechanisms of so called view models, which makes the whole concept
very dynamic and flexible.
Features
Support for all default form elements
Ability to define generic form rendering definitions
Possibility to override form rendering for specific form definitions
Easy to extend and customize for custom form elements
Compatible with TYPO3 13.4 LTS and 14.3 LTS
Support
There are several ways to get support for this extension:
The extension ships a site set that provides default TypoScript configuration and site
settings. Include it in your site's config.yaml:
config/sites/<identifier>/config.yaml
dependencies:-cpsit/handlebars-forms
Copied!
The site set requires two other sets as dependencies:
cpsit/handlebars-content-element (from EXT:handlebars)
and typo3/form (from EXT:form). Both are declared
in the extension's own set, so you do not need to list them separately.
Configuration
Site settings
The following settings are exposed through the site set and can be overridden per site.
Name of the Handlebars template used for rendering a form when no per-form
template is configured. Corresponds to a template file in the configured
Handlebars template root paths, e.g. Form.hbs.
Note
The default Form.hbs template serves as placeholder to allow a smooth
form rendering integration. It only shows a rendering warning and must be
overridden by a concrete template which handles the whole rendering.
TypoScript
The site set sets up a TypoScript object at
plugin.tx_form.handlebarsForms,
where integrators define how each form is rendered. The structure is:
plugin.tx_form.handlebarsForms {
# Applied to every form (fallback)
default {
templateName = {$handlebars_forms.view.templateName}
dataProcessing {
10 = process-form
10 {
# ... HBS_* configuration
}
}
}
# Override for a specific form – merged on top of "default"
my_contact_form {
templateName = ContactForm
}
}
Copied!
When a form is rendered, the extension looks up configuration blocks in the following
order. All matching blocks are merged, with later entries winning:
default – applied to every form
Form unique identifier (e.g.
my-contact-form-123)
Original form identifier before suffixes are appended (e.g.
my-contact-form)
Form persistence identifier (the YAML file path, e.g.
EXT:my_extension/Resources/Private/Forms/ContactForm.form.yaml)
The
templateName key names the Handlebars template file (without extension)
that receives the data produced by the process-form processor
as its template context.
Note
The
dataProcessing block follows the same TypoScript data-processor syntax
used elsewhere in TYPO3 (e.g. inside
FLUIDTEMPLATE). The
process-form processor identifier is provided by this
extension.
See Conditions in the processor reference for details on
using
if to conditionally omit keys from the output.
Usage
This section explains how to set up and use EXT:handlebars_forms in a TYPO3 project.
The extension works in two phases:
Form renderer –
HandlebarsFormRenderer is registered with EXT:form.
When a form is rendered on the frontend, EXT:form delegates rendering to this
class, which resolves a Handlebars view based on the TypoScript configuration
under
plugin.tx_form.handlebarsForms.
Data processor – The Handlebars template is expected to call the
process-form data processor. This processor walks the EXT:form
renderable tree and builds a plain PHP array from it using
HBS_*
content objects. The resulting array is passed to the Handlebars template as its
context.
This page walks through the minimum steps required to render a form with Handlebars.
Include the site set
Follow the site set instructions in the installation guide to add
cpsit/handlebars-forms to your site's dependencies.
Configure TypoScript
Add a
dataProcessing block under
plugin.tx_form.handlebarsForms.default that maps EXT:form renderables
to
HBS_* content objects. The array built by the processor becomes the
Handlebars template context.
The example below produces a
fields array and a
navItems
array from the current form page, plus a
hiddenFields string:
plugin.tx_form.handlebarsForms {
default {
dataProcessing {
10 = process-form
10 {
formData {
id = HBS_TAG
id.attribute = id
action = HBS_TAG
action.attribute = action
method = HBS_TAG
method.attribute = method
}
fields = HBS_RENDERABLES
fields {
default {
template = @form-field-generic
id = HBS_TAG
id.attribute = id
name = HBS_TAG
name.attribute = name
label = HBS_LABEL
value = HBS_TAG
value.attribute = value
}
# Per-type overrides inherit from default via TypoScript copy operator
Text < .default
Text {
template = @form-field-text
}
Email < .Text
# Suppress Honeypot in the template; render it verbatim instead
Honeypot {
content = HBS_PASSTHROUGH
}
}
navItems = HBS_NAVIGATION
navItems {
previousPage {
label = HBS_LABEL
name = HBS_TAG
name.attribute = name
value = HBS_TAG
value.attribute = value
}
nextPage < .previousPage
submit < .previousPage
}
hiddenFields = HBS_TAG
}
}
}
}
Copied!
Create a Handlebars template
Create a .hbs file in the Handlebars template root path configured by your
EXT:handlebars installation. The default template name is
Form
(configurable via the
handlebars_forms.view.templateName
site setting), so the file should be named Form.hbs.
The template receives the data built by the
process-form processor
directly as its context:
The
hiddenFields value is an HTML string (e.g. CSRF token, page
index). It is emitted by EXT:form's
<f:form> view helper and must be output
without escaping. In Handlebars this is done automatically when the value is a
SafeString – which is exactly what
HBS_TAG (used without
attribute) returns when wrapping tag content.
See also
process-form processor – full reference for the data processor, including
key resolution rules, conditions and TypoScript references
Content objects – reference for all available
HBS_* content
objects with their configuration options
Per-form overrides
To use a different template or a different data structure for a specific form, add a
block keyed by the form identifier. It is merged on top of
default:
plugin.tx_form.handlebarsForms {
my_contact_form {
templateName = ContactForm
dataProcessing {
10 = process-form
10 {
fields =< plugin.tx_form.handlebarsForms.default.dataProcessing.10.fields
fields {
# Extra field type only present in this form
Rating {
template = @form-field-rating
value = HBS_TAG
value.attribute = value
}
}
}
}
}
}
Copied!
process-form processor
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:
The processor iterates all keys in its configuration block and resolves each one by
the following rules, applied in order:
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).
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.
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:
[
'formData' => [
'id' => '…', // resolved by HBS_TAG'method' => '…', // resolved by HBS_TAG
],
'label' => '…', // resolved by HBS_LABEL'staticKey' => 'staticValue',
]
Copied!
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
Configuration for a content object is placed in the dotted sub-tree below the key:
id = HBS_TAG
id.attribute = id
subject = HBS_PROPERTY
subject.path = type
subject.subject = renderable
Copied!
The dotted sub-tree also supports
stdWrap, which is applied to the
resolved value after the content object returns:
label = HBS_LABEL
label.stdWrap.case = upper
Copied!
Conditions
if is supported at two levels and behaves like the built-in
TypoScript function.
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:
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:
someField {
if {
currentValue = HBS_PROPERTY
currentValue.path = required
isTrue.current = 1
}
label = HBS_LABEL
value = HBS_TAG
value.attribute = value
}
Copied!
TypoScript 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:
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.
Content objects
The extension registers the following custom content objects (
HBS_*). They
are only useful inside a
process-form data processor block; using them
elsewhere may log a warning and return an empty string.
Every
HBS_* content object supports the standard stdWrap
sub-key. The value resolved by the content object is passed through
stdWrap
before being stored in the processed data array.
Iterates the child renderables of the current renderable and resolves each one
according to per-type configuration. Returns a list (array).
When used at the top level (form runtime as current renderable), it iterates the
elements of the current page. For composite renderables such as
Fieldset,
it iterates their direct children.
Configuration
fields = HBS_RENDERABLES
fields {
# Per-type configuration (key = EXT:form element type)
Text {
template = @form-field-text
label = HBS_LABEL
value = HBS_TAG
value.attribute = value
}
# Fallback for types without a dedicated block
default {
template = @form-field-generic
}
# Single content object for a type (no sub-configuration)
Honeypot = HBS_PASSTHROUGH
# Suppress a type entirely
SomeType {
if.isTrue = 0
}
}
Copied!
The lookup order for each child element is: exact type key,
default. If
neither matches, the element is skipped.
Frontend register
While iterating,
HBS_RENDERABLES writes two values to the frontend
register that TypoScript conditions can read via register:
HBS_RENDERABLES_COUNT – total number of renderables in the current iteration
HBS_RENDERABLES_CURRENT – zero-based index of the element being processed
(unset after the loop)
Note
Since TYPO3 v14 the register is part of the frontend register stack on the global
request object (
frontend.register.stack request attribute) rather than the
legacy
$GLOBALS['TSFE']->register array. The extension handles both automatically.
HBS_PROPERTY
Reads a property from the current renderable, its view model, or the form runtime
using
Extbase\Reflection\ObjectAccess::getProperty(). Returns whatever type the
property holds (string, array, object, …).
Property path. Supports dotted-path notation for nested access (e.g.
renderingOptions.foo).
subject
subject
Type
string
Default
renderable
The object to read from. One of:
renderable – the current EXT:form renderable (default)
viewModel – the view model built for this renderable
formRuntime – the form runtime instance
Example
renderableType = HBS_PROPERTY
renderableType.path = type
# Read from the view model instead
resourcePointerFields = HBS_PROPERTY
resourcePointerFields {
subject = viewModel
path = children?[resourcePointerFields?]
}
Copied!
HBS_TAG
Reads an HTML attribute (or the inner content) from the tag rendered by the current
renderable's view model. The view model must implement
TagAwareViewModel; this is
the case for all view models built by the built-in
ViewModelBuilder implementations.
Returns a
SafeString (Handlebars will not escape the value).
The tag reflects the final output of the Fluid ViewHelper responsible for rendering the
renderable. For example, the root
FormRuntime object is rendered by the
<formvh:form> view helper, so
HBS_TAG on it returns attributes (or
content) of the
<form> tag that view helper produces. Similarly, a
Text
element is rendered by
<f:form.textfield>, so
HBS_TAG exposes the
attributes of the resulting
<input> tag.
Name of the HTML attribute to read. If omitted, the inner content of the
rendered tag is returned instead.
Example
# Read the "id" attribute of the rendered <input> tag
id = HBS_TAG
id.attribute = id
# Read the inner HTML of the rendered tag (e.g. <textarea> content)
content = HBS_TAG
Copied!
HBS_LABEL
Returns the translated label of the current renderable. If the current view model is
a
FormFieldViewModel, the label is taken from the view model's pre-resolved
label property; otherwise it falls back to
$renderable->getLabel().
Returns a string.
Configuration
No configuration keys.
stdWrap is supported.
label = HBS_LABEL
Copied!
HBS_FORM_VALUE
Reads the current or submitted value of the form element. Internally wraps
EXT:form's
<formvh:renderFormValue> view helper and exposes its result
as a
FormValueViewModel.
Without an
output key the resolved
processedValue is
returned directly.
Output instructions
The
output key accepts one of the following built-in instructions:
The formatted, human-readable value (e.g. option label for select fields).
VALUE
VALUE
Type
string instruction
The raw, machine-readable value.
IS_MULTI_VALUE
IS_MULTI_VALUE
Type
string instruction
Boolean – whether the field holds multiple values (e.g. multi-select,
multi-checkbox).
IS_SECTION
IS_SECTION
Type
string instruction
Boolean – whether the renderable is a section (fieldset, page).
EACH_PROCESSED_VALUE
EACH_PROCESSED_VALUE
Type
string instruction
Iterates over all values and processes each with the sub-configuration in
output.
EACH_VALUE
EACH_VALUE
Type
string instruction
Like
EACH_PROCESSED_VALUE but uses raw values.
Examples
# Summary page: show the human-readable value
value = HBS_FORM_VALUE
value.output = PROCESSED_VALUE
# Multi-value field: iterate over each option
values = HBS_FORM_VALUE
values {
output = EACH_PROCESSED_VALUE
output {
label = HBS_LABEL
selected = HBS_PROPERTY
selected.path = selected
}
}
Copied!
HBS_NAVIGATION
Resolves the navigation buttons (previous page, next page / submit) for the current
form page. Returns a list of processed items. Each item is built by the sub-configuration
keyed by button role.
Button roles
previousPage – previous-page button (only present when not on the first page)
nextPage – next-page button (only present when not on the last page)
submit – submit button (only present on the last page)
Within each role block,
HBS_TAG and
HBS_LABEL operate on
the rendered
<button> tag and the translated button label respectively.
Example
navItems = HBS_NAVIGATION
navItems {
previousPage {
label = HBS_LABEL
name = HBS_TAG
name.attribute = name
value = HBS_TAG
value.attribute = value
}
nextPage < .previousPage
submit < .previousPage
}
Copied!
HBS_PASSTHROUGH
Renders the current renderable using EXT:form's standard Fluid partials and returns
the result as a
SafeString. Useful for elements that do not need a custom template
(e.g.
Honeypot,
ContentElement) or as a fallback.
Configuration
Additional TypoScript keys are converted to plain PHP variables and passed to the Fluid
rendering context:
Honeypot {
content = HBS_PASSTHROUGH
}
# Pass extra variables to the Fluid partial
SomeElement {
content = HBS_PASSTHROUGH
content {
myVariable = someValue
}
}
Copied!
HBS_CHILDREN
Returns the children of the current view model as a list. The view model must implement
CompositeViewModel (e.g.
ViewModelCollection). Returns
null when the
view model has no children.
Each child is processed using the sub-configuration of
HBS_CHILDREN.
Frontend register
While iterating,
HBS_CHILDREN writes two values to the frontend register
that TypoScript conditions can read via register:
HBS_CHILDREN_COUNT – number of children
HBS_CHILDREN_CURRENT – index of the child being processed (unset after the loop)
Note
Since TYPO3 v14 the register is part of the frontend register stack on the global
request object (
frontend.register.stack request attribute) rather than the
legacy
$GLOBALS['TSFE']->register array. The extension handles both automatically.
Returns the translated message for a specific validation error code on the current
renderable. Uses EXT:form's
<formvh:translateElementError> view helper internally.
Iterates over every error and processes each with the sub-configuration in
output. On composite renderables the result is a dictionary keyed by
property path; on leaf elements it is a flat list.
EACH_RENDERABLE
EACH_RENDERABLE
Type
string instruction
Iterates over renderables that have at least one error. Processes each with
the sub-configuration, then passes the result through a second round of
process-form resolution so nested
HBS_* objects are
resolved too. The result is a dictionary keyed by property path.
ERROR_MESSAGE
ERROR_MESSAGE
Type
string instruction
Returns the translated message for the first error in the result set.
RESULT
RESULT
Type
string instruction
Returns a property from the
Result object. Requires
output.propertyPath to be set.
Returns the output of the view helper that was used to build the current view model.
The view model must be a
ViewHelperContainedViewModel. HTML strings are
returned as
SafeString (no double-escaping).
No configuration keys beyond
stdWrap.
Example
# Render the raw <input> tag produced by the view helper
content = HBS_VH_CONTENT
Copied!
Developer corner
This section covers extension points for integrators who need to go beyond what the
built-in
HBS_* content objects and view model builders provide.
Renderables are converted to so-called view models, which is done by dedicated view model builders.
Each view model represents the default view implementation of a renderable, based on the Fluid templates
shipped by EXT:form. Note that some renderables might be represented by various view model implementations,
based on specific aspects outlined below.
Tip
You can also create custom view model builders by implementing the
\CPSIT\Typo3HandlebarsForms\Domain\ViewModel\Builder\ViewModelBuilder interface.
The following renderables are currently supported by this extension:
Contains view models, reflecting both password fields:
Name
Type
Description
passwordField
ViewHelperContainedViewModel
Contains result from <formvh:form.password> view helper invocation for password field.
confirmationField
(a)
ViewHelperContainedViewModel
Result from <formvh:form.password> view helper invocation for password confirmation field.
(b)
FormFieldViewModel
Combination of confirmation label and result from <formvh:form.password> view helper invocation for password confirmation field.
Checkbox
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.checkbox> view helper invocation.
ContentElement
(a)
ViewHelperContainedViewModel
Contains result from <f:cObject> view helper invocation.
(b)
SimpleViewModel
If configured content element UID is invalid.
CountrySelect
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.countrySelect> view helper invocation.
Fieldset
(a)
StandaloneTagViewModel
Contains the <fieldset> tag with class name(s) and additional attributes.
FileUpload,
ImageUpload
(a)
ViewModelCollection
If uploaded resource can be resolved. Contains three view models:
Name
Type
Description
uploadField
ViewHelperContainedViewModel
Contains result from <formvh:form.uploadedResource> view helper invocation for password field.
resourcePointerFields
ViewModelCollection of StandaloneTagViewModel
Optional. References hidden <input> fields with resource pointers, if available.
uploads
ViewModelCollection of FileResourceViewModel
References file uploads, which contain one or two child view models:
resource: Instance of FileReference or PseudoFileReference.
deleteCheckbox: Optional and TYPO3 >= v14 only. FormFieldViewModel with result from <formvh:form.uploadDeleteCheckbox> view helper invocation, which allows to delete an existing file upload on submit.
(b)
ViewHelperContainedViewModel
If uploaded resource cannot be resolved. Contains result from <formvh:form.uploadedResource>
view helper invocation.
Form
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form> view helper invocation.
Hidden
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.hidden> view helper invocation.
MultiCheckbox
(a)
ViewModelCollection
Contains view models which reflect all available options, each as one of:
Type
Description
FormFieldViewModel
If label is available. Contains a combination of label and result from <formvh:form.checkbox> view helper invocation.
ViewHelperContainedViewModel
If associated label is invalid or missing. Contains result from <formvh:form.checkbox> view helper invocation.
Password
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.password> view helper invocation.
RadioButton
(a)
ViewModelCollection
Contains view models which reflect all available options, each as one of:
Type
Description
FormFieldViewModel
If label is available. Contains a combination of label and result from <formvh:form.radio> view helper invocation.
ViewHelperContainedViewModel
If associated label is invalid or missing. Contains result from <formvh:form.radio> view helper invocation.
SingleSelect,
MultiSelect
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.select> view helper invocation. Includes available
<option> tags as children of type StandaloneTagViewModel.
StaticText
(a)
FormFieldViewModel
If label is available. Contains a combination of label and <p> tag.
(b)
StandaloneTagViewModel
If label is invalid or missing. Contains <p> tag with class and text.
Textarea
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.textarea> view helper invocation.
Text,
Date,
Email,
Number,
Telephone,
Url
(a)
ViewHelperContainedViewModel
Contains result from <formvh:form.textfield> view helper invocation.
Every EXT:form renderable that reaches
HBS_RENDERABLES is converted to a
view model before TypoScript processes it. The conversion is
handled by view model builders: classes that implement
\CPSIT\Typo3HandlebarsForms\Domain\ViewModel\Builder\ViewModelBuilder.
When no registered builder claims a renderable, a plain
SimpleViewModel is
used as the fallback.
Implementing the interface
The
ViewModelBuilder interface declares two methods:
supports() is called first; return
true only for the renderable types
your builder handles.
build() is then called to produce the view model.
The easiest starting point is to extend
\CPSIT\Typo3HandlebarsForms\Domain\ViewModel\Builder\AbstractViewModelBuilder.
It takes care of the boilerplate:
Wraps the rendering inside a simulated
<formvh:renderRenderable> context
so EXT:form's state is correct.
Applies grid-column classes when the renderable is inside a
GridRow.
Provides
renderAdditionalAttributes() to resolve
fluidAdditionalAttributes
from the element's properties.
Override
renderRenderable() to produce your custom view model; return
null
from it to fall back to the default
ViewHelperContainedViewModel that wraps
the full rendered output of the view helper.
The
ViewModelBuilder interface carries a
#[AutoconfigureTag('handlebars_forms.view_model_builder')] attribute. Any class that
implements the interface is therefore registered automatically via Symfony DI when
autowiring is enabled (the default for extensions that include a Configuration/Services.yaml
with autowire: true).
No explicit YAML service definition is needed.
Builder priority
When multiple builders claim the same renderable type via supports(), the first
one in the service iterator wins. The iterator order is determined by the Symfony DI
priority
tag attribute. Built-in builders are registered without an explicit priority (i.e. priority 0).
To ensure your builder runs before a built-in one, set a higher priority:
Pick the view model type that best matches what your TypoScript configuration will
consume:
Type
When to use
ViewHelperContainedViewModel
Wraps the rendered tag from a Fluid view helper. Use when
HBS_TAG and
HBS_VH_CONTENT need to read from it.
StandaloneTagViewModel
Wraps a manually-built
TagBuilder. Use for composite elements
such as
Fieldset where you construct the tag yourself.
FormFieldViewModel
Combines a label (as
ViewHelperInvocationResult) with a child
view model. Use when
HBS_LABEL should return the
view-helper-resolved label rather than the raw renderable label.
ViewModelCollection
Holds a named map of child view models. Use for multi-part elements
such as
AdvancedPassword or
FileUpload where
the template needs to access named children.
HBS_CHILDREN iterates over these.
SimpleViewModel
Thin wrapper over a renderable with no extra state. Use as a fallback
or for elements whose properties are accessed entirely via
HBS_PROPERTY.
Custom content objects
If the built-in
HBS_* content objects do not cover a required value, you
can create your own by extending
\CPSIT\Typo3HandlebarsForms\ContentObject\AbstractHandlebarsFormsContentObject.
Implementing a custom content object
The abstract base class has one abstract method to implement:
$configuration is the TypoScript sub-tree below your content object's key.
$context exposes the current state:
$context->renderable – the EXT:form renderable being processed
$context->viewModel – its view model
$context->formRuntime – the active form runtime
$context->renderingContext – the Fluid rendering context
Return any value. Strings are returned directly to the TypoScript tree. Non-string
values (arrays, objects) are automatically stored in the
ValueCollector under
a placeholder key;
ProcessFormProcessor replaces the placeholder with the real
value after the full tree has been resolved.
stdWrap is handled automatically by the base class for every
HBS_* and custom content object. If
resolve() returns a stringable
value,
stdWrap is applied directly to it. If the value is non-stringable,
stdWrap receives an empty string but the original value is set as the
currentValue so TypoScript conditions inside
stdWrap can
still read it.
Registration
The
#[AutoconfigureTag('frontend.contentobject', ['identifier' => '...'])]
attribute is sufficient for registration when the class lives in a directory that is
autowired. No explicit YAML service definition is needed.
The identifier must be globally unique across all loaded extensions. Prefixing it
with your vendor name (e.g.
MYVENDOR_FOO) avoids collisions.
Recursing into the TypoScript tree
$context->process() re-invokes the
ProcessFormProcessor pipeline with an
arbitrary TypoScript configuration array. Its primary purpose is to let your content
object re-process the current (or a different) renderable under a different configuration
block — for example, to apply a sub-section of your own configuration, or to switch the
active renderable or view model entirely before the pipeline runs.
The
ContextStack is a shared singleton (shared: true in DI). It holds the
stack of
ValueResolutionContext objects pushed by
ProcessFormProcessor as
it walks the TypoScript tree.
Custom content objects receive the current context as a direct argument to
resolve() – injecting
ContextStack directly is not necessary and is
considered internal API.
Migration
There are currently no migration steps required.
Contribution guide
Thanks for considering contributing to this extension! Since it is
an open source product, its successful further development depends
largely on improving and optimizing it together.
The development of this extension follows the official
TYPO3 coding standards.
To ensure the stability and cleanliness of the code, various code
quality tools are used and most components are covered with test
cases. In addition, we use DDEV
for local development. Make sure to set it up as described below. For
continuous integration, we use GitHub Actions.
Use the following commands to normalize and format the code base:
# Apply all automatic fixes
composer fix
# Apply specific fixes
composer fix:composer
composer fix:editorconfig
composer fix:php
Copied!
Run checks
Use
composer check to run the full code quality pipeline locally.
This command bundles dependency analysis, static analysis, coding style checks,
and Rector in dry-run mode so that potential refactorings can be reviewed
without changing files.
# Run all checks
composer check
# Run specific checks
composer check:deps
composer check:refactor
composer check:static
composer check:style
# Run specific style checks
composer check:style:composer
composer check:style:editorconfig
composer check:style:php
composer check:style:typoscript
Copied!
Run refactorings
Refactorings are intentionally separated from regular checks because they may
change the code base.
# Run all configured refactorings
composer refactor
# Run specific refactorings
composer refactor:php
Copied!
Run tests
Run the full test suite before opening a pull request:
# Run all tests
ddev composer test
ddev composer test:coverage
# Run functional tests
ddev composer test:functional
ddev composer test:functional:coverage
# Run unit tests
ddev composer test:unit
ddev composer test:unit:coverage
# Merge coverage reports
ddev composer test:merge-coverage
Copied!
Coverage reports
Code coverage reports are written to Build/tests/coverage. Open the latest merge
HTML report with:
open Build/tests/coverage/html/_merged/index.html
Copied!
Pull requests
Once the changes are ready, please
submit a pull request
and describe what was changed and why. Ideally, the pull request references an
issue that describes the problem being solved.
All documented code quality tools are executed automatically for pull requests
across the currently supported PHP versions. For details, refer to the GitHub
Actions workflows.
Sitemap
Reference to the headline
Copy and freely share the link
This link target has no permanent anchor assigned.The link below can be used, but is prone to change if the page gets moved.