Инъекция частичной зависимости

В контексте MVC у меня есть контроллер, который зависит от службы, а служба, в свою очередь, зависит от источника данных (в конкретном случае - клиента для извлечения данных из стороннего API).

Чтобы создать экземпляр службы с фиктивным источником данных при тестировании, конструктор службы ожидает источник данных. То же самое относится и к контроллеру, конструктор которого ожидает сервис.

При создании контроллера я также хочу передать ему объект запроса, потому что я бы предпочел это

new Controller(request, service).action_name

к этому

new Controller(service).action_name(request)

Достижение этого без использования какого-либо контейнера для инъекций зависимости является тривиальным.

Я не понимаю, как это сделать с помощью php-di

Моя цель состоит в том, чтобы сервис внедрялся в контроллер контейнером при передаче объекта запроса самому контроллеру.

ОБНОВЛЕНИЕ 1

Это мой ApplicationController

namespace DEC;


class ApplicationController {

    private $service;
    private $request;

    public function __construct(Foo $service, $request) {
        $this->service= $service;
        $this->request = $request;
    }


    public function index() {
        $out = $this->service->foo();
        $out .= $this->request->method();
        return $out;
    }

}

Фу следует

namespace DEC;

class Foo {

    public function __construct() {
    }

    public function foo() {
        return "FOO";
    }
}

Это мой запрос

namespace DEC;

class Foo {

    public function __construct() {
    }

    public function foo() {
        return "FOO";
    }
}

И это моя попытка заставить ДИ работать так, как мне хотелось бы:

$container = ContainerBuilder::buildDevContainer();
$response = $container->call([ApplicationController::class, 'index'], [
            'request' => new Request('GET')
]);
echo $response;

Это ошибка, которую я получаю:

Entry "DEC\ApplicationController" cannot be resolved: Parameter $request of __construct() has no value defined or guessable
Full definition:
Object (
    class = DEC\ApplicationController
    scope = singleton
    lazy = false
    __construct(
        $service = get(DEC\Foo)
        $request = #UNDEFINED#
    )
)

NB: ошибка остается прежней, если я напечатал подсказку для запроса и / или переключил порядок параметров в конструкторе

Глядя на ошибку, я делаю вывод, что решение::call(), предложенное Мэтью Наполи, работает, если я создаю экземпляр контроллера только с помощью службы и передаю запрос в качестве параметра для метода действия.

Значит ли это, что я не могу полагаться на контейнер для "частичной" инъекции?

ОБНОВЛЕНИЕ 2

Для решения, описанного в этом обновлении, пожалуйста, посмотрите на мой собственный ответ на вопрос

3 ответа

Решение

Мне удалось сделать это, установив мой запрос в контейнере, прежде чем запрашивать контроллер:

$container->set('DEC\Request', new Request('GET'));
$controller = $container->get('DEC\ApplicationController');
$response = $controller->index();

Не очень понятно, что вы пробовали, но это должно вызвать метод действия и передать ему запрос (и разрешить контроллер со всеми его зависимостями):

$container->call([MyController::class, 'action_name'], [
    'request' => $request,
]);

Узнайте больше о call() здесь: http://php-di.org/doc/container.html

О запросе:

Не вводите подсказку параметра $request:

public function __construct($request, /*...*/) {}

Или введите подсказку RequestInterface для этого:

public function __construct(RequestInterface $request, /*...*/) {}

В обоих случаях DIC не сможет автоматически создать экземпляр запроса. Затем вы можете сделать это самостоятельно.

О Сервисе:

Тип-намек на это с бетоном, типа "Сервис". Затем экземпляр службы будет автоматически создан DIC со всеми его зависимостями (data_source).

Или введите подсказку с помощью интерфейса, например "ServiceInterface", и установите для него запись в DIC, используя псевдоним в определениях PHP. Что-то вроде этого:

return [
    'ServiceInterface' => DI\get('<NAMESPACE-TO>\Service'),
];

Увидеть:

PHP-DI "Ограничения" на http://php-di.org/doc/autowiring.html

PHP-DI "Определения PHP - псевдонимы" по адресу http://php-di.org/doc/php-definitions.html

Надеюсь, это помогло.

Другие вопросы по тегам