我在使用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;
}
答案 0 :(得分:23)
我假设您正在扩展默认的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()。在某些情况下,它会起作用,但它会使你的代码卷入其中。
答案 1 :(得分:4)
我也经常想在大多数控制器中使用当前用户的实例。我觉得做这样的事情最容易:
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操作之前完成更多工作,我建议您define your Controller as a Service。
答案 2 :(得分:1)
我必须为我的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我可以在控制器中使用私有/受保护功能,只要它包含零条件
答案 3 :(得分:0)
您无法为控制器构造函数中的服务调用getUser()或get()。如果你还记得,那么你将节省大量的调试时间。
答案 4 :(得分:0)
我知道问题已经很久了,但直到现在我才找到答案。所以我会分享它。
此处的目标是每次调用控制器中的操作时执行代码。
__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
魔法。
答案 5 :(得分:0)
此问题只有两种解决方案:
使用@Tjorriemorrie here指出的私有方法。但这对纯粹主义者来说是一种肮脏的方法。 (我正在使用它!:D);
将控制器定义为服务,但这样您将失去Symfony\Bundle\FrameworkBundle\Controller\Controller
提供的所有快捷方式。 Here是一篇展示如何执行此操作的文章。
就个人而言,就我而言,我更喜欢这样的解决方案:
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
的类,我把我在代码中使用的代码放在控制器中的多个动作中,或者无用地占用行(例如用于创建和填充表单的代码,或其他用于执行需要大量代码的繁重任务或任务的代码。
这样我就可以清除动作中的代码,而不会引起混淆。
使用属性来存储依赖项可能是一种过度优化,但是......我喜欢它:)
答案 6 :(得分:-3)
正如我所见,控制器扩展 ContainerAware ,如果我们看一下 ContainerAware ,它会实现 ContainerAwareInterface 。因此, ContainerAware 必须在其界面中声明确切的方法。添加此行
公共职能__construct();
到 ContainerAwareInterface 定义,它将被解决。