Рефакторинг старого приложения на PHP.
Я пытаюсь использовать компонент внедрения зависимостей Symfony для внедрения сервисов в контроллеры (или другие сервисы), но я не знаю, как этого добиться, потому что документация по симфонии более подготовлена для использования фреймворка, чем компонентов фреймворка.
У меня уже есть собственное ядро, контейнер, содержащий все службы и контроллеры (контроллеры уже зарегистрированы как службы). Мои контроллеры расширяют AbstractController из symfony/frameworkbundle. Итак, единственное, что я могу сделать сейчас, это:
Получить службу из контейнера с помощью $this->container->get('service_id'), но если служба в конструкторе будет иметь класс в качестве параметра
public function __constructor(SomeClass $someClass)
то я получаю это исключение:
The "App\V2\Service\TestService" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.
Если я изменю конфигурацию, чтобы сделать все службы общедоступными, то:
Too few arguments to function APP\V2\Service\TestService::__construct(), 0 passed and exactly 1 expected
Я готовлю суть, чтобы лучше понять, о чем я говорю: https://gist.github.com/miedzwin/49bac1cc1d5270d3ba1bfcf700abf864
Может ли кто-нибудь мне немного помочь с реализацией DI с использованием компонентов Symfony (а не фреймворка Symfony)? Достаточно хорошего рабочего примера. Или просто добавьте свои замечания в мою суть, я пытаюсь это исправить.
Кроме того, вы можете упростить свою конфигурацию следующим образом: gist.github.com/TomasVotruba/09af5a9452abaa91b64c15b740d74f2 e /…
@ TomášVotruba Я не регистрировал сервис, он должен регистрироваться автоматически, т.к. autowire: true. Я обновил суть, чтобы вы могли проверить, как выглядит TestService.php.
Хорошо, я внес изменения, как вы сделали в gist (ControllerResolver и ArgumentResolver теперь должны быть общедоступными, иначе я не могу использовать их в классе Framework). Сейчас это выглядит лучше, но теперь у меня есть другие проблемы: 1. Если в конфигурации службы по умолчанию установлен public: true, то службы, которые имеют в конструкторе аргументы скалярного типа (строка, целое число, массив), не могут быть подключены автоматически. Cannot autowire service "APP\V2\Service\API": argument "$facebookUserId" of method "__construct()" has no type-hint, you should configure its value explicitly.
2 Если public: false - Controller "APP\V2\Controller\API\SocialNetworkController::loginAction()" requires that you provide a value for the "$testService" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one. Итак, похоже, служба все еще не введена.
Отличная обратная связь! Вы только что дали мне важные элементы. Я постараюсь дать правильный ответ на вашу ситуацию.
@ TomášVotruba Я создал репо: github.com/miedzwin/legacy-framework Вы можете проверить, как это работает прямо сейчас. Если есть время, конечно. Может быть, ты быстрее найдешь, что я сделал не так. Спасибо.
Хорошо, я в нескольких местах спрашиваю, как с этим справиться, и решение было - собственный преобразователь контроллеров. Любой, кто может проверить, как я это сделал, - проверьте репо из предыдущего сообщения и просмотрите код в теге v0.1.






https://symfony.com/doc/current/service_container.html#fetching-and-using-services
Вам нужно изменить конфигурацию по умолчанию для вашего сервиса, чтобы сделать его общедоступным:
services:
_defaults:
public: true
Но более элегантный способ доступа к сервисам - это внедрить их в действия контроллера:
public function myAction(Request $request, TestService $service)
Судя по вашему вопросу и комментариям, я думаю, что все, что вам нужно сделать, это исправить автоматическую проводку.
В Symfony все просто: автосоединение всех сервисов и параметров, без ручной настройки (если возможно).
Чтобы применить это к вашему примеру, это будет лучшая конфигурация, соответствующая вашим потребностям и Symfony 4:
services:
_defaults:
# pass service dependencies to constructors by default
autowire: true
# add known tags (for commands, event subscribers etc) by default
autoconfigure: true
# to make using tests, bin files and another simpler
public: true
# autowiring of string/array/int parameters to constructors
# this fixes cases like "argument "$facebookUserId" of method "__construct()" has no type-hint, you should configure its value explicitly"
bind:
# $constructorVariableName: %parameter% in config
$facebookUserId: '%facebook_user_id%'
APP\V2\:
resource: '../src/app/V2/*'
exclude: '../src/app/V2/{Script, Trait}'
# symfony services - you still have to setup 3rd paryt services manually
Symfony\Component\DependencyInjection\ParameterBag\ContainerBag:
arguments:
- '@service_container'
# ...
Как выглядит
APP\V2\Service\T estService? Где его зарегистрировать?