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

Symfony Scheduler数据库查询位置及依赖注入问题求助

问题根源与解决方案

核心问题

Symfony Messenger 的消息类必须是可序列化的纯数据对象,不能在消息中注入服务(如EntityManagerInterface)。你当前的错误是手动实例化CheckReceiptStatus时缺少构造参数,本质是错误地把业务逻辑和依赖注入放在了消息类中。


步骤1:重构消息类

将消息改为无依赖的空对象,仅作为任务触发的标识:

// src/Scheduler/Message/CheckReceiptStatus.php
namespace App\Scheduler\Message;

class CheckReceiptStatus
{
    // 不需要构造函数和业务逻辑,仅作为任务触发标记
}

步骤2:修改处理器,将数据库逻辑移至此处

在处理器中注入EntityManagerInterface,执行查询和后续操作:

// src/Scheduler/Handler/CheckReceiptStatusHandler.php
namespace App\Scheduler\Handler;

use App\Entity\OnlineReceipt;
use App\Scheduler\Message\CheckReceiptStatus;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\HttpKernel\KernelInterface;

#[AsMessageHandler]
class CheckReceiptStatusHandler
{
    public function __construct(
        private readonly KernelInterface $kernel,
        private readonly EntityManagerInterface $entityManager
    ){}

    public function __invoke(CheckReceiptStatus $message): void
    {
        // 1. 查询需要处理的收据
        $expressionBuilder = Criteria::expr();
        $expression = $expressionBuilder->notIn('status', ['SUCCESS', 'ERROR']);
        $receipts = $this->entityManager->getRepository(OnlineReceipt::class)->matching(new Criteria($expression));

        // 2. 处理查询结果(示例:写入日志,可替换为你的数据库插入逻辑)
        $logPath = $this->kernel->getProjectDir().'/var/log/cron_test.log';
        $logContent = sprintf("[%s] 找到 %d 条待处理收据\n", date('Y-m-d H:i:s'), count($receipts));
        file_put_contents($logPath, $logContent, FILE_APPEND);

        // 3. 执行你的数据库插入操作(示例)
        // foreach ($receipts as $receipt) {
        //     // 创建新实体并保存
        //     $newEntity = new ...;
        //     $this->entityManager->persist($newEntity);
        // }
        // $this->entityManager->flush();
    }
}

步骤3:调整调度器代码

现在消息类无构造参数,直接实例化即可:

// src/Scheduler/ReceiptTaskScheduler.php
namespace App\Scheduler;

use App\Scheduler\Message\CheckReceiptStatus;
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\RecurringMessage;
use Symfony\Component\Scheduler\Schedule;
use Symfony\Component\Scheduler\ScheduleProviderInterface;

#[AsSchedule('default')]
class ReceiptTaskScheduler implements ScheduleProviderInterface
{
    public function getSchedule(): Schedule
    {
        $schedule = new Schedule();
        $schedule->add(RecurringMessage::every("20 seconds", new CheckReceiptStatus()));
        return $schedule;
    }
}

关键说明

  • 消息类仅用于标识任务,不包含任何业务逻辑或依赖
  • 所有业务逻辑(数据库查询、数据处理、持久化操作)都放在处理器中
  • 处理器通过依赖注入获取所需服务(如EntityManagerInterface),符合Symfony的服务容器规范

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:30:58