4

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

路由.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 呢?

4

2 回答 2

6

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

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 容器中提取控制器类后为您调用该方法。如果类名不是容器的注册键,那么它将实例化它并将容器传递给构造函数。

于 2016-04-09T13:51:40.037 回答
4

根据容器解析文档,您应该能够通过控制器内部的容器访问您的记录器:

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

看看他的示例 Slim 应用程序。例如AuthorController,如果您看一下,您会看到这种设计的控制器类如何不再依赖于提供所有服务的神奇容器。相反,您在构造函数中明确声明每个控制器需要哪些服务。这意味着您可以更轻松地模拟测试场景中的各个依赖项。

于 2016-04-08T21:23:17.427 回答