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
相关产品推荐
相关产品推荐

