Symfony2 – Как использовать __construct () в контроллере и получить доступ к Securty.Context?

У меня проблемы с Symfony2. А именно, как использовать функцию __construct (). Официальная документация ужасно плоха!

Я хочу иметь возможность использовать следующее:

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

Как всегда я получаю следующую ошибку:

Неустранимая ошибка: невозможно вызвать конструктор в /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php в строке 11

Строка 11 – «parent :: __ construct ();»

Я удалил его и получил следующую, новую ошибку

Неустранимая ошибка: вызов функции-члена get () для не-объекта в /Sites/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php в строке 242

Я думаю, мне, возможно, понадобится создать DIC ContainerInterface, но я понятия не имею, как это сделать (я пробовал и терпел неудачу,

Любые идеи?

Обновление. Пробовал переходить на расширение ContainerAware и получил эту ошибку:

Неустранимая ошибка: класс DEMO \ DemoBundle \ Controller \ Frontend \ HomeController не может распространяться на интерфейс Symfony \ Component \ DependencyInjection \ ContainerAwareInterface в /Sites/src/DEMO/DemoBundle/Controller/Frontend/HomeController.php в строке 43

Используя следующий код в контроллере:

 <?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 и поместите туда свою логику. Или просто создайте автономный контроллер, который не расширяет базовый класс контроллера и не вводит ваши зависимости непосредственно в конструктор.

Обновление Aug 2017

Все еще получаю несколько хитов. Если вы действительно хотите что-то выполнить перед каждым контроллером, используйте прослушиватель контроллера ядра. Если все, что вам нужно, это пользователь, то, конечно, используйте 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; } } 

Однако это слишком упрощенный пример. Если вы хотите сделать больше работы до того, как действие контроллера будет запущено, я предлагаю вам определить ваш контроллер как услугу .

Также взгляните на эту статью: переход от базового контроллера

Мне нужно найти менеджера «фасад» для ресурса моего ави. Не использовать конструктор и использовать закрытую функцию кажется самым простым и простым для меня.

 /** * 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 где я помещаю код, который я использую более чем в одном действии в контроллере, или который незаметно занимает строки (например, код для создания и заполнения форм или другой код для выполнения тяжелых задач или задач которые требуют большого количества кода).

Таким образом, я делаю код в действии ясным в своих целях, не добавляя путаницы.

Возможно, использование свойства для хранения зависимости – это переоптимизация, но … мне это нравится 🙂

Как я вижу, контроллер расширяет ContainerAware , и если мы посмотрим на ContainerAware, он реализует ContainerAwareInterface . Таким образом, ContainerAware должен был объявить точные методы в своем интерфейсе. Добавьте эту строку

публичная функция __construct ();

к определению ContainerAwareInterface, и оно будет разрешено.