10000 [HttpKernel] Add better error message when controller action isn't callable by pierredup · Pull Request #10788 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[HttpKernel] Add better error message when controller action isn't callable #10788

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

Merged
merged 1 commit into from
Sep 23, 2015

Conversation

pierredup
Copy link
Contributor
Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets none
License MIT
Doc PR

In the ControllerResolver, if a controller isn't callable, try to give a better description of what went wrong

array('Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest::staticsAction', 'The controller for URI "/" is not callable. Expected method "staticsAction" on class "Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest", did you mean "staticAction"?'),
array('Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest::privateAction', 'The controller for URI "/" is not callable. Method "privateAction" on class "Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest" should not be private'),
array('Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest::protectedAction', 'The controller for URI "/" is not callable. Method "protectedAction" on class "Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest" should not be protected'),
array('Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest::undefinedAction', 'The controller for URI "/" is not callable. Expected method "undefinedAction" on class "Symfony\Component\HttpKernel\Tests\Fixtures\ControllerTest". Available methods: "publicAction", "staticAction"'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the controller test class is used only in this file then it would be in the same file right?

@pierredup
Copy link
Contributor Author

Please add the DX label for this PR.

$message .= sprintf(', did you mean "%s"?', implode('", "', array_keys($alternatives)));
} else {
$message .= sprintf('. Available methods: "%s"', implode('", "', $collection));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, the alternatives should be full _controller strings.

So, don't just say, "Did you mean newAction"? If possible, I think we should say, did you mean "AcmeDemoBundle:Default:new"?

This would need to live actually on the ControllerResolver::createController method inside of the FrameworkBundle (as the AcmeDemoBundle:Default:new syntax is specific to the framework).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first part of the message is Expected method "%s" on class "%s". So saying something like Expected method "newAction" on class "DefaultController", did you mean AcmeDemoBundle:Default:news? doesn't feel right.
This checks for mistakes in the action name, if E.G you have a newsAction, but reference it just as new, then this message will give you an idea of the correct method name to use.
This is useful for any class and method, not just the Bundle:Controller:Action syntax in the FrameworkBundle

@weaverryan
Copy link
Member

@pierredup I like this PR, so let's see if we can get it merged. This is the last week before the Symfony 2.6 feature freeze, so if we can work quickly, then this could get in for 2.6 :). The biggest issue I see is that there is a lot of logic here to get the message right, which makes it look disorganized. Perhaps if we moved a lot (or all) of this logic into different private functions, it'll help make things look more clear. Specifically, if all the logic from line 92 to line 137 were in a private function, then all the nested if's would be easier to read. I actually just have a hard time following which if block I'm in :).

Thanks!

$container->expects($this->once())
->method('get')
->with('foo')
->will($this->returnValue($this))
;
->will($this->returnValue($this));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to make these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done according to fabbot.io (http://fabbot.io/report/symfony/symfony/10788/16743fe4ac4b5929409b9f79e8349bb2a3460a9a, but the page doesn't exist anymore). I just applied the patch, and assumed the changes is correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, then you're fine! Thanks for the clarification!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pierredup Sorry about that but fabbot (and actually PHP-CS-Fixer) is sometimes wrong, and here it is definitely wrong.

@weaverryan
Copy link
Member

@pierredup There are a few CS changes that I think you made accidentally and the PR needs to be rebased. But after that, 👍 from me - I think it's certainly a big improvement.

@pierredup
Copy link
Contributor Author

I've simplified the check a bit more and squashed the commits, so I think this PR is ready now

@@ -155,4 +159,52 @@ protected function createController($controller)

return array(new $class(), $method);
}

private function getControllerError(array $callable)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's wrong. The createController() method can return any PHP callable. It just happens that the default implementation returns an array, but that's not a requirement.

@weaverryan
Copy link
Member

@pierredup I see you made the change fabpot suggested - awesome! Can you rebase if you have a chance to fix the conflict?

$method,
$reflection->getName()
);
} elseif (is_string($callable) && !function_exists($callable)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if is enough given that the previous if returns.

@fabpot
Copy link
Member
fabpot commented Feb 11, 2015

@pierredup Do you have some time to finish this PR?

@pierredup
Copy link
Contributor Author

@fabpot Done

@pierredup
Copy link
Contributor Author

ping @fabpot

@weaverryan
Copy link
Member

Ping @symfony/deciders - failing tests seem unrelated

@weaverryan
Copy link
Member

👍 All the edge-cases for different types of controllers is quite complex, but I couldn't think of any other edge-cases, and if there are some, it will just cause a less-helpful error message that we can improve on.

@weaverryan
Copy link
Member

Status: Reviewed

@aitboudad
Copy link
Contributor

👍

$reflection = new \ReflectionClass($controller);

if (!method_exists($controller, $method)) {
$collection = array_map(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use get_class_methods() here?

@fabpot
Copy link
Member
fabpot commented Sep 14, 2015

@pierredup Can you have a look at the tests. They are broken.


$message .= $this->getControllerError($callable);

throw new \InvalidArgumentException($message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the intermediate $message var and do everything on one line?

@pierredup
Copy link
Contributor Author

@fabpot I'm looking into the failing builds, will let you know once the builds are passing

private function getControllerError($callable)
{
if (is F438 _string($callable)) {
if (!function_exists($callable)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is broken for Foo::bar strings, as such functions won't exist and so will go there. the check for :: needs to be done first

@pierredup pierredup force-pushed the controller-error branch 2 times, most recently from 0fa35ae to c7ff100 Compare September 23, 2015 07:21
array(
'Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest::bar',
'\InvalidArgumentException',
'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest::bar" for URI "/" is not callable.',
'/.?[cC]ontroller(.*?) for URI "\/" is not callable\.( Expected method(.*) Available methods)?/',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regular expression test is necessary because on travis when the tests are run using deps=low the tests failed because of the installed dependecies

@pierredup
Copy link
Contributor Author

Travis tests is now passing. The failures on appveyor looks unrelated to these changes.

@fabpot
Copy link
Member
fabpot commented Sep 23, 2015

Thank you @pierredup.

@fabpot fabpot merged commit e0e19f6 into symfony:master Sep 23, 2015
fabpot added a commit that referenced this pull request Sep 23, 2015
…action isn't callable (pierredup)

This PR was merged into the 3.0-dev branch.

Discussion
----------

[HttpKernel] Add better error m
7ABF
essage when controller action isn't callable

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | none
| License       | MIT
| Doc PR        |

In the `ControllerResolver`, if a controller isn't callable, try to give a better description of what went wrong

Commits
-------

e0e19f6 Add better error message when controller action isn't callable
@fabpot fabpot mentioned this pull request Nov 16, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DX DX = Developer eXperience (anything that improves the experience of using Symfony) HttpKernel Status: Reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
0