【问题标题】:Symfony dependency-injection component. Autowiring not working [closed]Symfony 依赖注入组件。自动装配不起作用[关闭]
【发布时间】:2020-03-08 10:17:11
【问题描述】:

出于我自己的好奇心,我目前正在创建一个基于 Symfony 组件的框架。

我想使用 symfony/dependency-injection 组件及其自动装配系统。

路由(带有注释)工作正常,但是当我尝试自动连接服务(内部或外部)时,我收到错误:

Uncaught ArgumentCountError: Too few arguments to function Shopper\Controller\IndexController::__construct(), 0 passed in 

我创建了一个存储库来帮助您回答我的问题:https://github.com/kerwanp/shopper

【问题讨论】:

  • 默认的 ControllerResolver 不支持容器,因此它将始终使用新的 IndexController。请改用 ContainerControllerResolver。
  • 感谢您的快速答复!在“框架”参数中,我必须将“controller_resolver”从HttpKernel\Controller\ControllerResolver::class 更改为HttpKernel\Controller\ContainerControllerResolver::class?它不起作用,我误解了我的想法
  • 您当然必须将容器注入解析器并确保您的控制器被定义为公共服务。我没有方便的例子。但是您也许可以在 ContainerControllerResolver::instantiateController 上中断以查看发生了什么。
  • 您的意思是“将解析器注入容器”吗?我的控制器被定义为服务 (gist.github.com/kerwanp/5ad109080d472b0ab998797022b5dc82) ContainerControllerResolver 扩展了 ControllerResolver 并仅使用以下方式实例化控制器:return new $class(); 不传递任何参数。
  • 几点:您应该在在您的问题中包含相关代码(并且仅包含相关代码),而不是作为外部链接。此外,链接代码似乎不是引发此错误的代码(该示例中没有 IndexController)。另外,由于某种原因,您两次包含 autoloader.php 脚本,请不要这样做。

标签: php symfony dependency-injection


【解决方案1】:

我让它工作了。需要进行一些调整。

首先也是最重要的,你需要在使用之前编译容器:

# index.php
$container = $containerLoader->getContainerBuilder();
$container->compile(); ### ADD THIS ###

添加编译后,您将收到各种需要修复的与容器相关的错误消息。

Autowire 尝试连接 AnnotatedRouteControllerLoader,但由于需要依赖而失败。所以你需要忽略它:

# services.yaml ADD The Annotation directory
  Shopper\:
    resource: '../*'
    exclude: '../{Annotation,DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

之后,您需要调整 ContainerControllerResolver 以注入容器。请注意,“service_container”服务是一种内置服务,可解析为容器:

# ContainerLoader
        $this->containerBuilder->register('controller_resolver', HttpKernel\Controller\ContainerControllerResolver::class)
            ->setArguments([new Reference('service_container')]);

最后,通过代码注册的服务默认是私有的。您需要将您的“框架”服务明确设置为公开:

# ContainerLoader
        $this->containerBuilder->register('framework', Kernel::class)
            ->setArguments([
                new Reference('dispatcher'),
                new Reference('controller_resolver'),
                new Reference('request_stack'),
                new Reference('argument_resolver'),
            ])
            ->setPublic(true) ### ADD THIS ###
        ;

应该这样做。我应该指出,使用像“request_stack”这样的服务名称有点老套了。在大多数情况下,您应该考虑使用类名。

【讨论】:

  • 非常感谢这个完美的答案!
  • 很高兴为您提供帮助。一旦你进一步了解,一定要研究如何缓存容器和你的路线。在每个请求上完全重建容器会有点慢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2018-11-01
  • 1970-01-01
相关资源
最近更新 更多