【问题标题】:Slim Framework 3 - How to inject $logger to route controllerSlim Framework 3 - 如何将 $logger 注入路由控制器
【发布时间】:2016-04-08 15:51:14
【问题描述】:

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

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?

【问题讨论】:

    标签: php dependency-injection slim slim-3


    【解决方案1】:

    为了让你的控制器更容易测试,你应该通过构造函数将记录器注入到控制器中。

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

    【讨论】:

    • 您好,谢谢您的回答。如果我有 10 个控制器需要使用记录器会怎样?
    • 我创建了 10 个工厂,因为这些控制器通常具有其他依赖项,例如服务类或数据库映射器。
    【解决方案2】:

    根据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,您会看到这种设计的控制器类如何不再依赖于提供所有服务的神奇容器。相反,您在构造函数中明确声明每个控制器需要 哪些 服务。这意味着您可以更轻松地模拟测试场景中的各个依赖项。

    【讨论】:

    • 谢谢!我怎么能错过那条信息!我通过以下方式获得了容器:function __construct(Slim\Container $ci)
    • 这不是将记录器注入控制器的正确方法。因为在这个例子中,你注入了容器本身。这不是正确的方法。我认为您可以查看 Rob 的答案。 stackoverflow.com/a/36517681/721600
    • @hkulekci 是的,我在其余的回答中提到了这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多