whoami

Lucas Jenß

cat /etc/motd

The Coding Journal ツ — Notes taken on an epic coding journey. Technical solutions, debugging notes, and practical guides from the trenches of software development.

Close-up of white dominoes with black dots standing on green felt surface, shallow depth of field, focused mood

ls -la ~/languages/

total 8
drwxr-xr-x
▶ PHP
▶ Ruby
▶ Scala
▶ C#
▶ JavaScript
▶ Objective-C
▶ Shell Scripting

ls -la ~/toolchain/

total 7
drwxr-xr-x
▶ Typo3
▶ Akka
▶ Capistrano
▶ Git
▶ MAMP
▶ Adobe Illustrator
▶ NSTrackingArea (Cocoa)

uname -a

platforms
drwxr-xr-x
▶ Mac OS X
▶ Unix

Custom TYPO3 data processors for Fluid variables

Fluid keeps rendering surprisingly separate from the data behind it. A template receives variables such as {page}, {data}, {settings}, and anything supplied by a controller or data processor. When a project needs a label, visibility rule, or derived value, placing the logic directly in Fluid makes the template harder to test and often harder to reuse.

A custom TYPO3 data processor gives that transformation a clear home. It receives the current variable set, performs a focused change, and returns values that Fluid can consume. This approach suits repeated content elements, editorial notices, and calculated labels. The important distinction is that a processor does not rewrite every Fluid view variable: it contributes selected keys, and the shape of those keys becomes part of your template contract.

Where Fluid variables come from

During rendering, Fluid builds its variables from the page, content object, TypoScript, and any configured data processors. The standard {data} variable often represents the current record, while {page} exposes page-level information. A processor sits between those sources and the template, receiving the variables available at that point. That position makes it useful for enriching a record without coupling the transformation to markup.

The returned array is the processor’s real output. A key such as siteNotice becomes {siteNotice} in Fluid, and nested keys become dot paths such as {siteNotice.heading}. Returning ['siteNotice' => [...]] does not change {data} or {page}; it creates or replaces only its own namespace. If several processors produce the same key, their order matters, so use distinct names unless later processing is intentional.

Context can also drive the transformation. For a notice published for a Sydney or Melbourne office, local time may determine the label. Those cities use AEST or AEDT depending on daylight saving, while Brisbane remains on UTC+10 year-round. Keeping that rule in PHP avoids scattering date checks through templates. An Australian agency may also maintain a TYPO3 site beside a WordPress property; resources for Elementor theme options belong to that separate platform and should not become Fluid variables.

Designing a safe variable contract

Start with the smallest shape the template actually needs. For example, a site notice might need heading, summary, and enabled. Put processor-specific options under a siteNotice key so they remain separate from values another extension might pass. This is especially helpful in Australian development teams, where “organisation” and “initialise” may appear in content while a technical key still follows the project’s chosen convention.

Decide whether the processor creates a new variable or returns a modified copy of an inherited one. Creating {siteNotice} is usually safer than replacing {data}, because {data} may already contain fields needed by other Fluid sections. If a derived page label really belongs to {data}, copy the current array, change the one field, and return the whole copy under data. To change {siteNotice.heading}, likewise return the complete siteNotice array.

Keep configuration values separate from runtime variables. processorConfiguration carries options from your rendering setup; contentObjectVariables carries values already available to the template. Escape text in Fluid, validate allowed audiences, and parse booleans deliberately, since an option such as 0 or false arrives as configuration text rather than a native boolean. Australian quotes often separate GST from the AUD amount, so an enrichment service also needs a clear budget owner before it becomes a render dependency.

Implementing the processor

Put the class in a Composer-autoloaded extension and implement TYPO3’s DataProcessorInterface. The example uses the three-argument getData contract used by modern TYPO3 releases; check the interface in your installed version when maintaining an older site.

<?php

declare(strict_types=1);

namespace Vendor\Site\DataProcessing;

use TYPO3\CMS\Core\DataProcessing\DataProcessorInterface;

final class SiteNoticeProcessor implements DataProcessorInterface
{
    public function getData(
        array $contentObjectConfiguration,
        array $contentObjectVariables,
        array $processorConfiguration
    ): array {
        $options = $processorConfiguration['siteNotice'] ?? [];
        $options = is_array($options) ? $options : [];

        $existing = $contentObjectVariables['siteNotice'] ?? [];
        $existing = is_array($existing) ? $existing : [];

        $heading = trim((string)($options['heading'] ?? ($existing['heading'] ?? '')));
        $summary = trim((string)($options['summary'] ?? ($existing['summary'] ?? '')));
        $enabled = filter_var(
            $options['enabled'] ?? ($existing['enabled'] ?? false),
            FILTER_VALIDATE_BOOLEAN
        );

        return [
            'siteNotice' => array_replace($existing, [
                'heading' => $heading,
                'summary' => $summary,
                'enabled' => $enabled,
            ]),
        ];
    }
}

