【问题标题】:Accessing $this->container in controller throws Catchable Fatal Error exception?在控制器中访问 $this->container 会引发 Catchable Fatal Error 异常?
【发布时间】:2014-10-08 17:36:56
【问题描述】:

我有以下控制器:

namespace Acme\CompanyBundle\Controller;
use Symfony\Component\DependencyInjection\Container;

/**
 * Company controller.
 *
 */
class CompanyController extends Controller
{
    protected $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function getData()
    {
        $userObj = $this->container->get('security.context')->getToken()->getUser();
    }
}

在我的services.yml 文件中,我注入了Container 类:

parameters:
    acme.controller.company.class:  Acme\ContainerBundle\Controller\CompanyController

services:
    acme.controller.company:
        class:      %acme.controller.company.class%
        arguments:  [@service_container]

加载此控制器时,出现以下错误:

可捕获的致命错误:参数 1 传递给 Acme\CompanyBundle\Controller\CompanyController::__construct() 必须是 Symfony\Component\DependencyInjection\Container 的一个实例,无 给定,在线调用 C:\wamp\www\symfony\app\cache\dev\classes.php 2785 并定义于 C:\wamp\www\symfony\src\Acme\CompanyBundle\Controller\CompanyController.php 线...

如您所见,这是将Container 对象简单地注入到控制器中,但会引发很好的错误。这里有什么问题?

类似问题发布在另一个SO thread here

【问题讨论】:

  • 原因是你的路由还在使用MyBundle:CompanyController:action。您需要将控制器作为服务调用_controller:acme.controller.company:action symfony.com/doc/current/cookbook/controller/service.html
  • 是的,很棒。我能理解。但是,您能否根据我的配置重写该设置,以便我清楚地理解?

标签: php symfony


【解决方案1】:

您不需要在控制器中注入容器,只要它们扩展了您的 Controller 基类即可。

只要做:

namespace Acme\CompanyBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

/**
 * Company controller.
 *
 */
class CompanyController extends Controller
{
    public function getData()
    {
        $userObj = $this->get('security.context')->getToken()->getUser();
    }
}

【讨论】:

  • 我在处理程序文件(AuthHandler、SecurityHandler 等)中使用了这种类似的注入。但它在那里工作而不会引发任何错误。我对 symfony 的依赖注入行为感到非常困惑和沮丧。
  • 抱歉,我没看到是Controller。我已经更新了我的答案。
  • 我试过了,得到了这个错误:错误:在 C:\wamp\www\symfony\src\Acme\CompanyBundle\ 中的非对象上调用成员函数 getUser() Controller\CompanyController.php 行 ...
  • 尝试改用$this->get('security.context')->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');。我知道这不是您想要的,但它会产生错误吗?
  • 谢谢,这是个好建议。我试过了,但它不会产生任何错误。
【解决方案2】:

默认情况下,路由如下所示:

cerad_player_wanabe_list:
    pattern:  /player-request/list
    defaults: 
        _controller: CeradPlayerWanabeBundle:Player/PlayerList:list

Symfony\Component\HttpKernel\HttpKernel::handle($request) 方法从请求对象中提取 _controller 属性。如果属性中有两个冒号,则它将属性转换为类名并使用 new 运算符创建实例。如果实例实现了 ContainerAwareInterface,则容器被注入到控制器实例中。未使用您定义的控制器服务。因此,没有参数被传递给构造函数的错误。

另一方面,如果 _controller 只有一个冒号,则控制器会作为服务从容器中拉出。不检查 ContainerAwareInterface。您可以通过服务定义注入依赖项。

这一切都记录在:http://symfony.com/doc/current/cookbook/controller/service.html

所以对于这个特定的问题,你的路线应该是这样的:

cerad_player_wanabe_list:
    pattern:  /player-request/list
    defaults: 
        _controller: acme.controller.company:action

这确实引发了您为什么尝试将控制器定义为服务的问题。默认方法已经完全符合您的要求,因此您不会获得任何东西。

将服务定义为容器的基本原理是,您可以准确控制控制器使用的依赖项。使控制器更易于理解和测试。

注入完整的容器几乎破坏了将控制器定义为服务的价值。

【讨论】:

    【解决方案3】:

    永远不要将容器注入到某些东西(服务、控制器或其他东西)中 而是尝试注入 securityContext 或通过上面建议的 symfony 控制器的辅助方法访问它。

    它不是一个对象的令牌只是因为控制器的路由可能不在防火墙下

    【讨论】:

    • $this->container 在我的控制器中不可用。那么没有这个我怎么能访问任何其他服务或“secutity.context”呢?
    • 它适用于任何 sf 控制器。顺便说一句,您可以将 security.context 或任何东西作为服务注入。查看 SF 文档。提示:如果您需要注入大量服务,解决方案不是注入所有容器,而是更改可能糟糕或糟糕的设计。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多