$ this->在Symfony3上的Controller中,容器为NULL

时间:2017-10-12 13:55:34

标签: php symfony web symfony-3.3

当我在控制器(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. 使用经理
  5. 这没有任何错误。

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

        services:
            client_domain:
                class: AppBundle\Controller\ClientDomainController
    

    最后,我测试了许多内容,例如为我的控制器创建一个构造函数,并将其添加到services.yml文件中(对于函数文件从未做过的事情):

        arguments: [ 'doctrine.orm.entity_manager' ]
    

3 个答案:

答案 0 :(得分:2)

当您将控制器注册为服务时,Symfony会像您告诉它一样创建它。

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

    calls:
        - [ setContainer, [ @service_container ] ]

但这不是最佳解决方案

将控制器注册为服务通常很好。它使它们更易于测试和维护。

但只要您坚持OOP的良好规则,情况就是如此。 在这种情况下,当您传递整个容器时,它意味着:

  1. 如果您没有传递容器,您的控制器实例可能会处于无效状态(或者您应该处理它可能无法在您使用它的任何位置设置),这在设计上是不好的。
  2. 很难测试,因为你必须模拟整个容器而不是只有这个控制器使用的依赖。
  3. 未明确定义依赖关系,因为您需要查看控制器代码以了解从容器中获取的依赖关系。
  4. 简而言之,依赖应该像最后一样通过控制器传递,或者当仅在此特定操作中使用依赖时,可以使用action-based dependency injection

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

答案 1 :(得分:0)

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

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>

我希望它有所帮助。

答案 2 :(得分:-1)

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

或者将calls部分添加到services.yml中,您可以在要使用控制器的类的构造函数中调用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);
    }
}