如何从自定义Repository查询中返回Model实例而非关联数组
解决方案
你有三种可行的方式将查询结果转换为CheckResults模型实例,以下是具体实现:
方案一:使用Extbase标准Repository(推荐)
这是最符合TYPO3 Extbase规范的方式,让Repository继承Extbase的Repository类,利用内置的查询机制自动返回模型实例。
修改CheckResultsRepository代码:
<?php namespace Homeinfo\SysMon2\Domain\Repository; use Homeinfo\SysMon2\Domain\Model\CheckResults; use TYPO3\CMS\Extbase\Persistence\Repository; final class CheckResultsRepository extends Repository { public function findBySystem(int $system): array { $query = $this->createQuery(); $query->matching( $query->equals('system', $system) ); // execute()返回QueryResultInterface,toArray()得到模型实例数组 return $query->execute()->toArray(); } }
注意事项
需要确保Extbase知道模型与数据库表的映射关系,在扩展的Configuration/Extbase/Persistence/Classes.php中添加配置:
<?php declare(strict_types=1); return [ \Homeinfo\SysMon2\Domain\Model\CheckResults::class => [ 'tableName' => 'checkresults', ], ];
方案二:使用DataMapper自动映射
如果不想让Repository继承Extbase的Repository类,可以注入Extbase的DataMapper来完成数组到模型的自动转换。
修改CheckResultsRepository代码:
<?php namespace Homeinfo\SysMon2\Domain\Repository; use Homeinfo\SysMon2\Domain\Model\CheckResults; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; final class CheckResultsRepository { public function __construct( private readonly ConnectionPool $connectionPool, private readonly DataMapper $dataMapper ) { } public function findBySystem(int $system): array { $queryBuilder = $this->connectionPool->getQueryBuilderForTable('checkresults'); $result = $queryBuilder ->select('*') ->from('checkresults') ->where( $queryBuilder->expr()->eq( 'system', $queryBuilder->createNamedParameter($system, Connection::PARAM_INT) ) ) ->executeQuery(); // 获取关联数组,通过DataMapper映射为模型实例 $rows = $result->fetchAllAssociative(); return $this->dataMapper->map(CheckResults::class, $rows); } }
方案三:手动映射数组到模型
适合需要自定义映射逻辑的场景,手动将数据库返回的数组字段赋值给模型实例。
修改CheckResultsRepository代码:
<?php namespace Homeinfo\SysMon2\Domain\Repository; use Homeinfo\SysMon2\Domain\Model\CheckResults; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; final class CheckResultsRepository { public function __construct( private readonly ConnectionPool $connectionPool ) { } public function findBySystem(int $system): array { $queryBuilder = $this->connectionPool->getQueryBuilderForTable('checkresults'); $result = $queryBuilder ->select('*') ->from('checkresults') ->where( $queryBuilder->expr()->eq( 'system', $queryBuilder->createNamedParameter($system, Connection::PARAM_INT) ) ) ->executeQuery(); $checkResultsList = []; // 遍历数据库结果,逐个实例化模型 foreach ($result->fetchAllAssociative() as $row) { $model = new CheckResults(); // 赋值普通类型字段 $model->id = (int)$row['id']; $model->system = (int)$row['system']; $model->icmp_request = (bool)$row['icmp_request']; $model->ssh_login = $row['ssh_login']; $model->http_request = $row['http_request']; $model->application_state = $row['application_state']; $model->smart_check = $row['smart_check']; $model->baytrail_freeze = $row['baytrail_freeze']; $model->fsck_repair = $row['fsck_repair']; $model->application_version = (bool)$row['application_version']; $model->ram_total = (int)$row['ram_total']; $model->ram_free = (int)$row['ram_free']; $model->ram_available = (int)$row['ram_available']; $model->efi_mount_ok = $row['efi_mount_ok']; $model->download = (int)$row['download']; $model->upload = (int)$row['upload']; $model->root_not_ro = $row['root_not_ro']; $model->sensors = $row['sensors']; $model->in_sync = (bool)$row['in_sync']; $model->recent_touch_events = (int)$row['recent_touch_events']; // 处理DateTime类型字段,需转换为DateTime对象 if (!empty($row['timestamp'])) { $model->timestamp = new \DateTime($row['timestamp']); } if (!empty($row['offline_since'])) { $model->offline_since = new \DateTime($row['offline_since']); } if (!empty($row['blackscreen_since'])) { $model->blackscreen_since = new \DateTime($row['blackscreen_since']); } $checkResultsList[] = $model; } return $checkResultsList; } }
方案对比
- 方案一:代码简洁,自动处理类型转换、分页、排序等,维护成本最低,优先推荐。
- 方案二:无需继承Repository,利用Extbase内置工具完成映射,减少手动代码。
- 方案三:灵活性最高,但代码冗余,字段较多时容易出错,仅适合特殊场景。
内容的提问来源于stack exchange,提问作者user3515670
相关产品推荐
相关产品推荐

