You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TYPO3 Extbase:n:1关系下ParentUser对象的子对象Hydration实现

解决方案:Extbase中为ParentUser自动关联Child对象(无仓库依赖)

针对你在TYPO3 12.4.18 + Extbase环境下的需求——在ParentUser对象水合时自动加载关联的Child集合到ObjectStorage,且模型不依赖仓库,可通过自定义PropertyMapper类型转换器实现,具体步骤如下:

1. 修改ParentUser模型

在ParentUser类中添加$children属性及对应的访问方法,全程不引入仓库依赖:

<?php
namespace Vendor\Xxx\Domain\Model;

use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;

class ParentUser extends AbstractDomainObject
{
    // 原有属性(first_name/last_name等)保持不变
    protected ?ObjectStorage $children = null;

    public function __construct()
    {
        $this->children = new ObjectStorage();
    }

    public function getChildren(): ObjectStorage
    {
        return $this->children;
    }

    public function setChildren(ObjectStorage $children): void
    {
        $this->children = $children;
    }

    // 可选:添加单个子对象的增删方法
    public function addChild(Child $child): void
    {
        $this->children->attach($child);
    }

    public function removeChild(Child $child): void
    {
        $this->children->detach($child);
    }
}

2. 自定义TypeConverter

创建类型转换器,负责在ParentUser水合时查询并转换关联的Child集合:

<?php
namespace Vendor\Xxx\Property\TypeConverter;

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use Vendor\Xxx\Domain\Model\ParentUser;
use Vendor\Xxx\Domain\Model\Child;
use TYPO3\CMS\Extbase\Property\PropertyMapper;

class ParentUserChildrenTypeConverter extends AbstractTypeConverter
{
    protected $sourceTypes = [ParentUser::class];
    protected $targetType = ObjectStorage::class;
    protected $priority = 10; // 设置优先级确保被优先调用

    public function __construct(
        protected readonly ConnectionPool $connectionPool,
        protected readonly PropertyMapper $propertyMapper
    ) {}

    public function convertFrom(
        $source,
        string $targetType,
        array $convertedChildProperties = [],
        PropertyMappingConfigurationInterface $configuration = null
    ): ObjectStorage {
        $objectStorage = new ObjectStorage();
        if (!$source instanceof ParentUser || !$source->getUid()) {
            return $objectStorage;
        }

        // 查询关联的Child记录(过滤已删除/隐藏的条目)
        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('tx_xxx_domain_model_child');
        $childRows = $queryBuilder
            ->select('*')
            ->from('tx_xxx_domain_model_child')
            ->where(
                $queryBuilder->expr()->eq('parent_user', $queryBuilder->createNamedParameter($source->getUid(), \PDO::PARAM_INT)),
                $queryBuilder->expr()->eq('deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)),
                $queryBuilder->expr()->eq('hidden', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
            )
            ->executeQuery()
            ->fetchAllAssociative();

        // 用PropertyMapper把数据库行转换为Child对象
        foreach ($childRows as $row) {
            $child = $this->propertyMapper->convert($row, Child::class);
            if ($child instanceof Child) {
                $objectStorage->attach($child);
            }
        }

        return $objectStorage;
    }
}

3. 注册TypeConverter

在扩展的Configuration/Services.yaml中注册该转换器:

services:
  Vendor\Xxx\Property\TypeConverter\ParentUserChildrenTypeConverter:
    arguments:
      - '@TYPO3\CMS\Core\Database\ConnectionPool'
      - '@TYPO3\CMS\Extbase\Property\PropertyMapper'
    tags:
      - name: extbase.property.type_converter

4. 配置PropertyMapper映射规则

在ParentUser的仓库中,为查询结果配置属性映射规则,让children字段使用自定义转换器:

<?php
namespace Vendor\Xxx\Domain\Repository;

use TYPO3\CMS\Extbase\Persistence\Repository;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
use Vendor\Xxx\Property\TypeConverter\ParentUserChildrenTypeConverter;

class ParentUserRepository extends Repository
{
    public function findAllWithChildren(): \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
    {
        $query = $this->createQuery();
        $querySettings = $query->getQuerySettings();

        // 配置children属性的转换规则
        $propertyMappingConfig = $this->objectManager->get(PropertyMappingConfigurationInterface::class);
        $propertyMappingConfig->forProperty('children')
            ->setTypeConverter($this->objectManager->get(ParentUserChildrenTypeConverter::class));
        
        $querySettings->setPropertyMappingConfiguration($propertyMappingConfig);
        $query->setQuerySettings($querySettings);

        return $query->execute();
    }
}

关键注意事项

  • 避免N+1查询:如果批量加载ParentUser,建议优化转换器逻辑——先获取所有ParentUser的UID,再用IN查询批量获取Child,最后手动关联,减少数据库请求次数。
  • 模型无依赖:ParentUser模型完全不依赖仓库,数据加载逻辑封装在转换器中,符合需求。
  • 状态过滤:转换器中已处理deleted和hidden字段,可根据业务需求调整过滤条件。

内容的提问来源于stack exchange,提问作者Doku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:23:22