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

Symfony 6.3.4自定义Doctrine Filter的Setter注入失效问题

解决Symfony 6.3.4中Doctrine自定义Filter依赖注入失效问题

问题原因

Doctrine默认会自行实例化SQLFilter子类,不会通过Symfony的服务容器管理,因此#[Required]注解的Setter注入无法触发,导致Security服务始终为null。

解决方案

1. 将Filter注册为Symfony服务

在config/services.yaml中把AccountFilter注册为服务,注入必要依赖:

# config/services.yaml
services:
    App\Doctrine\Filter\AccountFilter:
        arguments:
            $entityManager: '@doctrine.orm.default_entity_manager'
            $security: '@Symfony\Bundle\SecurityBundle\Security'
        tags:
            - { name: doctrine.orm.sql_filter, filter_name: account_filter }

2. 修改Doctrine配置,指定使用服务实例

在config/packages/doctrine.yaml中配置Filter时,添加service参数指向我们的服务:

# config/packages/doctrine.yaml
doctrine:
    orm:
        # 其他原有配置...
        filters:
            account_filter:
                class: App\Doctrine\Filter\AccountFilter
                enabled: true
                service: App\Doctrine\Filter\AccountFilter

3. 修改Filter类,使用构造函数注入依赖

替换原来的Setter注入为构造函数注入,确保依赖被正确初始化:

<?php

namespace App\Doctrine\Filter;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingDriver;
use Doctrine\ORM\Query\Filter\SQLFilter;
use Symfony\Bundle\SecurityBundle\Security;

class AccountFilter extends SQLFilter
{
    private Security $security;

    public function __construct(
        EntityManagerInterface $entityManager,
        Security $security,
        ?MappingDriver $mappingDriver = null
    ) {
        parent::__construct($entityManager, $mappingDriver);
        $this->security = $security;
    }

    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
    {
        // 检查实体是否包含account关联
        if (!$targetEntity->hasAssociation('account')) {
            return '';
        }

        $accountColumnName = $targetEntity->getSingleAssociationJoinColumnName('account');

        $user = $this->security->getUser();
        if (!$user instanceof User) {
            return '';
        }

        // 使用参数绑定避免SQL注入风险
        $paramName = 'account_id_' . uniqid();
        $this->setParameter($paramName, $user->getAccount()->getId());
        
        return sprintf('%s.%s = :%s', $targetTableAlias, $accountColumnName, $paramName);
    }
}

额外注意点

  • 避免直接拼接SQL:原代码直接将ID拼接到SQL字符串存在SQL注入风险,改用setParameter绑定参数更安全。
  • 确保Filter启用:在Doctrine配置中设置enabled: true,也可以通过事件监听器等方式动态控制启用状态。

内容的提问来源于stack exchange,提问作者Az.Youness

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:04:57