$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' ]
【问题讨论】:
我认为您在 service 和 controller 之间感到困惑,您创建了一个 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->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的主要内容,如果未能解决你的问题,请参考以下文章
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(示例代