-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DX] Improve exception message when AbstractController::getParameter fails #27443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -64,7 +65,9 @@ public function setContainer(ContainerInterface $container) | |||
protected function getParameter(string $name) | |||
{ | |||
if (!$this->container->has('parameter_bag')) { | |||
throw new \LogicException('The "parameter_bag" service is not available. Try running "composer require dependency-injection:^4.1"'); | |||
throw new ServiceNotFoundException('parameter_bag', null, null, array(), | |||
'The "parameter_bag" service could not be located. Ensure that symfony/dependency-injection 4.1.0 or higher '. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be great to decide ourselves instead of this "and" (line below) in the message (a class_exists check and we can know for sure which alternative is the correct one)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any ideas on a class to reliably test that was introduced in 4.1 and will not disappear until "infinity", so not internal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ContainerBagInterface :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
throw new \LogicException('The "parameter_bag" service is not available. Try running "composer require dependency-injection:^4.1"'); | ||
$message = 'The "parameter_bag" service could not be located. '; | ||
if (!interface_exists(ContainerBagInterface::class)) { | ||
$message .= 'Upgrade symfony/dependency-injection to at least 4.1.0 to have it injected automatically.'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggesting to install/upgrade symfony/dependency-injection does not seem relevant as framework-bundle requires it ^4.1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lol, hadn't bothered to doublecheck that because it was the original message and I assumed it to have a reason.
throw new \LogicException('The "parameter_bag" service is not available. Try running "composer require dependency-injection:^4.1"'); | ||
throw new ServiceNotFoundException('parameter_bag', null, null, array(), | ||
'The "parameter_bag" service could not be located. Ensure that the controller is either set '. | ||
'to be autoconfigured or wired manually to inject it.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[...] to be autoconfigured or has the "container.service_subscriber" tag.
?
should be on one single long line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sprintf('The "%s::getParameter()" method is missing a parameter bag to work properly. Did you forget to register your controller as a service subscriber? This can be fixed e.g. by using autoconfiguration or by manually wiring a "parameter_bag" in the service locator passed to the controller.', get_class($this))
(the name of the parameter is of no importance IMHO, but the controller class IS.)
Would you agree making this error message more verbose to give more context? Original:
Proposal: sprintf('The "getParameter()" method of the controller can\'t get the value of
the "%s" parameter because the "parameter_bag" service could not be located.
Either enable autowiring for the controller or inject the "parameter_bag"
service manually in the controller.', $name); My concern with the current message is that the user wrote |
You’re right - I missed that. I like your message more :) |
@javiereguiluz that suggestion is wrong on 2 counts: first off autowiring won't fix it, it needs autoconfigure. Secondly injecting In practice autoconfigure is the only viable solution to the problem. Realizing that makes you second guess whether this generic feature was a good idea to begin with even though autoconfigure+autowire is now recommended config - it's still not required. edit: out of the box thinking - shouldn't we just rock hard fail somewhere at compile-time if an AbstractController is used but doesn't get its ServiceLocator injected in any way? I suspect the missing |
that's still the case, autoconfiguration+autowiring is not the only way to define a service locator for a service subscriber. Using the Of course in practice, esp. for AbstractController, it's still the most common way to configure them, so that the message is OK mentioning these imho.
what would be the criteria? from the inside of the class, all service locators look the same :) |
Which makes it "unfeasible for end-user developers" like I said and only realistic for those that do not really require better DX in error messages like that in the first place.
There's multiple things we could do actually. Reviewing the default subscriptions quickly we have 5 that could (should?) lose the optional as they're direct dependencies of FrameworkBundle:
This automatically makes them candidates for a late-phase compiler pass to check integrity - any service that derives from AbstractController can have its It's the difference between getting "You've screwed up on how to use AbstractController for <10 reasons>" during compiletime for all of them at once, or 10 separate vague errors about missing parameter bags, request stacks and HTTP kernels at runtime. (actually the compiler pass could generically check all |
Meanwhile, how about this for the issue at hand, mainly adapting Javier's suggestion to implementation:
|
Could, but what would we gain doing so? Nothing related to the issue at glance. To which one then? This means "shouldn't" to me :) |
It's related to the second question: should having a ServiceLocator with a mandatory but undefined reference crash unexpectedly during development or right away at compiletime right after wrongly defining it? I think for DX it'd be better to fail early, and it'd fix the entire issue at hand ages before we ever got to the It'd even microscopically improve performance as it would mean |
But this wouldn't fail at compile time. Or based on what criteria would it fail? What would be the trigger to throw this when the issue is precisely that this controller was not registered for the compiler pass that looks for building locators for subscribers? |
If we can autoconfigure services that implement |
Here is a proposal to fix the DX issue: #27462 |
Good idea, but let's also fix the error message now as it's currently just wrong in 4.1. Just pushed my last proposal merging Javier's suggestion with mine. |
@@ -64,7 +65,8 @@ public function setContainer(ContainerInterface $container) | |||
protected function getParameter(string $name) | |||
{ | |||
if (!$this->container->has('parameter_bag')) { | |||
throw new \LogicException('The "parameter_bag" service is not available. Try running "composer require dependency-injection:^4.1"'); | |||
throw new ServiceNotFoundException('parameter_bag', null, null, array(), | |||
sprintf('The "getParameter()" method of the controller can\'t get the value of the "%s" parameter because the "parameter_bag" service could not be located. Either enable autoconfigure for the controller service or inject a ServiceLocator referencing a "parameter_bag" service manually in the controller.', $name)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You missed my last comment here it is :) Also this should really be on one line, not two.
sprintf('The "%s::getParameter()" method is missing a parameter bag to work properly. Did you forget to register your controller as a service subscriber? This can be fixed e.g. by using autoconfiguration or by manually wiring a "parameter_bag" in the service locator passed to the controller.', get_class($this))
(the name of the parameter is of no importance IMHO, but the controller class IS.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought you meant only the string with the previous one-line remark. Is the Symfony code style on layout stuff like that documented somewhere? It's confusing that most projects (including our internal ones) explicitly prohibit lines beyond common-screen limits (ie. ~120 characters) and Symfony 'prefers oneliners'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with Nicolas' comment applied
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long line for user message allow using grep to find where that exception/deprecation comes from. That's and important DX feature for ppl that use this workflow when debugging.
Ah ok, understandable from that perspective. |
Thank you @curry684. |
…getParameter fails (curry684) This PR was squashed before being merged into the 4.1 branch (closes #27443). Discussion ---------- [DX] Improve exception message when AbstractController::getParameter fails | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | no (DX) | New feature? | no | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #27436 | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> Improve exception message for situations where the `parameter_bag` is not present in `AbstractController`. Also fixed the exception to the correct type. Commits ------- a8f4128 [DX] Improve exception message when AbstractController::getParameter fails
Improve exception message for situations where the
parameter_bag
is not present inAbstractController
. Also fixed the exception to the correct type.