Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

symfony without framework Controller use $logger Fatal error #48739

Unanswered
xptela asked this question in Q&A
Discussion options

https://symfony.com/doc/current/index.html
The documentation is all based on using the framework and I have very limited access to help.
Now I need a little help.
I've followed "Create your own PHP Framework" and implemented the basic web framework, but when I try to get a logger service from the controller, it always throws a runtime exception:

Fatal error: Uncaught RuntimeException: Controller "App\Controller\LuckyController::number()" requires that you provide a value for the "$logger" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.

Controller part of the code:

class LuckyController
{
 #[Route('/lucky')]
 public function number(Request $request, Logger $logger): Response
 {
 $logger->critical('Test logger');
 return new Response($request->headers->get('user_agent'));
 }
}
You must be logged in to vote

Replies: 1 comment 2 replies

Comment options

So now you start to get into the fun stuff. Take a step back and ask yourself how the arguments actually get injected into the number action method. It's not normal dependency injection. $request for example is not even a service and of course a controller can have multiple actions each taking a different set of arguments. The answer is that Symfony has an ArgumentResolver class which takes care of figuring out what to inject where. If you take a look at where you configured your framework class you will see that you actually injected an argument_resolver service using the Symfony\Component\HttpKernel\Controller\ArgumentResolver class.

There are actually multiple resolvers for different types of arguments. By default the ArgumentResolver class uses:

 public static function getDefaultArgumentValueResolvers(): iterable
 {
 return [
 new RequestAttributeValueResolver(),
 new RequestValueResolver(),
 new SessionValueResolver(),
 new DefaultValueResolver(),
 new VariadicValueResolver(),
 ];
 }

So, for example, the RequestValueResolver checks for any controller action arguments of type Request and, if it finds one, injects $request.

What you need to do is to add the ServiceValueResolver to the list of resolvers. The ArgumentResolver class is final so you can't just extend it but fortunately you inject an array of resolvers as the second constructor argument instead of using the default list. Which means you have to define services for each of the default resolvers and then define a service for the ServiceValueResolver. Gather them all up in an array and inject them.

At which point, assuming you have also defined a Logger service, your logger should be injected.

Have fun

You must be logged in to vote
2 replies
Comment options

First of all, thank you for your reply, I did the following.

 $containerBuilder->register('logger', Logger::class);
 $containerBuilder->register('service_value_resolver', ServiceValueResolver::class);
 $containerBuilder->register('argument_resolver', ArgumentResolver::class)
 ->setArguments([null, [new Reference('service_value_resolver')]]);

There is a constructor in ServiceValueResolver::class where he asks to pass in a Container, I didn't know how to get the Container instead, so I didn't pass in the Container via setArguments.

The result is also the same as I expected, he does not work properly.

Too few arguments to function Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver::__construct(), 0 passed and exactly 1 expected in vendor\symfony\http-kernel\Controller\ArgumentResolver\ServiceValueResolver.php:30

Comment options

The container itself is a service with an id of service_container. The container actually creates this service automatically. Not sure where it is documented except maybe in the code.

Looks like you are making progress. Don't forget to inject the rest of the resolvers as well otherwise your existing code won't work. Especially the request resolver. And I'm pretty sure your logger service is going to need a bit more work as well but one step at a time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
2 participants

AltStyle によって変換されたページ (->オリジナル) /