$this->container 在 Symfony3 上的控制器中为 NULL

Posted

技术标签:

【中文标题】$this->container 在 Symfony3 上的控制器中为 NULL【英文标题】:$this->container is NULL in Controller on Symfony3 【发布时间】:2017-10-12 13:55:33 【问题描述】:

当我在控制器 (ClientDomainController) 中调用它时遇到了一个烦人的问题:

    $this->getDoctrine()->getManager();

我收到了这个错误:

    Call to a member function has() on null

我查看了堆栈跟踪,发现:

    $this->container is null

我的控制器从 Symfony 控制器组件扩展而来:

    use Symfony\Bundle\FrameworkBundle\Controller\Controller;

有趣的是,在另一个控制器(HomeController)中,我做了完全相同的事情:

    从控制器扩展(完全相同的类) 获得教义 获取 EntityManager 使用管理器

这没有任何错误。

HomeController 和 ClientDomainController 之间唯一的区别是第二个是服务。所以我把它写在 services.yml 文件中:

    services:
        client_domain:
            class: AppBundle\Controller\ClientDomainController

最后我测试了很多东西,比如为我的控制器创建一个构造函数并将其添加到 services.yml 文件中(从未对功能性文件做过的事情):

    arguments: [ 'doctrine.orm.entity_manager' ]

【问题讨论】:

我认为您在 servicecontroller 之间感到困惑,您创建了一个 service 类,这样它就可以在控制器中使用,但我从未听说过像您所描述的那样的 服务控制器...虽然我不是 Symfony 专家 您要创建的服务是什么? @teeyo 在 Symfony 中,将控制器定义为服务是很常见的,如果做得好,效果会很好。 【参考方案1】:

当您将控制器注册为服务时,Symfony 会按照您告诉它的方式创建它。

所以不同的是,虽然你的控制器实现了ContainerAwareInterface(通过扩展Controller类),最终没有人调用setContainer方法来利用这个接口并设置$container的值。您必须在 services.yml 配置中手动完成,例如:

    calls:
        - [ setContainer, [ @service_container ] ]

但这不是最好的解决方案

一般来说,将控制器注册为服务是好的。它使它们更具可测试性和可维护性。

但只要您遵守 OOP 的良好规则,这就是事实。 在这种情况下,当您传递整个容器时,这意味着:

    如果您不传递容器,您的控制器实例可能会处于无效状态(或者您应该处理它可能不会在您使用它的任何地方设置),这在设计上很糟糕。 很难测试,因为您必须模拟整个容器,而不是仅模拟此控制器使用的依赖项。 依赖没有明确定义,因为您需要查看控制器的代码才能知道从容器中提取的依赖是什么。

简而言之,依赖项应该通过 contrustor 传递,就像您最后所做的那样,或者当依赖项仅用于此特定操作时,您可以使用 action-based dependency injection。

实际上最好的解决方案是甚至不扩展基类 Controller 以使您的控制器框架独立。

【讨论】:

请使用构造函数代替操作:How to Slowly Turn your Symfony Project to Legacy with Action Injection【参考方案2】:

你的控制器应该是这样的:

class HelperController extends Controller


    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected $container;

    /**
     * HelperController constructor.
     *
     * @param ContainerInterface $container
     */
    public function __construct(ContainerInterface $container)
    
        $this->container = $container;
    
  

在配置文件中(在我的例子中是 xml)

    <service id="xxx.helper_controller" class="xxx\EspacePROBundle\Controller\HelperController">
        <argument type="service" id="service_container" />
    </service>

希望对你有帮助。

【讨论】:

我要补充一点,注入整个服务容器并不是一个好习惯。如果您只需要 EntityManager,请将其注入并在您的控制器构造函数中以$this-&gt;entityManager 的形式启动它 问题是容器为空,没有注入实体管理器。 从不要求在构造函数中使用 Container。此外在控制器中。而是按照@OKsure 的建议使用 EntityManager【参考方案3】:

正如 Jakub Matczak 的回答中所述,控制器的 DI 容器未设置。

除了在 services.yml 中添加 calls 部分之外,您还可以在要使用控制器的类的构造函数中调用 setContainer

use App\Controller\MyController;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyClass 

    /**
     * The injected controller
     * @var MyController
     */
    protected $my_controller;

    public function __construct(MyController $my_controller, ContainerInterface $container) 
        $this->my_controller = $my_controller;
        $this->my_controller->setContainer($container);
    

【讨论】:

以上是关于$this->container 在 Symfony3 上的控制器中为 NULL的主要内容,如果未能解决你的问题,请参考以下文章

matlab_第八章章符号计算

matlab_第八章章符号计算

Cakephp:分页不同于当前的模型并使用Containable

[Redux] Generating Containers with connect() from React Redux (FooterLink)

解决At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this log(示例代

Ruby 方法“to_sym”有啥作用?