Правильный способ использования диспетчера служб в Zend3

Я читал документацию Zend 3 по Service Manager и столкнулся с этой проблемой.

В документации говорится, что если у нас есть какой-то DI в нашем контроллере, мы должны обновить файл module.config.php и добавить ключ контроллера и вызвать контроллер не с InvokableFactory::class, а с пользовательским фабричным классом и добавить еще один ключ service_manager, который содержит массив классов, которые использует мой первый контроллер.

Хорошо, так что я делаю это:

модуль.config.php

'service_manager' => [
        'factories' => [
            Controller\Controller2::class => Factory\Controller2Factory::class,
            Controller\Controller3::class => Factory\Controller3Factory::class,
        ],
    ],
'controllers' => [
        'factories' => [
            Controller\Controller1::class => Factory\Controller1Factory::class
        ],
    ]

Controller1Factory.php

class Controller1Factory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        return new Controller1(
            $container->get(Controller2::class),
            $container->get(Controller3::class),
        );
    }
}

Но теперь у меня ошибка, что Controller2 и Controller3 также имеют DI в своих конструкторах, поэтому я создаю новые пользовательские фабрики и так далее, и так далее... пока не доберусь до своих моделей.

И у моделей также есть зависимость, которая вводится в их контроллер, который является нативным \Zend\Db\TableGateway\TableGatewayInterface zend, и теперь мне нужно снова отредактировать файл conf и добавить TableGatewayInterface.

И это неправильно. Я никогда не должен быть вынужден внедрять родные классы и сервисы Zend таким образом.

Так что я делаю неправильно?


person madeye    schedule 22.08.2016    source источник
comment
Не понятно в чем дело. Вы говорите, что ваши модели требуют внедрения других классов в их конструкторы, но при этом вы не хотите, чтобы вас заставляли внедрять классы с помощью диспетчера служб. (Если да, то какой метод вы бы предпочли?)   -  person Tim Fountain    schedule 23.08.2016
comment
@TimFountain Ну, моей модели требуется экземпляр \Zend\Db\TableGateway\TableGatewayInterface, и я добавляю его в конструктор моей модели. Но поскольку это интерфейс Zend, я не уверен, что вставка нового значения в диспетчере служб для этого конкретного интерфейса хороша.   -  person madeye    schedule 23.08.2016
comment
Вы не должны внедрять контроллеры в контроллеры. Создайте отдельный класс фабрики для каждого контроллера, который имеет зависимости от модели, и внедрите модели, которые нужны каждому.   -  person dualmon    schedule 26.08.2016
comment
Я перечитал ваш пост, и хотя я могу сказать вам, что вам не следует этого делать, я пытаюсь понять, чего вы на самом деле хотите достичь. Можешь уточнить свою цель?   -  person dualmon    schedule 26.08.2016


Ответы (1)


Если ваш контроллер не имеет зависимости, лучше всего объявить его в module.config.php, как вы это сделали.

Но если у него есть зависимости, лучше сделать это в Module.php. Сначала вы объявляете свои службы, затем контроллер (не забудьте удалить его из module.config.php), вводя в него службы, от которых он зависит:

public function getServiceConfig()
{
    return [
        'factories' => [
            Model\MyObjectTable::class => function($container) {
                $tableGateway = $container->get(Model\MyObjectTableGateway::class);
                return new Model\MyObjectTable($tableGateway);
            },
            Model\MyObjectTableGateway::class => function($container) {
                $dbAdapter = $container->get(AdapterInterface::class);
                $resultSetPrototype = new ResultSet();
                $resultSetPrototype->setArrayObjectPrototype(new Model\User());
                return new TableGateway('myObject', $dbAdapter, null, $resultSetPrototype);
            },
        ]
    ];
}

public function getControllerConfig()
{
    return [
        'factories' => [
            Controller\MyObjectController::class => function($container) {
                return new Controller\MyObjectController(
                    $container->get(Model\MyObjectTable::class)
                );
            },
        ]
    ];
}

И в вашем контроллере:

private $table;

public function __construct(MyObjectTable $table)
{
    $this->table = $table ;
}

Это описано в Эта обучающая страница ZF3 и последующие.

person Al Foиce ѫ    schedule 25.08.2016
comment
Использование замыкания для фабрики не является хорошей идеей. Код операции не может быть кэширован, а объединенный массив конфигурации не может быть кэширован. Для производственного использования вы всегда должны создавать конкретные фабрики, а затем ссылаться на них в разделе фабрик конфигурации вашего модуля. - person dualmon; 26.08.2016
comment
@dualmon Вот как Zend реализует это в учебнике по альбому. Но в углубленном туториэле они делают так, как вы говорите. Я тоже изучаю ZF3, и ваш комментарий натолкнул меня на мысль переписать свое приложение с конкретными фабриками. Спасибо. - person Al Foиce ѫ; 26.08.2016
comment
Может быть, также обновите свой ответ, как только вы это сделаете? Тогда я мог бы проголосовать за это. - person dualmon; 26.08.2016