Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Автоматические фабрики

Отдельный класс-фабрика для каждого контроллера и сервиса — много однообразного кода. В пакете laminas-servicemanager есть две готовые фабрики, которые сами подставляют зависимости в конструктор. Устанавливать ничего не нужно — пакет уже есть в проекте.

ReflectionBasedAbstractFactory

Эта фабрика читает типы аргументов конструктора и берёт из контейнера сервисы с такими же именами. Удалите файл PostControllerFactory.php из прошлого урока и измените настройки:

// module/Blog/config/module.config.php
// в начале файла:
// use Laminas\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory;
'controllers' => [
    'factories' => [
        Controller\PostController::class => ReflectionBasedAbstractFactory::class,
    ],
],

Конструктор контроллера остался прежним — __construct(private ReadingTime $readingTime). Фабрика увидит тип ReadingTime, найдёт сервис Blog\Service\ReadingTime в контейнере и передаст его. Страница /blog/1 работает как раньше.

Если в конструктор добавить ещё один сервис, настройки менять не придётся.

Что она умеет подставить

Аргумент конструктораЧто будет передано
Тип — класс или интерфейсСервис с таким именем из контейнера
array $configВесь массив настроек приложения
Аргумент со значением по умолчаниюЗначение по умолчанию
Строка или число без значения по умолчаниюОшибка: фабрика не знает, что подставить

ConfigAbstractFactory

Вторая фабрика не изучает класс, а читает список зависимостей из настроек. Список записывают под ключом ConfigAbstractFactory::class:

// module/Blog/config/module.config.php
// в начале файла:
// use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
'controllers' => [
    'factories' => [
        Controller\PostController::class => ConfigAbstractFactory::class,
    ],
],
ConfigAbstractFactory::class => [
    Controller\PostController::class => [
        Service\ReadingTime::class,
    ],
],

В массиве перечислены сервисы в том порядке, в каком их ждёт конструктор. Результат тот же, но зависимости видны прямо в файле настроек.

Что выбрать

СпособПлюсыМинусы
Свой класс-фабрикаЛюбая логика, самая быстраяМного кода
ReflectionBasedAbstractFactoryНичего не нужно писатьЧуть медленнее: класс изучается при каждом создании
ConfigAbstractFactoryЗависимости видны в настройкахСписок нужно обновлять вручную

На протяжении курса контроллеры и простые сервисы регистрируются через ReflectionBasedAbstractFactory. Свою фабрику пишут, когда объекту нужно что-то кроме сервисов: значение из настроек, имя таблицы, путь к файлу.

Генерация фабрик

Для рабочего сервера обычные фабрики можно не писать руками, а сгенерировать. В пакете есть консольная программа:

vendor/bin/generate-factory-for-class "Blog\Controller\PostController" > module/Blog/src/Controller/PostControllerFactory.php

Команда печатает код фабрики, а знак > сохраняет его в файл. Остаётся указать этот класс в разделе controllers.

Частая ошибка

ReflectionBasedAbstractFactory ищет сервис по имени типа. Если класс Blog\Service\ReadingTime не зарегистрирован в service_manager, вы получите исключение ServiceNotFoundException с именем этого класса — хотя ошибка возникнет при создании контроллера. Читайте в сообщении имя сервиса и регистрируйте именно его.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.