The second argument is the current Fluid variable set. Reading siteNotice from it lets the processor preserve keys supplied by an earlier processor. The array_replace call then applies only the notice’s own fields, leaving unrelated keys within that namespace intact. The first argument describes the content object and is available when the transformation needs more context. If you add constructor dependencies later, expose the class as a public service in the extension’s service configuration.

The class has no template-specific markup or direct database access, which makes it straightforward to unit test. When something fails, confirm the actual boundary before changing the implementation; handling native library load failures demonstrates that discipline in an Android NDK context. For a Fluid processor, inspect the returned array first, then the configuration and rendered template.

Three approaches suit different kinds of change:

Approach What Fluid receives Effect on other variables Good fit
A new {siteNotice} namespace A new or replaced notice array {data} and {page} stay unchanged Shared notices, flags and computed labels
A copied {data} array The complete record array with your changed field Other namespaces stay unchanged A deliberate change to a record field
Inline template logic Only the edited output No reusable processing state A genuinely one-off presentation change

Connecting it to Fluid

Attach the class through the dataProcessing configuration of the Fluid content object. The numeric key establishes processing order; the nested values become processorConfiguration for the class.

page = PAGE
page.10 = FLUID
page.10 {
    file = EXT:site_package/Resources/Private/Templates/Page.html
    dataProcessing {
        10 = Vendor\Site\DataProcessing\SiteNoticeProcessor
        10.siteNotice {
            heading = Latest site update
            summary = Check the maintenance window
            enabled = 1
        }
    }
}

The template can then use the result without any PHP calls. Keep conditionals close to the data they protect, and avoid assuming that a nested key exists when a processor might not have run.

<f:if condition="{siteNotice.enabled}">
    <h2>{siteNotice.heading}</h2>
    <p>{siteNotice.summary}</p>
</f:if>

Configure the processor where the page template is rendered, not in every component that displays the notice. That centralises default text and access rules and gives you one place to apply caching or a timeout. The separation of work from waiting described in chaining non-blocking Akka queries comes from Scala rather than PHP, but it remains a useful design reference: never make a visitor wait for an unbounded upstream call.

Testing and troubleshooting

Start with the output, not the markup. Log the processor’s returned array in a development environment, then check the namespace Fluid receives. A missing key often means the processor was never configured, the class was not autoloaded, or a later processor replaced the namespace. For boolean options, test 0, 1, true, false and an absent value; PHP casts the non-empty string "false" to true unless parsing is explicit.

The same discipline applies when a runtime dependency fails: confirm the failing boundary before changing the implementation. For Fluid, the equivalent boundary is configuration, PHP processing and final template output, in that order. This prevents a template workaround from hiding a processor that never ran or returned an unexpected shape.

If enrichment depends on a slow service, keep that work out of the render path where possible. Fetch upstream data before rendering, apply a timeout, and cache a stable result rather than making every visitor wait. A processor that changes only local values can usually run during each request, but a processor that depends on remote data deserves a more deliberate caching strategy.

Test the processor with unit cases for defaults, overrides and unexpected input, then confirm the rendered notice in a real template. In a casual Australian stand-up, “no worries” can close a discussion without settling every edge case, so acceptance criteria still need explicit examples. Australian public-sector procurements often specify WCAG 2.2 AA, making heading order, link purpose and contrast part of acceptance rather than final polish.


Create a branch for the feature, add the processor to a site extension, and connect one dataProcessing entry before touching the template. Return a single, documented namespace, cover it with tests for defaults and overrides, and render it once in the real page context. That narrow slice gives editorial staff a predictable notice variable while keeping the PHP logic reusable for future content elements. Implement that path in your next release.


cat ~/interests.json

KeyValue
editorTerminal-first workflow
osMac OS X / Unix
vcsGit, distributed version control
deployCapistrano, cron automation
graphicsSVG, Adobe Illustrator troubleshooting
networkingIP validation, SSH, VPN

git log --oneline --reverse

2013-10-30

Solving SVG import issues in Adobe Illustrator CS6 and CC

When importing an SVG into Illustrator, the operation fails with an unknown error [CANT]. A workaround for this Adobe-side bug.

2013

Solving NDK build issues on OS X

Troubleshooting native development kit compilation problems on Mac OS X.

2013

Programmatically adding PHP generated TypoScript to the backend configuration

Integrating dynamically generated TypoScript into Typo3 backend setups using PHP.

2013

ArgumentError: Could not parse PKey: no start line

Debugging an SSH key parsing error encountered during deployment.

2011-08-04

Validating IP-Addresses in PHP

Using PHP filter functions with flags like FILTER_FLAG_IPV4 and FILTER_FLAG_IPV6, and understanding how filter_var handles reserved IP addresses.

2011-07-09

Cocoa: Using NSTrackingArea

A short tutorial on using Cocoa's NSTrackingArea to capture mouseEntered and mouseExited events.


cat ~/contact.txt

github: github.com/x3ro
stackoverflow: x3ro
coderwall: coderwall.com/x3ro
twitter: @x3rames