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

Symfony 5.x独立使用Routing组件:如何为控制器注入参数?

解决Symfony 5.x组件中控制器依赖注入问题

一、构造函数注入实现(推荐,配置简单)

因为你已经接受构造函数注入的方式,这种方式无需额外扩展参数解析器,仅需通过DI容器配置服务即可实现嵌套依赖的自动实例化。

1. 配置DI容器服务

创建config/services.yaml文件,注册所有需要的服务(包括嵌套依赖):

services:
  # 注册AgentRepository的嵌套依赖,以PDO为例
  database_connection:
    class: PDO
    arguments:
      - 'mysql:host=localhost;dbname=your_database'
      - 'your_username'
      - 'your_password'

  # 注册AgentRepository,自动注入PDO依赖
  App\Repository\AgentRepository:
    autowire: true
    arguments:
      $pdo: '@database_connection'

  # 注册ShopController,自动注入AgentRepository依赖
  App\Controller\ShopController:
    autowire: true

2. 初始化DI容器并关联HttpKernel

在启动文件中加载容器配置,并用容器版控制器解析器替换默认实现:

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use App\Controller\ShopController;

// 1. 初始化DI容器
$containerBuilder = new ContainerBuilder();
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__.'/config'));
$loader->load('services.yaml');
$containerBuilder->compile();

// 2. 定义路由
$routes = new RouteCollection();
$routes->add(
    'shop_info',
    new Route('/api/v1/shop/info', [
        '_controller' => [ShopController::class, 'index'],
    ])
);

// 3. 创建路由匹配器
$context = new RequestContext();
$context->fromRequest(Request::createFromGlobals());
$matcher = new UrlMatcher($routes, $context);

// 4. 使用容器版控制器解析器(自动从容器获取控制器实例)
$controllerResolver = new ContainerControllerResolver($containerBuilder);
$argumentResolver = new ArgumentResolver();

// 5. 构建HttpKernel并处理请求
$kernel = new HttpKernel($matcher, $controllerResolver, null, $argumentResolver);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();

此时你的构造函数注入版本的ShopController就能正常工作,容器会自动实例化AgentRepository及其所有嵌套依赖。


二、方法参数注入实现(自定义ArgumentResolver)

如果偏好方法参数注入,需要实现自定义参数解析器,让它从DI容器中获取类型提示的依赖。

1. 创建自定义参数解析器

实现ArgumentValueResolverInterface,用于识别并注入容器中的服务:

namespace App\Resolver;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;

class ContainerArgumentResolver implements ArgumentValueResolverInterface
{
    private ContainerInterface $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function supports(Request $request, ArgumentMetadata $argument): bool
    {
        // 判断参数类型是否在DI容器中已注册为服务
        return $argument->getType() && $this->container->has($argument->getType());
    }

    public function resolve(Request $request, ArgumentMetadata $argument): iterable
    {
        // 从容器获取对应服务实例并返回
        yield $this->container->get($argument->getType());
    }
}

2. 在DI容器中注册自定义解析器

修改config/services.yaml,添加自定义解析器的服务配置:

services:
  # ... 保留之前的服务配置 ...

  App\Resolver\ContainerArgumentResolver:
    arguments:
      $container: '@service_container'

3. 将自定义解析器加入参数解析链

在启动文件中,把自定义解析器添加到ArgumentResolver的解析器列表中:

// ... 保留之前的容器初始化、路由定义代码 ...

// 获取自定义解析器实例
$containerResolver = $containerBuilder->get(App\Resolver\ContainerArgumentResolver::class);

// 构建包含自定义解析器的参数解析器链
$argumentResolver = new ArgumentResolver([
    new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver(),
    new \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver(),
    $containerResolver, // 加入自定义解析器
]);

// 构建HttpKernel并处理请求
$kernel = new HttpKernel($matcher, $controllerResolver, null, $argumentResolver);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();

此时你的方法参数注入版本的ShopController就能正常工作,自定义解析器会自动将AgentRepository注入到index方法的参数中。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 05:22:39