关于 typo3-datahandler
面向 TYPO3 v14 的开发技能,指导使用 DataHandler 而非原始 SQL 修改记录。涵盖扩展开发中的创建、更新、命令执行及后端用户上下文。
主要功能
- 01DataHandler 使用指南
- 02DataMap 与 CmdMap 模式
- 03创建、更新、移动和复制记录
- 04后端用户上下文说明
适用场景
- 01实现 TYPO3 v14 记录写入
- 02添加记录移动或删除操作
- 03在 CLI 或 scheduler 任务中运行 DataHandler
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dirnbauer/ webconsulting-skills --skill typo3-datahandler安装后在 Claude Code 中输入/typo3-datahandler确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/06-common-pitfalls.md07-retrieving-new-record-uids.md08-workspace-aware-operations.md09-extending-datahandler-hooks-and-real-core-events.md10-version-constraints-for-extensions.mdcredits-and-attribution.mdfull-guide.mdv14-only-changes.md详细介绍
TYPO3 DataHandler 操作
**兼容性:**TYPO3 v14.x 此技能中的所有代码示例均适用于 TYPO3 v14。
**优先使用 TYPO3 API:**在创建自定义实现之前,始终优先使用 TYPO3 内置的 API、核心功能和既定约定。不要重复实现 TYPO3 已提供的功能。请务必查阅 TYPO3 官方文档,确认所使用的 API 和方法在 TYPO3 v14 中存在且未弃用。
1. 首要原则
绝不要对 pages、tt_content 或任何由 TCA 配置的表使用原始 SQL(INSERT、UPDATE、DELETE)。
必须使用 DataHandler,以确保:
- 更新引用索引(
sys_refindex) - 清除缓存
- 版本历史(
sys_history) - 与工作区兼容
- 正确集成 Core 定义的钩子/事件(参见 §9)
- 处理 FlexForm
- 管理 MM 关系
例外情况(允许使用原始 SQL)
- 没有 TCA 的自定义日志表
- 批量分析/报告查询(只读)
- 明确重建引用索引的迁移脚本
2. 数组结构
DataMap($data)
用于创建或更新记录。
语法:$data[tableName][uid][fieldName] = value
创建新记录:
使用以 NEW 开头的唯一字符串作为 UID:
<?php
declare(strict_types=1);
$data = [
'tt_content' => [
'NEW_1' => [
'pid' => 1,
'CType' => 'text',
'header' => 'My New Content Element',
'bodytext' => '<p>Content goes here</p>',
'sys_language_uid' => 0,
],
],
];
更新现有记录:
使用数字 UID:
<?php
declare(strict_types=1);
$data = [
'tt_content' => [
123 => [
'header' => 'Updated Header',
'hidden' => 0,
],
],
];
引用 NEW 记录:
<?php
declare(strict_types=1);
$data = [
'pages' => [
'NEW_page' => [
'pid' => 1,
'title' => 'New Page',
],
],
'tt_content' => [
'NEW_content' => [
'pid' => 'NEW_page', // References the new page
'CType' => 'text',
'header' => 'Content on new page',
],
],
];
CmdMap($cmd)
用于移动、复制、删除或恢复删除记录。
语法:$cmd[tableName][uid][command] = value
删除记录:
<?php
declare(strict_types=1);
$cmd = [
'tt_content' => [
123 => ['delete' => 1],
],
];
移动记录:
<?php
declare(strict_types=1);
$cmd = [
'tt_content' => [
123 => ['move' => 456], // Target page UID; use negative UID to place after record
],
];
复制记录:
<?php
declare(strict_types=1);
$cmd = [
'tt_content' => [
123 => ['copy' => 1], // Target page UID
],
];
本地化记录:
<?php
declare(strict_types=1);
$cmd = [
'tt_content' => [
123 => [
'localize' => 1, // Target language UID
],
],
];
3. 执行模式
TYPO3 v14 的公开 DataHandler API 如下:
- 每次使用时,通过
GeneralUtility::makeInstance(DataHandler::class)获取DataHandler——DataHandler 持有状态,不得通过依赖注入构造函数注入;也应避免使用new DataHandler(),以确保 Core 装配(钩子、协作者)保持一致。 - 在任何
process_*调用之前,调用start($dataMap, $commandMap[, $backendUser[, $referenceIndexUpdater]])。第 4 个参数存在,但属于@internal;扩展代码通常只应使用前 2 到 3 个参数。 - 调用
process_datamap()和/或process_cmdmap() - 检查
$dataHandler->errorLog,验证$dataHandler->substNEWwithIDs中是否包含预期键;如果是在工作区中操作,且预期会有版本行,则检查$dataHandler->autoVersionIdMap。
**缓存:**优先使用 CacheManager/缓存组或 PSR-14 缓存事件,而不是旧版 DataHandler 缓存辅助方法。
官方文档未定义 DataHandler 的通用事务约定。在常规扩展代码中,应首先使用普通 API;只有在仔细验证特定用例涉及的数据库连接和副作用后,才添加自己的事务处理。
<?php
declare(strict_types=1);
namespace Vendor\Extension\Service;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
final class ContentService
{
public function createOrUpdateContent(array $data, array $cmd = []): array
{
/** @var DataHandler $dataHandler */
$dataHandler = GeneralUtility::makeInstance(DataHandler::class);
$dataHandler->start($data, $cmd);
if ($data !== []) {
$dataHandler->process_datamap();
}
if ($cmd !== []) {
$dataHandler->process_cmdmap();
}
if ($dataHandler->errorLog !== []) {
throw new \RuntimeException(
'DataHandler error: ' . implode(', ', $dataHandler->errorLog),
1700000001
);
}
return $dataHandler->substNEWwithIDs;
}
}
4. 后端上下文
DataHandler 需要有效的后端用户上下文。它不要求你通过修改 $GLOBALS['BE_USER']->user 来手动伪造管理员模式。
- 在命令行/调度器上下文中,使用 DataHandler 前须初始化后端身份验证
- TYPO3 命令使用
_cli_后端用户 - 如果需要使用其他后端用户,请将正确的
BackendUserAuthentication对象作为start()的第三个参数传入 - 应使用权限检查和真实的后端用户对象,而不是手动设置
$GLOBALS['BE_USER']->user['admin'] = 1
CLI 命令设置(TYPO3 v14)
<?php
declare(strict_types=1);
namespace Vendor\Extension\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
#[AsCommand(
name: 'myext:import',
description: 'Import data using DataHandler',
)]
final class ImportCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
Bootstrap::initializeBackendAuthentication();
// Your DataHandler logic here...
return Command::SUCCESS;
}
}
使用其他后端用户
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
final class ImportService
{
public function runAsUser(
array $data,
array $cmd,
BackendUserAuthentication $backendUser
): void {
/** @var DataHandler $dataHandler */
$dataHandler = GeneralUtility::makeInstance(DataHandler::class);
$dataHandler->start($data, $cmd, $backendUser);
$dataHandler->process_datamap();
$dataHandler->process_cmdmap();
if ($dataHandler->errorLog !== []) {
throw new \RuntimeException(
'DataHandler error: ' . implode(', ', $dataHandler->errorLog),
1700000001
);
}
}
}
5. 引用索引处理
对于常规 DataHandler 写入,TYPO3 会自动使引用索引保持同步。通常,普通使用 process_datamap() / process_cmdmap() 后无需手动调用 ReferenceIndex。
手动更新引用索引主要适用于:
- 部署和 TYPO3 升级
- TCA 定义的关系发生更改
- 绕过 DataHandler 的迁移或脚本
- 修复 / 维护场景
重建完整引用索引
vendor/bin/typo3 referenceindex:update
手动更新特定记录(不建议)
在 v14 中,ReferenceIndex 和 updateRefIndexTable() 均为 @internal——扩展不应自行操作引用索引。建议使用 vendor/bin/typo3 referenceindex:update,或让 DataHandler 维护索引。如果你仍然调用此内部 API,请做好它可能在不弃用的情况下发生变更的准备:
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Database\ReferenceIndex;
use TYPO3\CMS\Core\Utility\GeneralUtility;
// @internal API — discouraged; prefer referenceindex:update or DataHandler
$referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
$referenceIndex->updateRefIndexTable('tt_content', 123);
详细参考
如果任务需要详细示例、较长的模板、故障排除矩阵、附录,或上述内容未涵盖的章节,请阅读完整指南。对于范围较窄的任务,请勿加载此文件,以便遵循渐进式披露。