Примечание. Начиная с версии 2.8 Symfony предоставила
autowire: true
для конфигурации службы, а с версии 3.3 Symfony предоставилаalias
(вместоautowire_types
) псевдоним конкретного объекта для интерфейса для автоматической инъекции зависимостей в "контроллеры как службы". Там также имеется пучок, позволяющий автоувеличивать методы "действия" контроллера, хотя я отошел от этого и больше сосредоточился на вариации шаблона ADR (который, в основном, представляет собой один класс "действия" с методом интерфейса и не толкая нагрузку методов действий в рамках одного класса, что в конечном итоге приводит к архитектурному кошмару). Это, фактически, то, что я искал все эти годы, и теперь больше не нужно "подключаться" к достойному рекурсивному инжектору зависимостей (auryn), поскольку структура теперь обрабатывает то, что у него должно было быть четыре года назад. Я оставлю этот ответ здесь, если кто-то захочет проследить шаги, которые я сделал, чтобы посмотреть, как работает ядро, и некоторые параметры, доступные на этом уровне.
Примечание. Хотя этот вопрос в первую очередь нацелен на Symfony 3, он также должен иметь отношение к пользователям Symfony 2, поскольку логика ядра, похоже, не сильно изменилась.
Я хочу изменить способ создания контроллеров в Symfony. Логика их создания в настоящее время находится в HttpKernel:: handle и, более конкретно, HttpKernel:: handleRaw. Я хочу заменить call_user_func_array($controller, $arguments)
на свой собственный инжектор, выполняющий эту конкретную строку.
Параметры, которые я пробовал до сих пор:
- Расширение
HttpKernel::handle
с помощью моего собственного метода, а затем с вызовом symfony
http_kernel:
class: AppBundle\HttpKernel
arguments: ['@event_dispatcher', '@controller_resolver', '@request_stack']
Недостатком этого является то, что, поскольку handleRaw
является закрытым, я не могу его распространять без хакерского отражения, поэтому мне пришлось бы копировать и вставлять тонну кода.
- Создание и регистрация нового контроллера.
controller_resolver:
class: AppBundle\ControllerResolver
arguments: []
Это было фундаментальное недоразумение, которое у меня было, поэтому я решил записать его здесь. Задача распознавателя - решить, где найти контроллер как вызываемый. На самом деле это еще не вызвано. Я более чем доволен тем, как Symfony берет маршруты от routes.yml
и вычисляет класс и метод для вызова контроллера как вызываемого.
- Добавление прослушивателя событий на
kernel.request
kernel.request:
class: MyCustomRequestListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 33 /** Important, we'll get to why in a minute **/ }
Взглянув на Документацию компонента Http Kernel, мы видим, что она имеет следующую типичную цель:
Чтобы добавить дополнительную информацию в запрос, инициализировать части системы или вернуть ответ, если это возможно (например, уровень безопасности, который запрещает доступ).
Я решил, что, создав нового слушателя, используя мой пользовательский инжектор для создания моего контроллера, а затем вернет ответ в этом слушателе, обойдется остальная часть кода, который создает экземпляр контроллера. Это то, что я хочу! Но есть главный недостаток:
Symfony Profiler не появляется или ничего из этого материала, это просто мой ответ и что он. Мертв. Я обнаружил, что я могу переключить приоритет с 31 до 33 и переключиться между моим кодом и Symfonys, и я считаю, что это из-за прослушивателя роутера priority. Я чувствую, что иду по неверному пути.
- Прослушивание события kernel.controller.
Нет, это позволяет мне изменить вызываемый, который будет вызываться call_user_func_array()
, а не то, как фактически создается экземпляр контроллера, что является моей целью.
Я документировал свои идеи, но я вышел. Как я могу достичь следующего?
- Измените способ создания и выполнения контроллеров, в частности
call_user_func_array()
, который находится в черном частном методе (спасибо Symfony) - Вернитесь к экземпляру контроллера по умолчанию, если моя работа не работает.
- Разрешить все остальное работать так, как ожидалось, например, загрузку профилировщика.
- Уметь связывать это с расширением для других пользователей.
Почему я хочу это сделать?
Контроллеры могут иметь множество разных методов для разных обстоятельств, и каждый метод должен иметь возможность вводить текст для того, что он требует по отдельности, а не иметь конструктор, чтобы взять все вещи, некоторые из которых могут даже не использоваться в зависимости от выполняемого метода контроллера, Контроллеры действительно не придерживаются принципа единой ответственности, и они являются "краеугольным камнем объекта". Но они такие, какие они есть.
Я хочу заменить, как контроллеры создаются с помощью моего собственного рекурсивного инсталлятора autowiring, а также то, как они выполняются, снова с рекурсивной интроспекцией через мой инжектор, поскольку пакет Symfony по умолчанию, похоже, не обладает этой функциональностью. Даже с последней опцией службы "autowire" в Symfony 2.8 +.