Я начал создавать проект с использованием Symfony 2. Мне нужно обмениваться данными между всеми контроллерами.
Я добавил базовый контроллер, который расширяет Symfony \ controller, и каждый из моих контроллеров расширяет этот базовый контроллер
class BaseController extends Controller class HomeController extends BaseController
Этот базовый контроллер будет использоваться для таких вещей, как назначение глобальных переменных ветви (я знаю, что могу это сделать в конфиге, но некоторые из переменных будут получены из других файлов конфигурации и базы данных).
Поэтому мне показалось, что я могу ссылаться на контейнер, поскольку контроллер знает о контейнере, однако я не использую функции (от конструктора).
public function __construct ()
Я видел, как люди упоминали прохождение контейнера в качестве параметра и упоминание служб, но я посмотрел и не могу понять. Все, чего я хочу достичь, это:
public function __construct (Container $container) { $container->get('twig').addGlobal('foo'); }
Это общий камень преткновения для новичков Symfony 2. Вопрос о контроллере / контейнере был задан за сотни раз, поэтому вы не одиноки (подсказка).
Почему ваш конструктор конструктора контроллера не работает?
Начните с поиска по поставщику / symfony … FrameworkBundle / Controller / Controller.php. Хм. Нет конструктора там, где червь – это контейнер? Мы видим, что Controller расширяет ContainerAware. Это кажется многообещающим. Мы смотрим ContainerAware (пространство имен помогает найти, где находится файл), и еще раз, никакой конструктор. Однако существует метод setContainer, поэтому мы можем предположить, что контейнер вводится в контроллер после вызова конструктора. Достаточно распространен в рамках основанной на зависимостях инъекции.
Итак, теперь мы знаем, почему код конструктора терпит неудачу. Контейнер еще не был введен. Глупый дизайн? Время для другой структуры? На самом деле, нет. Давайте посмотрим правде в глаза, чтобы все ваши контроллеры расширяли базовый контроллер только для того, чтобы установить некоторые переменные ветви, не лучший дизайн.
Способ Symfony для выполнения кода перед выполнением действия контроллера заключается в создании прослушивателя событий контроллера. Он будет выглядеть примерно так:
namespace Cerad\Bundle\CoreBundle\EventListener; use Symfony\Component\DependencyInjection\ContainerAware; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class ModelEventListener extends ContainerAware implements EventSubscriberInterface { public static function getSubscribedEvents() { return array(KernelEvents::CONTROLLER => array( array('doTwig', 0), // 0 is just the priority )); } public function doTwig(FilterControllerEvent $event) { // Ignore sub requests if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) return; $this->container->get('twig')->addGlobal('foo'); } } // This goes in services.yml parameters: cerad_core__model_event_listener__class: Cerad\Bundle\CoreBundle\EventListener\ModelEventListener services: cerad_core__model_event_listener: class: '%cerad_core__model_event_listener__class%' calls: - [setContainer, ['@service_container']] tags: - { name: kernel.event_subscriber }
Итак, теперь у нас есть желаемая функциональность без необходимости в классе базового контроллера.
Также обратите внимание, что к контроллеру можно получить доступ через событие. Поскольку контроллер создан, но метод действия еще не вызван, вы можете вызвать методы контроллера или ввести данные непосредственно в контроллер. Это редко необходимо. В большинстве случаев вы добавляете дополнительную информацию к объекту запроса, который затем вводится в метод действия контроллера.
Это действительно приятный дизайн, когда вы устраиваете слушателей и сервисы.
Пожалуйста, внимательно прочитайте этот вопрос – передайте данные Symfony2 между пучками и контроллерами , попробуйте использовать код, включенный в него.
Например, вы можете использовать сервис для решения своей проблемы.
Если вы посмотрите на класс Controller, вы увидите следующее:
class Controller extends ContainerAware
Это означает, что вы можете извлечь веточку из контейнера так же просто, как это:
$twig = $this->get('twig');
Но я бы порекомендовал вам использовать пользовательское расширение ветки в вашем случае.