В контексте 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
Для решения, описанного в этом обновлении, пожалуйста, посмотрите на мой собственный ответ на вопрос
Не очень понятно, что вы пробовали, но это должно вызвать метод действия и передать ему запрос (и разрешить контроллер со всеми его зависимостями):
$container->call([MyController::class, 'action_name'], [
'request' => $request,
]);
Узнайте больше о call()
Вот: http://php-di.org/doc/container.html#call
О запросе:
Не указывайте параметр $ 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
Надеюсь, это помогло.
Мне удалось сделать это, установив мой запрос в контейнере, прежде чем запрашивать контроллер:
$container->set('DEC\Request', new Request('GET'));
$controller = $container->get('DEC\ApplicationController');
$response = $controller->index();