TYPO3 12.4对象增改删时PSR-14事件监听及实现问题
我有包含product和version的数据模型,每个product关联多个version,version包含size字段。需要在页面展示每个product的maximum_size(即关联所有version的size最大值)。计划在TYPO3 12.4中高效实现以下逻辑:
- 在
product模型中添加maximum_size属性,基于关联的version计算并保存该值 - 监听
version对象的保存、更新或删除事件 - 找到关联的
product,重新计算并保存maximum_size值
现在想确认:是否有适配该场景的TYPO3 PSR-14事件?我选中了三个候选事件:\TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent、\TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent、\TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent
尝试使用第一个事件EntityPersistedEvent但未生效:已按文档步骤创建事件监听器类、注册事件、配置日志输出到指定文件,但日志文件未生成,也没有任何日志记录。请问是事件监听器实现有误,还是EntityPersistedEvent并非合适的选择?
监听器类
# Classes/EventListener/ProductMaximumSizeUpdater.php <?php declare(strict_types=1); namespace MyVendor\MyExtension\EventListener; use \TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent; use \Psr\Log\LoggerInterface; final class ProductMaximumSizeUpdater { public function __construct( private readonly LoggerInterface $logger, ) {} public function __invoke(EntityPersistedEvent $event): void { $entity = $event->getObject(); $this->logger->info('test message'); } }
事件注册配置
# Configuration/Services.yaml services: _defaults: autowire: true autoconfigure: true public: false MyVendor\MyExtension\EventListener\ProductMaximumSizeUpdater: tags: - name: event.listener identifier: 'productMaximumSizeUpdater'
日志配置
$GLOBALS['TYPO3_CONF_VARS']['LOG']['MyVendor']['MyExtension']['EventListener']['writerConfiguration'] = [ \TYPO3\CMS\Core\Log\LogLevel::INFO => [ \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [ 'logFile' => \TYPO3\CMS\Core\Core\Environment::getVarPath() . '/log/MyEventListener.log' ] ] ];
1. 事件选择是否正确
EntityPersistedEvent仅在新实体首次保存时触发,无法覆盖你需要的version更新、删除场景,所以这个事件并不适配全部需求:
- 新增
version:EntityPersistedEvent会触发 - 更新
version:需要监听EntityUpdatedInPersistenceEvent - 删除
version:需要监听EntityRemovedFromPersistenceEvent
你需要同时注册这三个事件的监听器,或者在一个监听器类中处理多个事件。
2. 监听器未生效的可能原因
(1)事件标签未显式指定类型
默认情况下TYPO3会自动推断监听事件,但如果自动推断失效,需显式指定event属性。修改Services.yaml:
# Configuration/Services.yaml services: _defaults: autowire: true autoconfigure: true public: false MyVendor\MyExtension\EventListener\ProductMaximumSizeUpdater: tags: - name: event.listener identifier: 'productMaximumSizeUpdater.persisted' event: TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent - name: event.listener identifier: 'productMaximumSizeUpdater.updated' event: TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent - name: event.listener identifier: 'productMaximumSizeUpdater.removed' event: TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent
(2)日志配置问题
- 检查
Environment::getVarPath()返回的路径是否正确,可临时替换为绝对路径测试 - 确保日志文件所在目录有Web服务器用户的写入权限
(3)缺少实体类型判断
当前监听器会监听所有实体的事件,建议先添加类型判断避免无效触发,同时补充核心逻辑:
<?php declare(strict_types=1); namespace MyVendor\MyExtension\EventListener; use TYPO3\CMS\Extbase\Event\Persistence\EntityPersistedEvent; use TYPO3\CMS\Extbase\Event\Persistence\EntityUpdatedInPersistenceEvent; use TYPO3\CMS\Extbase\Event\Persistence\EntityRemovedFromPersistenceEvent; use Psr\Log\LoggerInterface; use MyVendor\MyExtension\Domain\Model\Version; use MyVendor\MyExtension\Domain\Model\Product; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; final class ProductMaximumSizeUpdater { public function __construct( private readonly LoggerInterface $logger, private readonly PersistenceManager $persistenceManager ) {} public function __invoke(EntityPersistedEvent|EntityUpdatedInPersistenceEvent|EntityRemovedFromPersistenceEvent $event): void { $entity = $event->getObject(); // 仅处理Version实体 if (!$entity instanceof Version) { return; } $this->logger->info('Version event triggered', ['uid' => $entity->getUid()]); $product = $entity->getProduct(); if (!$product instanceof Product) { return; } // 计算关联Version的最大size $maxSize = 0; foreach ($product->getVersions() as $version) { $size = $version->getSize(); if ($size > $maxSize) { $maxSize = $size; } } // 更新并保存Product的maximum_size $product->setMaximumSize($maxSize); $this->persistenceManager->update($product); } }
3. 性能优化建议
遍历所有Version计算最大值效率较低,可改用Extbase查询构建器直接查询最大值:
// 注入VersionRepository public function __construct( private readonly LoggerInterface $logger, private readonly PersistenceManager $persistenceManager, private readonly \MyVendor\MyExtension\Domain\Repository\VersionRepository $versionRepository ) {} // 替换最大值计算逻辑 $query = $this->versionRepository->createQuery(); $query->matching($query->equals('product', $product)); $query->setOrderings(['size' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING]); $query->setLimit(1); $latestVersion = $query->execute()->getFirst(); $maxSize = $latestVersion ? $latestVersion->getSize() : 0;
内容的提问来源于stack exchange,提问作者oracl

