Задать вопрос

Можно ли в symfony динамически внедрять зависимости?

Предположим, у нас есть сервис Foo, и он принимает в конструктор BarInterface. И есть 3 сервиса, реализующие этот интерфейс, условно назовем их Bar1, Bar2 и Bar3. Так вот, в зависимости от каких-либо условий (например параметров http-запроса пользователя) нужно внедрить в Foo экземпляр Bar1, Bar2 или Bar3.

Можно ли где-то описать логику выбора сервиса для внедрения?
  • Вопрос задан
  • 379 просмотров
Подписаться 6 Средний Комментировать
Решения вопроса 1
SerafimArts
@SerafimArts
Senior Notepad Reader
По-умолчанию симфонёвый контейнер это не позволяет. Есть 3 варианта развития:
1) Не сопротивляться и не использовать в этом случае контейнер, а использовать, например, фектори (т.е. чтобы контейнер возвращал этот самый фектори, который в зависимости от чего-либо возвращал нужный сервис).
2) Если Symfony 3.x и нужен сервис в контроллерах, то можно использовать Param Resolver: https://symfony.com/doc/current/controller/argumen...
3) Можно написать свой бридж на более мощный контейнер, например Laravel, в этом случае надо в обязательном порядке наследоваться от симфонёвого (чёртова симфонёвая кодогенерация) и зарегистрировать его внутри AppKernel (там есть метод получения класса контейнера).

P.S. А ещё в последних симфонях добавили Service Locator механизм (слайс контейнера), в теории можно придумать что-нибудь с ним.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Решить проблему в лоб, к сожалению, не получится.
Вам нужен промежуточный слой между сервис контейнером и вашим сервисом. В симфони есть механизм для подобных задач: symfony.com/doc/current/service_container/compiler...

Работает это так:

1. Вы декларируете сервисы Bar1, Bar2, Bar3 указывая им определенный тег:
services:
   bundle.service.bar1:
      class: .../Bar1
      arguments:
         ...
      tags:
         - { name: bar }

2. Создаете сервис, например BarProvider, который будет содержать ссылки на сервисы Bar1, Bar2, ... и предоставляющий метод(ы) для их получения.

3. Создаете Compiler, которые достает из сервис-контейнера все сервисы, имеющие тег bar и складывает их в BarProvider (BarProvider должен иметь метод для добавления BarInterface)

4. Инжектите BarProvider в нужный вам сервис и достаете из него требуемый сервис Bar
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы