FreeLightman
FreeLightman

Reputation: 2294

How to make LoggerInterface service public in symfony 4

I want to have Psr\Log\LoggerInterface public in symfony to be able to get it directly from the container with $container->get('Psr\Log\LoggerInterface').

I tried the following services.yaml:

_defaults:
 public: true

Psr\Log\LoggerInterface:
 public: true

Psr\Log\LoggerInterface:
 alias: 'logger'
 public: true

Psr\Log\LoggerInterface:
 alias: 'monolog.logger'
 public: true

I can not get a clue why it is so hard to rewrite a service.

Upvotes: 3

Views: 3112

Answers (3)

Not sure if it helps in your case, but in my case I needed a public version of the monolog.logger service in the tests to mock it. So I created a public alias of it:

test.monolog.logger:
  alias: 'Psr\Log\LoggerInterface'
  public: true

Now when I inject this service using DI with the LoggerInterface class I get this service, which I mocked in my test with:

$loggerMock = $this->createMock(LoggerInterface::class);
static::getContainer()->set("test.monolog.logger", $loggerMock);

Upvotes: 0

Cerad
Cerad

Reputation: 48865

As previously noted, directly accessing services from the container is discouraged. But I was a bit curious to see how to make a private service public. I tried what was listed in the question and confirmed it did not work.

This may not be the simplest approach but a compiler pass will do the trick:

# src/Kernel.php
# Make the kernel a compiler pass
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class Kernel extends BaseKernel implements CompilerPassInterface
...
public function process(ContainerBuilder $container)
{
    $logger = $container->getAlias(LoggerInterface::class);
    $logger->setPublic(true);
}

# And that should do the trick, you can confirm with
bin/console debug:container Psr\Log\LoggerInterface

Be aware that only services which have the complete container injected will be able to take advantage of this. Controllers which extend from AbstractController only have access to a small number of services.

Take a look at Service Subscribers if you need the logger in your controller or if you just want a "better" way of doing this.

Upvotes: 4

Yarimadam
Yarimadam

Reputation: 1183

Using $container->get() is a bad practise. It violates many good software design principles.

You should use constructor injection instead.

class Foo
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

Upvotes: -4

Related Questions