Awesome! Down in parse(), if the source contains the word bacon... then of course,
we need to know about that! Use $this->logger->info('They are talking about bacon again!'):

37 lines src/Service/MarkdownHelper.php

... lines 1 - 8

classMarkdownHelper

{

... lines 11 - 21

publicfunctionparse(string $source): string

{

if (stripos($source, 'bacon') !== false) {

$this->logger->info('They are talking about bacon again!');

}

... lines 27 - 34

}

}

Ok, try it! This article does talk about bacon. Refresh! To see if it logged,
open the profiler and go to "Logs". Yes! Here is our message. I love autowiring.

The Other Loggers

Go back to your terminal. The debug:autowiring output say that LoggerInterface
is an alias to monolog.logger. That is the id of the service that's being passed
to us. Fun fact: you can get a bit more info about a service by running:

./bin/console debug:container monolog.logger

This is cool - but you could also learn a lot by dumping it. Anyways, we normally
use debug:container to list all of the services in the container. But we can
also get a filtered list. Let's find all services that contain the word "log":

./bin/console debug:container --show-private log

There are about 6 services that I'm really interested in: these monolog.logger.
something services.

Logging Channels

Here's what's going on. Symfony uses a library called Monolog for logging. And
Monolog has a feature called channels, which are kind of like categories.
Instead of having just one logger, you can have many loggers. Each has a unique
name - called a channel - and each can do totally different things with their
logs - like write them to different log files.

In the profiler, it even shows the channel. Apparently, the main logger uses a
channel called app. But other parts of Symfony are using other channels, like
request or event. If you look in config/packages/dev/monolog.yaml, you can
see different behavior based on the channel:

20 lines config/packages/dev/monolog.yaml

monolog:

handlers:

main:

type:stream

path:"%kernel.logs_dir%/%kernel.environment%.log"

level:debug

channels:["!event"]

# uncomment to get logging in your browser

# you may have to allow bigger header sizes in your Web server configuration

#firephp:

# type: firephp

# level: info

#chromephp:

# type: chromephp

# level: info

console:

type:console

process_psr_3_messages:false

channels:["!event","!doctrine","!console"]

For example, most logs are saved to a dev.log file. But, thanks to this
channels: ["!event"] config, which means "not event", anything logged
to the "event" logger is not saved to this file.

This is a really cool feature. But mostly... I'm telling you about this because
it's a great example of a new problem: how could we access one of these other
Logger objects? I mean, when we use the LoggerInterface type-hint, it gives us
the main logger. But what if we need a different Logger, like the "event" channel
logger?

Creating a new Logger Channel

Actually, let's create our own new channel called markdown. I want anything
in this channel to log to a different file.

To do this, inside config/packages, create a file: monolog.yaml. Monolog
is interesting: it doesn't normally have a main configuration file: it only has
environment-specific config files for dev and prod. That makes sense: we log
things in completely different ways based on the environment.

But we're going to add some config that will create a new channel, and we want
that to exist in all environments. Add monolog, then channels set to [markdown]:

3 lines config/packages/monolog.yaml

monolog:

channels:['markdown']

That's it!

Because of a Symfony bug - which, is now fixed (woo!) - but won't be available
until the next version - Symfony 4.0.5 - we need to clear the cache manually when
adding a new config file:

./bin/console cache:clear

As soon as that finishes, run debug:container again:

./bin/console debug:container log

Yea! Suddenly we have a new logger service - monolog.logger.markdown! So cool.

Go back to the "dev" monolog.yaml file. Copy the first log handler, paste, and
give it a key called markdown_logging - that's just a meaningless internal name.
Change the path to markdown.log and only log the markdown channel:

25 lines config/packages/dev/monolog.yaml

monolog:

handlers:

... lines 3 - 7

markdown_logging:

type:stream

path:"%kernel.logs_dir%/markdown.log"

level:debug

channels:["markdown"]

... lines 13 - 25

Ok! If you go to your browser now and refresh... it does work. But if you check
the logs, we are - of course - still logging to the app channel Logger. Yep,
there's no markdown.log file yet.

Fetching a Non-Standard Service

So how can we tell Symfony to not pass us the "main" logger, but instead to pass
us the monolog.logger.markdown service? This is our first case where autowiring
doesn't work.

That's no problem: when autowiring doesn't do what you want, just... correct it!
Open config/services.yaml. Ignore all of the configuration on top for now. But
notice that we're under a key called services. Yep, this is where we configure
how our services work. At the bottom, add App\Service\MarkdownHelper, then
below it, arguments:

32 lines config/services.yaml

... lines 1 - 4

services:

... lines 6 - 25

App\Service\MarkdownHelper:

arguments:

... lines 28 - 32

The argument we want to configure is called $logger. Use that here: $logger.
We are telling the container what value to pass to that argument. Use the service
id: monolog.logger.markdown. Paste!

Ah! It's totally legal to set an argument to a string value. But we don't want
to pass the stringmonolog.logger.markdown! We want to pass the service
with this id!

To do that, use a special Symfony syntax: add an @ symbol:

32 lines config/services.yaml

... lines 1 - 4

services:

... lines 6 - 25

App\Service\MarkdownHelper:

arguments:

$logger:'@monolog.logger.markdown'

... lines 29 - 32

This tells Symfony not to pass us that string, but to pass us the service with that id.

Try it again! It works! Check out the var/log directory... boom! We have a markdown.log
file!

Next, I'll show you an even cooler way to configure this. And we'll learn more
about what all this config in services.yaml does.

Leave a comment!

2018-04-25Diego Aguiar

Hey @elbarto

Injecting the "EntityManager" into your services is totally ok. You can do it by type hinting the interface "EntityManagerInterface"

> Dependency Injection through the constructor doesn't seem to work

Can you tell me what error do you see?

Cheers!

2018-04-25elbarto

Would you say it's a good solution to inject ManagerRegistry into the service's constructor in order to getConnection() and getRepository() ?

2018-04-25elbarto

Hi there !I wanted to know : how would you do when you need to use the entityManager inside your own service ?Dependency Injection through the constructor doesn't seem to work (typehints issues for example). What whould be the best solution in order to be able to call findAll() on an entity in my service ?