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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:50:21