简体   繁体   English

Slim Framework 3 - 如何将$ logger注入路由控制器

[英]Slim Framework 3 - How to inject $logger to route controller

I am using Slim Framework 3. I want to inject $logger defined in dependencies.php into a Router Controller class. 我正在使用Slim Framework 3.我想将dependencies.php定义的$logger注入到Router Controller类中。 Below is what I do, is there a better way? 以下是我的工作,有更好的方法吗?

routes.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');
    }
}

In Slim Framework 3 documentation, the proper way of using a Route Controller should be: 在Slim Framework 3文档中,使用路径控制器的正确方法应该是:

$app->get('/test', 'AccountController:test');

But how do I inject $logger into AccountController when I choose to code my Route Controller in this more "elegant" way? 但是当我选择以更“优雅”的方式编写路径控制器代码时,如何将$logger注入AccountController?

According to the container resolution docs , you should be able to access your logger through the container, inside your controller: 根据容器解析文档 ,您应该能够通过控制器内的容器访问您的记录器:

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');
    }
}

When you call $app->get('/test', 'AccountController:test'); 当你调用$app->get('/test', 'AccountController:test'); , Slim should automatically pass the container into AccountController 's constructor. ,Slim应该自动将容器传递给AccountController的构造函数。

That being said , this is more of a convenience feature than an example of great design. 话虽这么说 ,这是一个方便的功能,而不是一个伟大的设计的例子。 As Rob Allen explains in his answer, you can achieve better modularity, and thus more easily tested code (if you're using unit tests), by injecting the controllers into the application container, rather than injecting the container into each controller. 正如Rob Allen在他的回答中所解释的那样,通过将控制器注入应用程序容器,而不是将容器注入每个控制器,您可以实现更好的模块化,从而更容易测试代码(如果您使用单元测试)。

Take a look at his example Slim application . 看看他的示例Slim应用程序 If you look at, for example AuthorController , you can see how with this design controller classes no longer depend on the magical container providing all the services. 如果您查看,例如AuthorController ,您可以看到这个设计控制器类如何不再依赖于提供所有服务的神奇容器。 Instead, you explicitly state which services each controller will need in the constructor. 相反,您明确说明构造函数中每个控制器将需要哪些服务。 This means you can more easily mock the individual dependencies in testing scenarios. 这意味着您可以更轻松地模拟测试场景中的各个依赖项。

In terms of making your controller easier to test, you should inject the logger into the controller via the constructor. 在使控制器更易于测试方面,您应该通过构造函数将记录器注入控制器。

AccountController looks like this: 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']);
    }
}

Set up in index.php is something like: 在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');

Note that if you make the format route callable be a string of 'class name' colon 'method name' , then Slim 3 will call the method for you after extracting the controller class from the DI container. 请注意,如果您将格式化路由可调用为'class name' colon 'method name'的字符串,则Slim 3将在从DI容器中提取控制器类后为您调用该方法。 If the class name is not a registered key with the container, then it will instantiate it and pass the container to the constructor. 如果类名不是容器的注册密钥,那么它将实例化它并将容器传递给构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM