繁体   English   中英

Symfony2 - 如何在Controller中使用__construct()并访问Securty.Context?

[英]Symfony2 - How to use __construct() in a Controller and access Securty.Context?

我在使用Symfony2时遇到了一些麻烦。 即在如何使用__construct()函数。 官方文档非常糟糕!

我希望能够使用以下内容:

public function __construct()
{
    parent::__construct();
    $user = $this->get('security.context')->getToken()->getUser();
}

我怎么得到以下错误:

致命错误:无法在第11行的/Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php中调用构造函数

第11行是“parent :: __ construct();”

我删除它并得到以下新错误

致命错误:在第242行的/Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php中调用非对象的成员函数get()

我可能需要设置ContainerInterface DIC,但我不知道如何做到这一点(我试过并失败,悲惨)

有什么想法吗?

更新 - 尝试更改以扩展ContainerAware并出现此错误:

致命错误:类DEMO \\ DemoBundle \\ Controller \\ Frontend \\ HomeController无法从第43行的/Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php中的界面Symfony \\ Component \\ DependencyInjection \\ ContainerAwareInterface扩展

在控制器中使用以下代码:

<?php

namespace DEMO\DemoBundle\Controller\Frontend;

use Symfony\Component\DependencyInjection\ContainerAware;

class HomeController extends ContainerAwareInterface
{
     protected $container;

     public function setContainer(ContainerInterface $container = null)
     {
         $this->container = $container;
     }

我假设您正在扩展默认的Symfony控制器? 如果是这样,查看代码将揭示答案:

namespace Symfony\Bundle\FrameworkBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerAware;

class Controller extends ContainerAware
{

请注意,没有定义Controller :: __构造,因此使用parent :: __ construct将无法到达任何地方。 如果我们看看ContainerAware:

namespace Symfony\Component\DependencyInjection;

class ContainerAware implements ContainerAwareInterface
{
    protected $container;
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }
}

同样,在调用setContainer之前,没有构造函数和容器可用。 所以重写setContainer并将你的逻辑放在那里。 或者只是创建一个独立的控制器,它不扩展基本控制器类并将您的依赖项直接注入构造函数。

2017年8月更新

还有一些点击这个。 如果你真的想在每个控制器之前执行某些操作,那么使用内核控制器监听器。 如果你需要的只是用户,那么当然要使用getUser()。 请不要覆盖setContainer()。 在某些情况下,它可以工作,但它只会卷入你的代码。

在大多数控制器中,我也经常需要当前用户的实例。 我觉得做这样的事情最简单:

class SomeController extends Controller
{
    protected $user;

    public function getUser()
    {
        if ($this->user === null) {
            $this->user = $this->get('security.context')->getToken()->getUser();
        }
        return $this->user;
    }
}

但是,这是一个过于简单的示例案例。 如果您想在启动Controller操作之前完成更多工作,我建议您将Controller定义为服务

另请参阅本文: 远离基本控制器

我必须为我的rest api资源检索'facade'管理器。 不使用构造函数并使用私有函数对我来说似乎是最简单和最简单的。

/**
 * Class ExchangesController
 * @RouteResource("Exchange")
 */
class ExchangesController extends Controller
{
    /**
     * Get exchange manager
     * @return ExchangeManager
     */
    protected function getExchangeManager()
    {
        return $this->get('exchange_manager');
    }

    /**
     * @ApiDoc(
     *  description="Retrieve all exchanges",
     *  statusCodes={
     *    200="Successful"
     *  }
     * )
     */
    public function cgetAction()
    {
        return $this->getExchangeManager()->findAll();
    }

PS只要它包含零条件,我就可以在控制器中使用私有/受保护功能

您不能在控制器构造函数中为服务调用getUser()或get()。 如果你还记得,那么你将节省大量的调试时间。

我知道问题已经很久了,但直到现在我才找到答案。 所以我会分享它。

这里的目标是每次调用控制器中的动作时执行代码。

__construct方法不起作用,因为它在其他任何方法之前被调用,因此您无法访问服务容器。

诀窍是在调用每个方法时自动重载:

<?php
namespace AppBundle\DefaultController;

class DefaultController extends Controller {
    private function method1Action() {
        return $this->render('method1.html.twig');
    }

    private function method2Action() {
        return $this->render('method2.html.twig');
    }

    public function __call($method, $args) {
         $user = $this->get('security.tokenStorage')->getToken()->getUser();

         // Do what you want with the User object or any service. This will be executed each time before one of those controller's actions are called.

        return call_user_func_array(array($this, $method), $args);
    }
}

警告 ! 您必须将每个方法定义为私有方法! 或者不会调用__call魔术方法。

这个问题只有两个解决方案:

  1. 使用@Tjorriemorrie 在此处指出的私有方法。 但这对纯粹主义者来说是一种肮脏的方法。 (我正在使用它!:D);

  2. 将控制器定义为服务,但这样您将丢失Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller提供的所有快捷方式。 这里展示了如何做到这一点的文章。

据我所知,在我看来,我更喜欢这样的解决方案:

class MyController extends Controller
{
    /** @var AwesomeDependency */
    private $dependency;

    public function anAction()
    {
         $result = $this->getDependency();
    }

    /**
     * Returns your dependency.
     */
    private function getDependency()
    {
        if (null === $this->dependency)
            $this->dependency = $this->get('your.awesome.dependency');

        return $this->dependency;
    }
}

这通常是一个我称之为MyManager的类,我将我在控制器中使用的代码放在多个操作中,或者无用地占用行(例如用于创建和填充表单的代码,或其他代码来执行繁重的任务或任务这需要很多代码)。

这样我就可以清除动作中的代码,而不会增加混淆。

也许使用属性来存储依赖是一种过度优化,但是......我喜欢它:)

正如我所见, Controller扩展了ContainerAware ,如果我们看一下ContainerAware,它就实现了ContainerAwareInterface 因此, ContainerAware必须在其界面中声明确切的方法。 添加此行

public function __construct();

ContainerAwareInterface定义,它将被解决。

暂无
暂无

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

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