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

Symfony自定义约束验证器依赖注入传参不足报错解决方案

问题产生原因

报错里提到的ContainerConstraintValidatorFactory.php第52行的逻辑是:工厂类优先以验证器全类名为ID从依赖注入容器拉取已装配好依赖的服务,如果拉取失败,就直接通过反射无参实例化验证器类。你遇到的0参数传入构造函数的问题,就是工厂走了无参实例化的分支,没有传入TranslatorInterface依赖,具体触发原因有三点:

  • 代码本身存在基础bug:构造函数只声明了接收TranslatorInterface参数,没有给$this->translator属性赋值,就算依赖正常传入,后续调用翻译方法时也会报未定义属性错误。
  • 验证器没有被容器识别为合法的约束验证器服务:绝大多数场景是因为服务自动配置丢了约束验证器的标签,或者验证器所在的命名空间被services.yaml的自动发现规则排除,导致容器里没有对应服务,工厂只能退回到无参实例化的逻辑。
  • 额外逻辑bug:你在调用翻译方法传占位符参数时用了索引数组['{{ string }}', $value],就算依赖注入正常,消息里的{string}占位符也无法被正确替换。
修复方案

按以下步骤调整即可解决:

  1. 修正验证器基础代码逻辑
    用PHP 8构造函数属性提升特性完成依赖赋值,同时修正翻译参数的数组格式,调整后的验证器核心代码如下:
    <?php
    namespace App\Infrastructure\Domain\Model\Company;
    
    use Symfony\Component\Validator\Constraint;
    use Symfony\Component\Validator\ConstraintValidator;
    use Symfony\Component\Validator\Exception\UnexpectedTypeException;
    use Symfony\Component\Validator\Exception\UnexpectedValueException;
    use Symfony\Contracts\Translation\TranslatorInterface;
    use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
    
    // 加标签让容器识别这是约束验证器
    #[AutoconfigureTag('validator.constraint_validator')]
    class ContainsUnsupportedSymbolsValidator extends ConstraintValidator
    {
        // 构造函数直接声明属性完成赋值
        public function __construct(
            private readonly TranslatorInterface $translator
        ) {}
    
        public function validate($value, Constraint $constraint)
        {
            if (!$constraint instanceof ContainsUnsupportedSymbols) {
                throw new UnexpectedTypeException($constraint, ContainsUnsupportedSymbols::class);
            }
    
            if (null === $value || '' === $value) {
                return;
            }
    
            if (!is_string($value)) {
                throw new UnexpectedValueException($value, 'string');
            }
    
            if (!preg_match('/^\+?[0-9]{3}-?[0-9]{6,12}$/', $value)) {
                $this->context->buildViolation(
                    // 修正参数为关联数组
                    $this->translator->trans($constraint->message, ['{{ string }}' => $value])
                )->addViolation();
            }
        }
    }
    
  2. 校验服务自动配置(可选,加了上面的标签可以跳过这步)
    如果你不想在类上加注解,可以检查config/services.yaml里的全局实例配置,确保所有约束验证器子类都被自动打标签,Symfony默认骨架自带这段配置,很多人调整服务配置时会误删:
    services:
        _defaults:
            autowire: true
            autoconfigure: true
        # 其他服务配置...
        _instanceof:
            Symfony\Component\Validator\ConstraintValidator:
                tags: ['validator.constraint_validator']
    
  3. 可选优化:移除手动翻译逻辑
    Symfony校验组件本身已经内置了消息翻译能力,不需要手动注入TranslatorInterface:违规消息会自动走validators翻译域,你只需要把约束里的$message作为翻译键,在translations/validators.zh_CN.yaml等对应语言文件中配置翻译内容即可,组件会自动完成翻译和占位符替换,可以从根源避免这类依赖注入问题。

注意:不要随意在ContainsUnsupportedSymbols约束类中覆写validatedBy()方法,默认方法返回的就是约束类名加Validator后缀,和你的验证器类名完全匹配,手动修改返回值反而会导致工厂找不到对应验证器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:51:17