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

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

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

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

new Controller(request, service).action_name

к этому

new Controller(service).action_name(request)

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

Я не понимаю, как это сделать, используя PHP-ди

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

ОБНОВЛЕНИЕ 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#
)
)

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

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

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

ОБНОВЛЕНИЕ 2

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

0

Решение

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

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

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

0

Другие решения

О запросе:

Не указывайте параметр $ 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#limitations

PHP-DI «Определения PHP — псевдонимы» в http://php-di.org/doc/php-definitions.html#aliases

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

0

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

$container->set('DEC\Request', new Request('GET'));
$controller = $container->get('DEC\ApplicationController');
$response = $controller->index();
0
По вопросам рекламы [email protected]