繁体   English   中英

$ this-> container在Symfony3上的Controller中为NULL

[英]$this->container is NULL in Controller on Symfony3

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

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

我收到此错误:

    Call to a member function has() on null

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

    $this->container is null

我的控制器来自Symfony Controller组件:

    use Symfony\Bundle\FrameworkBundle\Controller\Controller;

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

  1. 从Controller扩展(完全相同的类)
  2. 获取学说
  3. 获取EntityManager
  4. 使用经理

而且这没有任何错误。

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

    services:
        client_domain:
            class: AppBundle\Controller\ClientDomainController

最后,我测试了很多事情,例如在控制器中创建一个构造函数,并将其添加到services.yml文件中(从不对功能函数执行此操作):

    arguments: [ 'doctrine.orm.entity_manager' ]

然后,当您将控制器注册为服务时,Symfony会像您说的那样创建它。

因此区别在于,尽管您的控制器实现了ContainerAwareInterface (通过扩展Controller类),但最终没有人调用setContainer方法来利用此接口并设置$container的值。 您必须在services.yml配置中手动执行此操作,例如:

    calls:
        - [ setContainer, [ @service_container ] ]

但这不是最好的解决方案

将您的控制器注册为服务通常是好的。 它使它们更具可测试性和可维护性。

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

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

简而言之,应该像最后一样通过依赖者传递依赖关系,或者当仅在此特定操作中使用依赖关系时,可以使用基于操作的依赖关系注入

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

您的控制器应如下所示:

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>

希望对您有所帮助。

如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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM