4

I have a Slim Php (slim4) application to which I added Monolog for logging purposes. I'm adding the logger to the application like this:

$containerBuilder->addDefinitions([
  LoggerInterface::class => function (ContainerInterface $c) {
     $logger = new Logger('appname');
     ...
     return $logger

This works fine for injecting the logger in most of my classes, by just doing:

public function __construct(ContainerInterface $container = null, LoggerInterface $logger)
{
    // I can use $logger here

Now I'd also like to use the logger in the middleware like authentication. I don't see how I can properly do this. I can get this working by adding the logger as a named entry in the container like this:

$containerBuilder->addDefinitions([
  "LoggerInterface" => function (ContainerInterface $c) {

and then passing it to the middleware as a constructor parameter by getting it back from the container:

$middlewares[] = new MyAuthentication(..., $container->get('LoggerInterface'));

But this:

  • a) breaks the injection by classname for the other classes
  • b) is apparently not a best practice

So what is the correct way to get this logger injected in the middleware?

S. Roose
  • 1,398
  • 1
  • 12
  • 27

3 Answers3

3

Without adding the LoggerInterface as a named entry to the container, could you just inject the LoggerInterface class directly to your middleware via $container->get()? I.E. in a routes.php App function:

$container = $app->getContainer();
$app->add(new MiddleWare\MyAuthentication(..., $container->get(LoggerInterface::class)));
Woodrow
  • 2,740
  • 1
  • 14
  • 18
  • Nice, that's exactly what I needed! (although it seems not to be best practice, it looks quite clean to me) – S. Roose Nov 20 '19 at 21:55
0

In short, I do not think you are going to be able to auto-wire the dependencies for the middleware as they need to be constructed before being appended to the router. You would need to explicitly inject the dependency as suggested by @Woodrow, although I would opt for method injection instead of constructor injection for the LoggerInterface as it would adhere to the LoggerAwareInterface.

Alex Barker
  • 4,316
  • 4
  • 28
  • 47
  • Hi, thanks for your reply. How would the method injection work concretely? Does this mean passing the logger as parameter to each call to the class? – S. Roose Nov 20 '19 at 21:54
  • The [LoggerAwareInterface](https://github.com/php-fig/log/blob/master/Psr/Log/LoggerAwareInterface.php) provides a pretty good idea. Just use a NullHandler or NoOpHandler for the classes logger member variable in the constructor. Then the setter method just sets the objects member if desired. You maybe able to use the PHP-DI factory to auto-wire up the constructor for you. – Alex Barker Nov 20 '19 at 22:18
0

You could let the dependency injection container (PHP-DI) resolve and inject all dependencies into your middleware:

LoggerInterface::class => function (ContainerInterface $container) {
    return new Logger('name');
},

Then just register the middleware with the class name:

$app->add(\MiddleWare\MyAuthentication::class);

(You should not inject the container itself into the middleware)

That's all.

odan
  • 4,757
  • 5
  • 20
  • 49