@fasewyby

Как работать с DI-контейнером?

Прошу пояснить как должен работать DI-контейнер. В самом контейнере задаются только примитивные типы данных? А все объектные зависимости решаются с помощью автовайринга через Reflection API?

К примеру, у меня есть контроллер. Он принимает модель и вид. Сам вид принимает шаблоны, это обычные строки с разванием шаблонов, которые нужно подключить. Модель принимает класс соединения с БД, а БД принимает массив с настройками подключения. Есть еще класс пагинации, он тоже должен быть в контроллере и его конструктор принимает три параметра типа int.

В контейнер нужно названия всех шаблонов и массив с настройками подключения к БД разместить? Как быть с пагинацией, три int аргумента выщитываются в контроллере и вызывается класс.
  • Вопрос задан
  • 174 просмотра
Пригласить эксперта
Ответы на вопрос 2
Vamp
@Vamp
В самом контейнере задаются только примитивные типы данных?

В DI контейнере обычно регистрируют объекты, общие для всего приложения, а не для конкретного запроса. Например, коннект к базе, роутер, кеш. Автовайринг примитивных типов в DI - прямая дорога к путанице и сложным для обнаружения ошибкам.

А все объектные зависимости решаются с помощью автовайринга через Reflection API?

Можно и так. А можно руками связи выставить. Или аннотациями. Разные способы бывают, смотря какие поддерживаются выбранной вами реализацией DI.

К примеру, у меня есть контроллер.

В случае с контроллерами обычно делают front controller, на который сваливаются абсолютно все запросы, а дальше он сам определяет какой из контроллеров нужно создать и передаёт запрос на обработку ему.

Сам вид принимает шаблоны, это обычные строки с разванием шаблонов, которые нужно подключить.

Если строки с названием шаблонов фиксированы, хранятся в конфиге/базе и одинаковы для всех страниц и всех пользователей, то можно шаблон и в DI зарегистрировать. В противном случае лучше создавать его во фронт контроллере. Либо зарегистрировать в DI фабрику шаблонов, которая будет создавать объекты вью в зависимости от переданных параметров. Аналогично и с моделью.

Модель принимает класс соединения с БД, а БД принимает массив с настройками подключения.

В контейнере можно зарегистрировать объект Settings, в котором хранятся данные для подключения к базе и прочие глобальные настройки, а затем инжектить его в класс для работы с базой. Ещё контейнер может сам выступать хранилищем настроек и инжектить их (в том числе примитивные). Так сделано в DI компоненте Symfony.

Есть еще класс пагинации, он тоже должен быть в контроллере и его конструктор принимает три параметра типа int.

Опять же, если эти три параметра не зависят от запроса, то можно зарегистрировать пагинатор в DI. Если зависят, то можно из конструктора перенести эти параметры в метод и вызывать его в контроллере. Например: $page = $this->paginator->calulatePage($one, $two, $three)
Ответ написан
dmitriylanets
@dmitriylanets
веб-разработчик
DI-контейнер это один из основных инструментов который должен быть в вашем приложении. Одно из правил SOLID это инверсия зависимостей, которая решается внедрением DI-контейнера с Автовайрингом для удобства.
Уже много лет использую https://container.thephpleague.com/ и работа с зависимостями перестала был проблемой.
Теперь по вашей задаче:
У вас есть контроллер HomeController который должен иметь две зависимости, например UserRepository и Pagination.
Какие зависимости должен иметь контроллер через абстракцию ? UserRepository потому что репозиторий это как правило класс который реализует слой хранения данных, который в свою очередь может меняться так как относится к слою инфраструктуры, поэтому у вас есть UserRepositoryInterface. Но вот к чему относится Pagination ? - к слою представления где у вас и находится контроллер, по сути использовать абстракции для него нет смысла, также как и для Response и Request и тд.
Поэтому ваш код будет выглядеть так:
class HomeCotroller{

   public function __construct(protected Request $request, protected UserRepositoryInterface $userRepository)

  }
  public function index(): Response { 

    $params = $this->request->getAll()
    //тут логика получения переменных

    $pagination = new Pagination($param1, $param2);
    $pagiationHtml = $pagitation->render();

    //тут логика построения html через шаблонизатор

    return new Response($html);
 }


По поводу конфига с настройками: в DI контейнере есть возможность использовать singlitone объекты , создаете адаптер подключения к базе MysqlAdapter который в конструкторе берет настройки из вашего .env файла и создает соединение 1 раз. И дальше можете адаптер использовать его через инфекцию в ваши репозитории.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы