Symfony清洁架构项目中FormInterface自动注入失败问题求助
问题解决:Symfony清洁架构项目中SearchHtmlView的Autowire错误
问题背景
在基于清洁架构的Symfony项目中,实现首页搜索栏对接API时,页面抛出Autowire错误:
Cannot autowire service "Infrastructure\Symfony\view\SearchHtmlView": argument "$form" of method "__construct()" references interface "Symfony\Component\Form\FormInterface" but no such service exists. Did you create a class that implements this interface?
错误原因
Symfony的依赖注入容器无法自动注入FormInterface,核心原因是:
- 表单实例不是服务:
FormInterface的实现是在控制器中通过createForm()动态创建的临时对象,并非由DI容器管理的服务,因此无法在类的构造函数中依赖注入。 SearchHtmlView的逻辑矛盾:构造函数注入了FormInterface,但generateView方法又接收了一个表单参数,内部却使用构造注入的实例,导致逻辑混乱。
修复步骤
1. 重构SearchHtmlView类
移除构造函数中的FormInterface依赖,仅保留Twig环境,在generateView方法中直接使用传入的表单实例:
namespace Infrastructure\Symfony\view; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Response; use Twig\Environment; use Twig\Error\LoaderError; use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; class SearchHtmlView { private Environment $twig; // 仅注入Twig环境,移除FormInterface依赖 public function __construct(Environment $twig) { $this->twig = $twig; } /** * @throws RuntimeError * @throws SyntaxError * @throws LoaderError */ public function generateView(FormInterface $form): Response { return new Response($this->twig->render( 'main/main.html.twig', [ // 使用传入的表单创建视图对象 "form" => $form->createView() ] )); } }
2. 优化控制器逻辑(可选)
原控制器中addFlash的位置会导致无论表单是否提交都会显示提示,建议调整为仅在表单提交无效时显示:
namespace Infrastructure\Symfony\controller; use Domain\Form\SearchFormType; use Domain\Presenter\SearchCarPresenterInterface; use Domain\UseCase\SearchCarUseCase; use Infrastructure\Symfony\view\SearchHtmlView; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Twig\Error\LoaderError; use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; #[Route("/", name: "main")] class mainController extends AbstractController { public string $model; private SearchHtmlView $searchView; private SearchCarUseCase $carUseCase; private SearchCarPresenterInterface $presenter; public function __construct( SearchHtmlView $searchView, SearchCarUseCase $carUseCase, SearchCarPresenterInterface $presenter ) { $this->searchView = $searchView; $this->carUseCase = $carUseCase; $this->presenter = $presenter; } /** * @throws SyntaxError * @throws RuntimeError * @throws LoaderError */ public function __invoke(Request $carRequest): Response { $form = $this->createForm(SearchFormType::class); $form->handleRequest($carRequest); if ($form->isSubmitted() && $form->isValid()) { $this->model = $form->get("car")->getData(); $this->carUseCase->searchCar($form, $this->model); // 可选:添加搜索成功提示 $this->addFlash("success", "搜索请求已发送"); } elseif ($form->isSubmitted() && !$form->isValid()) { // 仅在表单提交但验证失败时显示错误提示 $this->addFlash("message", "veuillez remplir le champ demande"); } return $this->searchView->generateView($form); } }
3. 清洁架构适配建议
为了符合清洁架构的分层原则,还可以做以下调整:
- Domain层解耦框架:将
Domain\Form\SearchFormType移到Infrastructure\Symfony\Form目录下,Domain层仅定义搜索请求的DTO(比如SearchCarRequest),避免Domain层依赖Symfony组件。 - UseCase解耦表单:
SearchCarUseCase的searchCar方法不应直接接收FormInterface,而是接收Domain层的SearchCarRequest对象,由控制器负责将表单数据映射到该DTO后传入UseCase,实现框架无关的业务逻辑。
内容的提问来源于stack exchange,提问作者Armad
相关产品推荐
相关产品推荐

