Wer in einer TYPO3-Extension ein INSERT INTO tt_content absetzt, umgeht Cache-Invalidierung, Reference Index, Workspace-Versioning und die vom Core vorgesehenen DataHandler-Extension-Points (v. a. SC_OPTIONS-Hook-Klassen unter dem Legacy-Schlüssel t3lib/class.t3lib_tcemain.php, der auf \TYPO3\CMS\Core\DataHandling\DataHandler gemappt wird). Das funktioniert – bis es das nicht mehr tut. Der DataHandler ist die API, die diese Mechanismen zuverlässig orchestriert. Dieser Leitfaden ist mit dem Schwerpunkt TYPO3 v14 geschrieben; wo nötig, sind Übergänge aus v13 erwähnt.
Inhaltsverzeichnis
Die goldene Regel
Warum direktes SQL Cache, Index und Workspaces sabotiert.
DataMap & CmdMap
Create, Update, Delete, Copy, Move – alles über zwei Arrays.
Ausführung & Fehler
Transaktionssicherheit, errorLog und substNEWwithIDs.
CLI & Scheduler
Admin-Kontext, Bootstrap und Symfony Commands.
Hooks
processDatamap, processCmdmap und praktische Listener.
Reference Index & Cache
Cache-Tags, referenceindex:update und clear_cacheCmd.
Workspace-Kompatibilität
Versionierte Records und der neue discard-Befehl (v14).
Häufige Fallstricke
Die vier Fehler, die in fast jeder Extension lauern.
v14 Breaking Changes
Entfernte Properties, ISO8601-Datumswerte und Migration.
Die goldene Regel: Kein rohes SQL für TCA-Tabellen
Für pages, tt_content und jede andere TCA-konfigurierte Tabelle gilt: Verwenden Sie ausschließlich den DataHandler. Rohes SQL (INSERT, UPDATE, DELETE) umgeht sämtliche Integritätsmechanismen, die TYPO3 im Hintergrund ausführt.
| Feature | DataHandler | Rohes SQL |
|---|---|---|
| Reference Index (sys_refindex) | ✓ | ✕ |
| Cache-Invalidierung | ✓ | ✕ |
| Versionshistorie (sys_history) | ✓ | ✕ |
| Workspace-Kompatibilität | ✓ | ✕ |
| SC_OPTIONS-Hooks / dokumentierte Core-Events | ✓ | ✕ |
| FlexForm-Verarbeitung | ✓ | ✕ |
| MM-Relationen | ✓ | ✕ |
| Performance bei Bulk-Reads | Standard | Schneller |
- Custom-Logging-Tabellen ohne TCA-Konfiguration
- Bulk-Analytics und Reporting (rein lesend)
- Migrationsskripte mit explizitem Reference-Index-Rebuild danach
Seit TYPO3 v13.0.1 (und v12.4.11) blockiert der DataHandler Schreibzugriffe auf die sys_file-Tabelle. Zusätzliche Felder gehören in sys_file_metadata. Hintergrund ist das Security Advisory TYPO3-CORE-SA-2024-006.
Die zwei Kernstrukturen
Alles, was der DataHandler tut, wird über zwei Arrays gesteuert: DataMap ($data) für Anlegen und Ändern, CmdMap ($cmd) für Verschieben, Kopieren und Löschen.
DataMap: Records erstellen und aktualisieren
Syntax: $data[tabellenname][uid][feldname] = wert
Für neue Records verwenden Sie einen eindeutigen String mit dem Prefix NEW als UID:
Der DataHandler verarbeitet nur Felder, die in $GLOBALS['TCA'] konfiguriert sind. Felder mit "type" => "none" oder ungültigen Typen werden ignoriert.
CmdMap: Records verschieben, kopieren, löschen
Syntax: $cmd[tabellenname][uid][befehl] = wert
Soft-Delete wird automatisch verwendet, wenn $GLOBALS['TCA'][$table]['ctrl']['delete'] konfiguriert ist.
Ausführung, Fehlerbehandlung und neue UIDs
Der DataHandler ist zustandsbehaftet. Verwenden Sie für jede Operation eine neue Instanz (in der Praxis typischerweise GeneralUtility::makeInstance(DataHandler::class)). Dieselbe Instanz sollten Sie nicht über mehrere unabhängige Schreibvorgänge hinweg wiederverwenden.
DataHandler-Ausführungsablauf: Von der Initialisierung bis zur UID-Auflösung
Basispattern
Nach process_datamap() enthält $dataHandler->substNEWwithIDs die Zuordnung von NEW-Platzhaltern zu echten UIDs. Beispiel: $dataHandler->substNEWwithIDs['NEW_hero'] liefert die tatsächliche UID des angelegten Records.
Erweitert: Eigene DB-Transaktionen (mit Vorsicht)
Die offizielle Dokumentation definiert keinen allgemeinen Transaktionsvertrag für den DataHandler. In Extensions genügt in der Regel zuerst die schlichte API (start → process_datamap() / process_cmdmap()). Eigene beginTransaction() / commit() nur, wenn Sie mehrere Läufe oder eigene SQL-Schritte auf derselben Connection bewusst bündeln — und nach Prüfung von Seiteneffekten und DB-Connection.
CLI und Scheduler-Einsatz
Im CLI-Kontext (Symfony Commands, Scheduler Tasks) existiert kein automatischer Backend-User. Sie müssen Bootstrap::initializeBackendAuthentication() aufrufen, bevor der DataHandler Schreiboperationen durchführt. Andernfalls erhalten Sie Fehler wie Attempt to modify table "pages" without permission.
Der _cli_-Backend-User benötigt die tatsächlich nötigen Rechte für Ihre Tabellen und Seiten. Nicht per Hand $GLOBALS['BE_USER']->user['admin'] = 1 setzen. Verwenden Sie einen echten BackendUserAuthentication-Datensatz mit passenden Rechten und übergeben Sie ihn optional als drittes Argument an start($data, $cmd, $backendUser). Berechtigungen prüfen Sie mit den üblichen TYPO3-Mechanismen — nicht durch ein gefaktes Admin-Flag.
Hooks: Auf Datenbankoperationen reagieren
Der DataHandler bietet SC_OPTIONS-Hook-Klassen, über die Sie auf Datamap- und Cmdmap-Vorgänge reagieren können – für Logging, Benachrichtigungen, externe Synchronisation oder Validierung.
Das Core liefert keine PSR-14-Events mit Namen wie BeforeRecordOperationEvent oder AfterDatabaseOperationsEvent für jeden Datamap-Schritt. Für Reaktionen nach DB-Schreiben sind die Hook-Klassen auf t3lib/class.t3lib_tcemain.php (z. B. processDatamapClass / processCmdmapClass) das etablierte Muster. Unter TYPO3\CMS\Core\DataHandling\Event dokumentiert Core derzeit v. a. Reference-Index- und Link-Parsing-Events — z. B. IsTableExcludedFromReferenceIndexEvent, AppendLinkHandlerElementsEvent — siehe DataHandling-Events in der Core-Doku und \TYPO3\CMS\Core\DataHandling\Event.
Verfügbare Hooks
| Hook | Zeitpunkt | Methode |
|---|---|---|
| processDatamapClass | Vor/Nach Datenoperationen | processDatamap_preProcessFieldArray, processDatamap_postProcessFieldArray, processDatamap_afterDatabaseOperations, processDatamap_afterAllOperations |
| processCmdmapClass | Vor/Nach Befehlen | processCmdmap_preProcess, processCmdmap_postProcess, processCmdmap_deleteAction |
| clearCachePostProc | Nach Cache-Clearing | Benutzerdefinierte Methode |
Hook registrieren
Praxisbeispiel: Auf neue Records reagieren
$status:'new'oder'update'$table: Name der betroffenen Tabelle$id: UID des Records (bei'new': derNEW-Platzhalter)$fieldArray: Array der tatsächlich geschriebenen Felder$dataHandler: Die DataHandler-Instanz (Zugriff aufsubstNEWwithIDs)
Reference Index und Cache
Reference Index aktualisieren
Der Reference Index (sys_refindex) bildet alle Beziehungen zwischen Records ab. Der DataHandler aktualisiert ihn automatisch – nach Bulk-Operationen oder Migrationen sollten Sie ihn zusätzlich über die CLI prüfen:
In TYPO3 v14 steht Referenzindex prüfen und aktualisieren unter Verwaltungswerkzeuge → System → Wartung (EXT:install), nicht mehr am früheren Low-Level-Einstieg. Auf der CLI bleibt vendor/bin/typo3 referenceindex:update sinnvoll für große Instanzen.
Cache-Invalidierung
Der DataHandler invalidiert nach jeder Operation automatisch die relevanten Caches über Cache-Tags. Für jedes betroffene Record werden folgende Tags geflusht:
- Tabellenname: z.B.
pages,tt_content - Tabelle + UID: z.B.
tt_content_123 - Seiten-UID: z.B.
pageId_10
Für manuelles Cache-Clearing verwenden Sie clear_cacheCmd:
Workspace-kompatibel entwickeln
Wenn Ihr Code in einer Workspace-Umgebung läuft, erstellt der DataHandler automatisch versionierte Records. Das erfordert kein spezielles Handling – solange Sie den DataHandler nutzen.
Neu in v14: Der discard-Befehl
TYPO3 v14 führt einen neuen DataHandler-Befehl ein, der Workspace-Änderungen verwirft – sauberer und expliziter als das bisherige version/clearWSID-Konstrukt:
Der Core akzeptiert in DataHandler::discard() die UID eines Live- oder Workspace-Datensatzes; bei Live-UID wird die Workspace-Overlay-Zeile aufgelöst. Siehe DataHandler::discard().
Häufige Fallstricke
v14 Breaking Changes
TYPO3 v14 entfernt mehrere öffentliche Properties des DataHandler und ändert das Verhalten bei Datumswerten. Hier die vollständige Übersicht:
| Änderung | Forge Issue | Migration |
|---|---|---|
| userid und admin Properties entfernt | #107848 | Backend-User wird direkt aus $GLOBALS['BE_USER'] gelesen |
| storeLogMessages entfernt | #106118 | log() schreibt jetzt immer in sys_log – keine Konfiguration nötig |
| copyWhichTables, neverHideAtCopy, copyTree entfernt | #107856 | Werte werden aus BE_USER->uc gelesen (neverHideAtCopy, copyLevels) |
| Neuer discard-Befehl | #107519 | Ersetzt version/clearWSID und version/flush für Workspace-Operationen |
| ISO8601-Datumswerte verbessert | #105549 | Workarounds mit manuellen Timezone-Offsets entfernen |
| List- und Seitenmodul: Record API | #107356 / #92434 | Vorschau/Transformationen auf `Record`-Objekte umstellen statt roher Arrays |
ISO8601-Migration im Detail
Bisher behandelte TYPO3 qualifizierte ISO8601-Datumswerte mit Z fälschlicherweise als Lokalzeit. v14 korrigiert das:
Property-Migration für v14
Der TYPO3 Extension Scanner erkennt Zugriffe auf die entfernten Properties als Weak Match. Prüfen Sie Ihre Extensions vor dem v14-Upgrade.
Fazit
DataHandler ist Pflicht
Für jede TCA-Tabelle. Rohes SQL umgeht Cache, Reference Index und Workspace-Integrität.
Zwei Arrays, volle Kontrolle
DataMap ($data) für Create/Update. CmdMap ($cmd) für Copy/Move/Delete. Immer als neue Instanz.
v14-Migration planen
Entfernte Properties prüfen, ISO8601-Workarounds entfernen, discard statt clearWSID verwenden.
Der DataHandler ist kein optionales Komfort-Feature – er ist die Voraussetzung für konsistente, workspace-fähige und wartbare TYPO3-Extensions. Investieren Sie die Zeit, ihn zu verstehen, und Ihre Extensions werden es Ihnen mit Stabilität und Zukunftssicherheit danken.
TYPO3 DataHandler Skill
Agent-optimierte Referenz (Skill v2.0.0, Kompatibilität TYPO3 v13–v14): DataMap/CmdMap, Backend-Kontext, Reference Index, SC_OPTIONS-Hooks vs. dokumentierte PSR-14-Events. Im selben Ordner: SKILL.md, SKILL-PHP84.md, SKILL-CONTENT-BLOCKS.md.