我正在使用Slim Framework 3.我想将$logger
中定义的dependencies.php
注入路由器控制器类。以下是我的工作,有更好的方法吗?
routes.php文件
$app->get('/test', function($request, $response, $args){
$controller = new AccountController($this->get('logger'));
return $controller->test($request, $response, $args);
});
AccountController
class AccountController{
private $logger;
function __construct($logger){
$this->logger = $logger;
}
public function test($request, $response, $args){
$this->logger->info('i am inside controller');
return $response->withHeader('Content-Type', 'application/json')->write('test');
}
}
在Slim Framework 3文档中,使用路径控制器的正确方法应该是:
$app->get('/test', 'AccountController:test');
但是当我选择以更“优雅”的方式编写路径控制器代码时,如何将$logger
注入AccountController?
答案 0 :(得分:4)
根据container resolution docs,您应该能够通过控制器内的容器访问记录器:
AccountController
class AccountController
{
protected $ci;
//Constructor
public function __construct(ContainerInterface $ci)
{
$this->ci = $ci;
}
public function test($request, $response, $args)
{
$this->ci->get('logger')->info('i am inside controller');
return $response->withHeader('Content-Type', 'application/json')->write('test');
}
}
当您致电$app->get('/test', 'AccountController:test');
时,Slim会自动将容器传递给AccountController
的构造函数。
就是说,这是一个方便的功能,而不是一个伟大的设计的例子。正如Rob Allen在他的回答中解释的那样,您可以通过将控制器注入应用程序容器而不是通过将控制器注入到应用程序容器中来实现更好的模块化,从而更容易地测试代码(如果您正在使用单元测试)将容器注入每个控制器。
看看他的example Slim application。如果您查看,例如AuthorController
,您可以看到这个设计控制器类如何不再依赖于提供所有服务的神奇容器。相反,您明确声明每个控制器在构造函数中需要哪些服务。这意味着您可以更轻松地模拟测试场景中的各个依赖项。
答案 1 :(得分:4)
在使控制器更易于测试方面,您应该通过构造函数将记录器注入控制器。
AccountController看起来像这样:
class AccountController
{
protected $logger;
public function __construct($logger) {
$this->logger = $logger;
}
public function test($request, $response, $args){
$this->logger->info('i am inside controller');
return $response->withJson(['foo' => 'bar']);
}
}
在index.php中设置如下:
$container = $app->getContainer();
$container[Logger::class] = function ($c) {
$logger = new \Monolog\Logger('logger');
return $logger;
};
$container[AccountController::class] = function ($c) {
$logger = $c->get(Logger::class);
return new AccountController($logger);
};
$app->get('/test', 'AccountController:test');
请注意,如果您将格式route callable设为'class name' colon 'method name'
字符串,则Slim 3将在从DI容器中提取控制器类后为您调用该方法。如果类名不是容器的注册密钥,那么它将实例化它并将容器传递给构造函数。