---
title: "Modify fields with the PSR-14 event"
manual: "Headless Content Blocks"
version: "main"
permalink: "https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:modify-fields-with-the-psr-14-event@main"
source: "Howto/ModifyFieldsWithEvent.rst"
rendered: "2026-09-22T01:10:25+00:00"
---

# Modify fields with the PSR-14 event {#modify-fields-with-the-psr-14-event}

This guide shows the legacy way of overriding single field values — the `ModifyArrayRecursiveToArrayEvent`. **It is deprecated** and kept for backwards compatibility; prefer normalizers or field value transformers for new code.

## Why it is deprecated {#why-it-is-deprecated}

The event predates the normalizer registry. It runs per field on *every* record conversion, carries ContentBlocks internals in its payload, and cannot express value-type dispatch cleanly. The modern equivalents:

| Legacy (event) | Modern |
| --- | --- |
| Override by field name | [Field value transformer](https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:register-a-field-value-transformer@main) (strings) |
| Override by value type | [Custom normalizer](https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:register-a-custom-normalizer@main) |
| Whole-block post-processing | [headless.php](https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:post-process-json-with-headless-php@main) |

The event keeps firing with its original payload until the next minor release; listeners continue to work unchanged until then.

## The listener {#the-listener}

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\EventListener;

use Netzbewegung\NbHeadlessContentBlocks\Event\ModifyArrayRecursiveToArrayEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;

#[AsEventListener]
final class MyCustomListener
{
    public function __invoke(ModifyArrayRecursiveToArrayEvent $event): void
    {
        // Custom handling by field name (column!)
        if ($event->getKey() === 'tx_my_vendor_field_name') {
            $processedValue = strtoupper((string)$event->getValue());
            $event->setProcessedValue($processedValue);
        }

        // Custom handling for all text fields
        if (
            $event->getTcaFieldDefinition() !== null
            && $event->getTcaFieldDefinition()->fieldType instanceof \TYPO3\CMS\ContentBlocks\FieldType\TextFieldType
        ) {
            $event->setProcessedValue(strtoupper((string)$event->getValue()));
        }
    }
}
```

Semantics:

-   `getKey()` is the **database column** (pre identifier mapping) — `tx_my_vendor_field_name`, not `my_field`.
-   `setProcessedValue()` marks the field as handled; the value lands in the JSON under the mapped field identifier.
-   Unhandled fields fall through to the normal conversion.
-   The event fires for **every field of every record** — return fast.

## Migration {#migration}

Replace `setProcessedValue($value)` calls with a transformer (string values) or normalizer (everything else). The migrated code is smaller, testable in isolation, and independent of ContentBlocks internals.
