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

如何在类中获取Symfony仓库?Respect/Validation验证规则问题

我来帮你解决这两个Symfony和Respect/Validation的常见问题:

1. 如何在类中获取Symfony的Repository?

在Symfony里,最规范也最推荐的方式是依赖注入,别直接从容器里硬拿,这样代码耦合度低,还方便写测试。分几种常见情况给你说明:

  • 控制器中获取:
    优先用构造函数注入Repository,Symfony会自动帮你完成实例化;也可以用框架自带的getDoctrine方法快速获取。比如构造注入的写法:

    use App\Repository\CountryRepository;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    
    class CountryController extends AbstractController
    {
        private $countryRepo;
    
        public function __construct(CountryRepository $countryRepo)
        {
            $this->countryRepo = $countryRepo;
        }
    
        public function list()
        {
            $countries = $this->countryRepo->findAll();
            // 后续业务逻辑
        }
    }
    
  • 自定义服务类(比如你的验证规则类):
    只要你的类在src/目录下,Symfony默认会把它注册为服务,直接在构造函数里添加Repository参数即可,框架会自动注入:

    use App\Repository\CountryRepository;
    
    class YourCustomService
    {
        private $countryRepo;
    
        public function __construct(CountryRepository $countryRepo)
        {
            $this->countryRepo = $countryRepo;
        }
    
        // 业务逻辑中直接使用 $this->countryRepo
    }
    
  • 特殊场景下从容器获取(不推荐):
    若遇到老代码或特殊需求必须从容器获取,可实现ContainerAwareInterface,但这种写法会让类与容器耦合,能不用就不用:

    use Symfony\Component\DependencyInjection\ContainerAwareInterface;
    use Symfony\Component\DependencyInjection\ContainerAwareTrait;
    
    class LegacyClass implements ContainerAwareInterface
    {
        use ContainerAwareTrait;
    
        public function someOldMethod()
        {
            $countryRepo = $this->container->get(CountryRepository::class);
        }
    }
    
2. 实现Respect/Validation的CountryNameUnique规则(检查数据库名称唯一)

你的CountryNameUnique需要访问数据库,核心是把Repository注入到这个规则类里——因为AbstractRule本身不支持依赖注入,咱们得修改构造函数来接收Repository,再编写验证逻辑:

首先改造CountryNameUnique类:

use App\Repository\CountryRepository;
use Respect\Validation\Rules\AbstractRule;

class CountryNameUnique extends AbstractRule
{
    private $countryRepository;

    // 通过构造函数注入Repository
    public function __construct(CountryRepository $countryRepository)
    {
        $this->countryRepository = $countryRepository;
    }

    public function validate($input)
    {
        // 假设你的Country实体有name字段,Repository包含findOneByName方法
        $existingCountry = $this->countryRepository->findOneByName($input);
        
        // 验证逻辑:数据库无同名则返回true(通过),有则返回false(失败)
        return !$existingCountry;
    }
}

接着调整CountryName规则类,因为现在CountryNameUnique需要构造参数,咱们要改它的构造函数,直接注入实例化好的CountryNameUnique:

use Respect\Validation\Rules\AllOf;
use Respect\Validation\Rules\Alpha;
use Respect\Validation\Rules\Length;
use Respect\Validation\Rules\NotEmpty;
use Respect\Validation\Rules\StringType;

class CountryName extends AllOf
{
    public function __construct(CountryNameUnique $countryNameUnique)
    {
        parent::__construct(
            new StringType(),
            new NotEmpty(),
            new Alpha(),
            new Length(1, 100),
            $countryNameUnique // 使用注入好的实例
        );
    }
}

在Symfony中,只要你的类在src/目录下,自动装配(autowire)会自动完成依赖注入:把CountryRepository注入到CountryNameUnique,再把CountryNameUnique注入到CountryName,无需额外配置。

比如在控制器中使用这个验证规则:

use App\Validation\CountryName;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;

class CountryController extends AbstractController
{
    public function create(Request $request, CountryName $countryNameValidator)
    {
        $countryName = $request->request->get('name');
        
        if (!$countryNameValidator->validate($countryName)) {
            // 验证失败,获取错误信息
            $errors = $countryNameValidator->assert($countryName);
            // 处理错误,比如返回表单提示
        }

        // 验证通过,继续创建国家的逻辑
    }
}

如果需要支持编辑场景(允许当前国家名称不变,仅检查其他国家的名称唯一性),可以给CountryNameUnique添加排除ID的参数:

class CountryNameUnique extends AbstractRule
{
    private $countryRepository;
    private $excludeId;

    // 新增excludeId参数,默认null表示不排除
    public function __construct(CountryRepository $countryRepository, int $excludeId = null)
    {
        $this->countryRepository = $countryRepository;
        $this->excludeId = $excludeId;
    }

    public function validate($input)
    {
        $queryBuilder = $this->countryRepository->createQueryBuilder('c')
            ->where('c.name = :name')
            ->setParameter('name', $input);

        // 若有排除ID,添加条件排除当前国家
        if ($this->excludeId !== null) {
            $queryBuilder->andWhere('c.id != :id')
                ->setParameter('id', $this->excludeId);
        }

        $existingCountry = $queryBuilder->getQuery()->getOneOrNullResult();
        
        return !$existingCountry;
    }
}

编辑时可以这样实例化规则:

// 编辑ID为5的国家,排除该ID不检查
$countryNameUnique = new CountryNameUnique($countryRepo, 5);
$countryNameValidator = new CountryName($countryNameUnique);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:33:08