mcpField
T
typo3-datahandler

typo3-datahandler

github.com/dirnbauer开发3380 次安装13 周前更新
代码仓库

关于 typo3-datahandler

面向 TYPO3 v14 的开发技能,指导使用 DataHandler 而非原始 SQL 修改记录。涵盖扩展开发中的创建、更新、命令执行及后端用户上下文。

主要功能

  1. 01DataHandler 使用指南
  2. 02DataMap 与 CmdMap 模式
  3. 03创建、更新、移动和复制记录
  4. 04后端用户上下文说明

适用场景

  1. 01实现 TYPO3 v14 记录写入
  2. 02添加记录移动或删除操作
  3. 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.md
07-retrieving-new-record-uids.md
08-workspace-aware-operations.md
09-extending-datahandler-hooks-and-real-core-events.md
10-version-constraints-for-extensions.md
credits-and-attribution.md
full-guide.md
v14-only-changes.md

详细介绍

TYPO3 DataHandler 操作

来源:https://github.com/dirnbauer/webconsulting-skills

**兼容性:**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 如下:

  1. 每次使用时,通过 GeneralUtility::makeInstance(DataHandler::class) 获取 DataHandler——DataHandler 持有状态,不得通过依赖注入构造函数注入;也应避免使用 new DataHandler(),以确保 Core 装配(钩子、协作者)保持一致。
  2. 在任何 process_* 调用之前,调用 start($dataMap, $commandMap[, $backendUser[, $referenceIndexUpdater]])。第 4 个参数存在,但属于 @internal;扩展代码通常只应使用前 2 到 3 个参数。
  3. 调用 process_datamap() 和/或 process_cmdmap()
  4. 检查 $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);

详细参考

如果任务需要详细示例、较长的模板、故障排除矩阵、附录,或上述内容未涵盖的章节,请阅读完整指南。对于范围较窄的任务,请勿加载此文件,以便遵循渐进式披露。

评论

支持 Markdown