У меня проблемы с 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
не будет вызван.
Решить эту проблему можно только двумя способами:
Используйте частный метод, как указано здесь @Tjorriemorrie. Но это грязный метод для пуристов. (Я использую это!: D);
Определите контроллер как службу, но таким образом вы потеряете все ярлыки, предоставляемые 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, и оно будет разрешено.