【问题标题】:Symfony3, DI, Error when injecting a custom repository in controllerSymfony3,DI,在控制器中注入自定义存储库时出错
【发布时间】:2016-03-20 20:05:21
【问题描述】:

得到以下异常:

Catchable Fatal Error: Argument 1 passed to AppBundle\Controller\AudienceController::__construct() must be an instance of AppBundle\Repository\AudienceRepository, none given, called in /home/eddy/Projects/tm/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 162 and defined

意思是,我使用自定义存储库作为构造函数参数定义了我的控制器,但是存储库从未传递或未创建。我尝试调试到 ControllerResolver 但无济于事。

[services.yml]
services:
    app.audience_repository:
        class: Doctrine\ORM\EntityRepository
        factory: ["@doctrine.orm.entity_manager", getRepository]
        arguments:
            - AppBundle\Entity\Audience
    app.audience_controller:
        class: AppBundle\Controller\AudienceController
        arguments:
            - "@app.audience_repository"


[AppBundle\Controller\AudienceController.php]
    class AudienceController extends Controller
    {
        /**
         * @var AudienceRepository
         */
        private $repository;

        /**
         * @param AudienceRepository $repository
         */
        public function __construct(AudienceRepository $repository)
        {
            $this->repository = $repository;
        }

[AppBundle\Repository\AudienceRepository]
class AudienceRepository extends EntityRepository
{
    public function save(Audience $audience)
    {
        $this->getEntityManager()->persist($audience);
        $this->getEntityManager()->flush();
    }
}

[AppBundle\Entity\Audience.php]
/**
 * Audience
 *
 * @ORM\Table(name="audience")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\AudienceRepository")
 */
class Audience

我认为这是根据 http://php-and-symfony.matthiasnoback.nl/2014/05/inject-a-repository-instead-of-an-entity-manager/ 对 symfony3 的修改(参见 https://stackoverflow.com/a/20348821/30759),应该可以工作,但我不断收到此错误。

Stacktrace:
at ErrorHandler ->handleError ('4096', 'Argument 1 passed to AppBundle\Controller\AudienceController::__construct() must be an instance of AppBundle\Repository\AudienceRepository, none given, called in /home/eddy/Projects/tm/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 162 and defined', '/home/eddy/Projects/tm/src/AppBundle/Controller/AudienceController.php', '23', array()) 
in src/AppBundle/Controller/AudienceController.php at line 23   + 
at AudienceController ->__construct () 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php at line 162   + 
at ControllerResolver ->instantiateController ('AppBundle\Controller\AudienceController') 
in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php at line 81   + 
at ControllerResolver ->instantiateController ('AppBundle\Controller\AudienceController') 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php at line 150   + 
at ControllerResolver ->createController ('AppBundle\Controller\AudienceController::newAction') 
in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php at line 73   + 
at ControllerResolver ->createController ('AppBundle\Controller\AudienceController::newAction') 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php at line 76   + 
at ControllerResolver ->getController (object(Request)) 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/TraceableControllerResolver.php at line 46   + 
at TraceableControllerResolver ->getController (object(Request)) 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 127   + 
at HttpKernel ->handleRaw (object(Request), '1') 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 62   + 
at HttpKernel ->handle (object(Request), '1', true) 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php at line 169   + 
at Kernel ->handle (object(Request)) 
in web/app_dev.php at line 30   + 
at require ('/home/eddy/Projects/tm/web/app_dev.php') 
in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php at line 40   + 

非常感谢任何帮助:)

【问题讨论】:

  • 你需要告诉你的路由控制器被定义为服务:symfony.com/doc/current/cookbook/controller/service.html。顺便说一句,除非您将 setContainer 添加到控制器服务定义中,否则您将无法使用基本控制器类中的任何辅助方法(如渲染)。

标签: dependency-injection symfony


【解决方案1】:

在您链接到的文章(“注入存储库而不是实体管理器”)中,他写了关于“正常”服务的文章,我还认为如果适用,您应该注入存储库而不是实体管理器。 但是:在 symfony 中,控制器默认不是服务。

基本上有两种选择:

选项 1:告诉 Symfony 你的控制器是一个服务

因为这有点复杂,所以我把这个链接留在这里:How to Define Controllers as Services

在这种情况下,您不应该扩展 Controller 基类,这反过来意味着您不能使用它提供的方法。如果你无论如何都不使用它们,这没关系,你可以去。

如果不是(例如您想使用“render”方法),您还必须使用 setContainer 方法将服务容器注入到您的控制器中,并且您做了很多工作才能再次使用基本控制器。这就是为什么我会推荐使用选项 2

选项 2:使用 Controller 类中的辅助方法(我更喜欢这个)

$audienceRepo = $this->getDoctrine()->getRepository(Audience::class);

在这种情况下,您不必将控制器定义为服务,您可以像以前一样使用它。

【讨论】:

  • 选项 3:从基本控制器扩展您的控制器并从您的服务定义中调用 setContainer。将存储库以及其他特定于控制器的服务注入到构造函数中。两全其美。
  • 这就是我(试图)在选项 1 中描述的内容,但在我看来,仅仅避免使用基本控制器的“get”方法需要付出太多努力。当然,如果你想这样做,这是可能的。
  • 在服务定义中添加一行以换取所有标准控制器辅助函数对我来说似乎是合理的,但每个函数也是如此。
  • 让我看看我是否理解选项 #2:所以存储库不会作为构造函数中的依赖项注入?
  • 没错。基本上这违反了 DI 原则,因为您从控制器内部请求服务,但它更易于使用。您还应该阅读这篇文章,以获取更多信息为什么要这样做(或为什么不这样做):knpuniversity.com/screencast/question-answer-day/…
猜你喜欢
  • 1970-01-01
  • 2014-04-22
  • 2019-09-30
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 2016-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多