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

Slim Framework 3 - How to inject $logger to route controller

我正在使用 Slim Framework 3。我想将 dependencies.php 中定义的 $logger 注入路由器控制器 class。下面是我的做法,有没有更好的方法?

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 文档中,使用 Route Controller 的正确方法应该是:

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

但是,当我选择以这种更 "elegant" 的方式编写我的 Route Controller 代码时,如何将 $logger 注入到 AccountController 中?

根据 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 在他的回答中解释的那样,通过将 controllers 注入应用程序容器,您可以获得更好的模块化,从而更容易测试代码(如果您使用单元测试),而不是而不是将 容器 注入每个控制器。

看看他的example Slim application. If you look at, for example AuthorController,你可以看到如何通过这个设计控制器类不再依赖于提供所有服务的神奇容器。相反,您在构造函数中明确说明每个控制器需要哪些 服务。这意味着您可以更轻松地模拟测试场景中的各个依赖项。

为了使您的控制器更易于测试,您应该通过构造函数将记录器注入控制器。

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

注意,如果你将format route callable设为'class name' colon 'method name'的字符串,那么Slim 3会在从DI容器中提取控制器class后为你调用该方法。如果 class 名称不是容器的注册键,那么它将实例化它并将容器传递给构造函数。