php Symfony2 - 如何在控制器中使用 __construct() 并访问 Securty.Context?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9736598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Symfony2 - How to use __construct() in a Controller and access Securty.Context?
提问by Mr Pablo
I am having some trouble with Symfony2. Namely in how to use the __construct() function. the Official Documentation is shockingly bad!
我在使用 Symfony2 时遇到了一些麻烦。即如何使用 __construct() 函数。官方文档非常糟糕!
I want to be able to use the following:
我希望能够使用以下内容:
public function __construct()
{
parent::__construct();
$user = $this->get('security.context')->getToken()->getUser();
}
How ever I get the following error:
我怎么会收到以下错误:
Fatal error: Cannot call constructor in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 11
致命错误:无法在第 11 行的 /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php 中调用构造函数
Line 11 is "parent::__construct();"
第 11 行是“parent::__construct();”
I removed it and got the following, new error
我删除它并得到以下新错误
Fatal error: Call to a member function get() on a non-object in /Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 242
致命错误:在第 242 行的 /Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php 中的非对象上调用成员函数 get()
I thinkI might need to set up the ContainerInterface DIC, but I have no idea how to do this (I tried and failed, miserably)
我想我可能需要设置 ContainerInterface DIC,但我不知道该怎么做(我尝试过但失败了,很惨)
Any ideas folks?
大家有什么想法吗?
Update- Tried changing to extend ContainerAware and got this error:
更新- 尝试更改以扩展 ContainerAware 并收到此错误:
Fatal error: Class DEMO\DemoBundle\Controller\Frontend\HomeController cannot extend from interface Symfony\Component\DependencyInjection\ContainerAwareInterface in /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php on line 43
致命错误:类 DEMO\DemoBundle\Controller\Frontend\HomeController 不能从 Symfony\Component\DependencyInjection\ContainerAwareInterface 接口扩展到 /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php 第 43 行
Using the following code in the controller:
在控制器中使用以下代码:
<?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;
}
回答by Cerad
I'm assuming you are extending the default Symfony controller? If so, a look at the code will reveal the answer:
我假设您正在扩展默认的 Symfony 控制器?如果是这样,查看代码将揭示答案:
namespace Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
class Controller extends ContainerAware
{
Notice that there is no Controller::__construct defined so using parent::__construct will not get you anywhere. If we look at ContainerAware:
请注意,没有定义 Controller::__construct,因此使用 parent::__construct 不会让您到任何地方。如果我们看一下 ContainerAware:
namespace Symfony\Component\DependencyInjection;
class ContainerAware implements ContainerAwareInterface
{
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}
Again, no constructor and the container is not available until setContainer is called. So override setContainer and put your logic there. Or else just make a stand alone controller that does not extend the base controller class and inject your dependencies directly into the constructor.
同样,在调用 setContainer 之前,没有构造函数和容器不可用。所以覆盖 setContainer 并将您的逻辑放在那里。或者只是制作一个不扩展基本控制器类的独立控制器,并将您的依赖项直接注入到构造函数中。
Update Aug 2017
2017 年 8 月更新
Still getting a few hits on this. If you really want to execute something before each controller then use a kernel controller listener. If all you need is the user then of course use getUser(). And please don't override setContainer(). In some cases it would work but it would just convolute your code.
仍然得到一些点击。如果您真的想在每个控制器之前执行某些操作,请使用内核控制器侦听器。如果您只需要用户,那么当然使用 getUser()。并且请不要覆盖 setContainer()。在某些情况下,它会起作用,但它只会使您的代码变得复杂。
回答by leek
I also frequently want an instance of the current User in most of my controllers. I find it is easiest to just do something like this:
我还经常希望在我的大多数控制器中都有一个当前用户的实例。我发现做这样的事情最简单:
class SomeController extends Controller
{
protected $user;
public function getUser()
{
if ($this->user === null) {
$this->user = $this->get('security.context')->getToken()->getUser();
}
return $this->user;
}
}
However, this is an overly simplistic example case. If you want to do more work before a Controller action is started, I suggest you define your Controller as a Service.
然而,这是一个过于简单的示例案例。如果您想在 Controller 操作开始之前做更多工作,我建议您将 Controller 定义为 Service。
Also take a look at this article: Moving Away from the Base Controller
另请看这篇文章:远离基础控制器
回答by Tjorriemorrie
I have to retrieve the 'facade' manager for my rest api's resource. Not using the constructor and using a private function seems the easiest and simplest for me.
我必须为我的 rest api 资源检索“外观”管理器。不使用构造函数而使用私有函数对我来说似乎是最简单和最简单的。
/**
* 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 It's ok for me to use private/protected functions in my controller as long as it contains zero conditionals
PS 我可以在我的控制器中使用私有/受保护的函数,只要它包含零条件
回答by highroller
You cannot call getUser() or get() for services in controller constructors. If you remember that, you will save lots of debugging time.
您不能在控制器构造函数中为服务调用 getUser() 或 get()。如果您记住这一点,您将节省大量调试时间。
回答by Thibault Henry
I know the question is very old, but I didn't found an answer until now. So I'll share it.
我知道这个问题很老了,但直到现在我才找到答案。所以我来分享一下。
The goal here, is to execute a code everytime a action in our controller is called.
这里的目标是每次调用控制器中的操作时执行代码。
The __construct
method doesn't work, because it's called before anything else, so you can't access the service container.
该__construct
方法不起作用,因为它在其他任何事情之前调用,因此您无法访问服务容器。
The trick is to overload each method automatically when they are called :
诀窍是在调用每个方法时自动重载它们:
<?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);
}
}
Warning ! You have to define each method as a private method ! Or the __call
magic method won't be called.
警告 !您必须将每个方法定义为私有方法!或者__call
魔法方法不会被调用。
回答by Aerendir
There are only two solutions to this problem:
这个问题只有两种解决方法:
Use a private method as pointed out by @Tjorriemorrie here. But this is a dirty method for purists. (I'm using this! :D );
Define the controller as a service, but this way you will lose all the shortcuts provided by
Symfony\Bundle\FrameworkBundle\Controller\Controller
. Hereis the article that shows how to do this.
使用@Tjorriemorrie here指出的私有方法。但对于纯粹主义者来说,这是一种肮脏的方法。(我正在使用这个!:D);
将控制器定义为服务,但这样您将丢失
Symfony\Bundle\FrameworkBundle\Controller\Controller
. 这是显示如何执行此操作的文章。
As told, personally, in my situation, I prefere a solution like this:
如前所述,就我个人而言,我更喜欢这样的解决方案:
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;
}
}
This is typically a class that I call MyManager
where I put the code that I use in more than one action in the controller or that unusefully occupies lines (for example the code to create and populate forms, or other code to do heavy tasks or tasks that require a lot of code).
这通常是我调用的一个类,我MyManager
将在多个操作中使用的代码或无用地占用行的代码(例如,用于创建和填充表单的代码,或用于执行繁重任务或任务的其他代码)需要大量代码)。
This way I mantain the code in the action clear in its purposes, without adding confusion.
通过这种方式,我将操作中的代码保持在明确的目的,而不会增加混乱。
Maybe the use of a property to store the dependency is an overoptimization, but... I like it :)
也许使用属性来存储依赖项是一种过度优化,但是......我喜欢它:)
回答by gizmo_marco
As i see, Controllerextends ContainerAware, and if we take a look of ContainerAwareit implements ContainerAwareInterface. So, ContainerAwaremust have declared the exact methods in it's interface. Add this line
正如我所见,Controller扩展了ContainerAware,如果我们看一下ContainerAware它实现了ContainerAwareInterface。因此,ContainerAware必须在其接口中声明了确切的方法。添加这一行
public function __construct();
公共函数 __construct();
to the ContainerAwareInterfacedefinition and it will be solved.
到ContainerAwareInterface定义,它将被解决。