8000 [HttpKernel] Better exception page when the controller returns nothing by lyrixx · Pull Request #27138 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[HttpKernel] Better exception page when the controller returns nothing #27138

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
May 9, 2018

Conversation

lyrixx
Copy link
Member
@lyrixx lyrixx commented May 3, 2018
Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #27137
License MIT
Doc PR

Before:

before

after:

after

throw $e;
}

$r = new \ReflectionProperty(\Exception::class, 'trace');
Copy link
Member
@nicolas-grekas nicolas-grekas May 3, 2018

Choose a reason for hiding this comment

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

What about using a rebound closure instead of reflection? It'd make things easier to read IMHO.

Copy link
Member Author

Choose a reason for hiding this comment

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

Warning: Cannot bind closure to scope of internal class Exception

$r->setAccessible(true);
$r->setValue($e, array_merge(array(
array(
'line' => $e->getLine(),
Copy link
Member

Choose a reason for hiding this comment

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

This could be even more accurate, passing the line of the call_user_fun above (using __LINE__ next to it.)
Aren't they other keys we should put in the frame? How does it look when thrown from inside the controller?

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

8000
}

if (is_object($controller)) {
$r = new \ReflectionClass($controller);
Copy link
Member

Choose a reason for hiding this comment

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

method __invoke()?

Copy link
Member Author
@lyrixx lyrixx May 3, 2018

Choose a reason for hiding this comment

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

yes

BTW, I adapted the code from

protected function parseController($controller)
{
if (is_string($controller) && false !== strpos($controller, '::')) {
$controller = explode('::', $controller);
}
if (is_array($controller)) {
try {
$r = new \ReflectionMethod($controller[0], $controller[1]);
return array(
'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0],
'method' => $controller[1],
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);
} catch (\ReflectionException $e) {
if (is_callable($controller)) {
// using __call or __callStatic
return array(
'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0],
'method' => $controller[1],
'file' => 'n/a',
'line' => 'n/a',
);
}
}
}
if ($controller instanceof \Closure) {
$r = new \ReflectionFunction($controller);
return array(
'class' => $r->getName(),
'method' => null,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);
}
if (is_object($controller)) {
$r = new \ReflectionClass($controller);
return array(
'class' => $r->getName(),
'method' => null,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
);
}
return is_string($controller) ? $controller : 'n/a';
}

@lyrixx lyrixx force-pushed the http-kernel-exception-controller branch from 31a63b9 to 93ecc0b Compare May 3, 2018 15:05
@@ -146,7 +146,7 @@ private function handleRaw(Request $request, int $type = self::MASTER_REQUEST)
$arguments = $event->getArguments();

// call controller
$response = \call_user_func_array($controller, $arguments);
$response = \call_user_func_array($controller, $arguments); $line = __LINE__;
Copy link
Member

Choose a reason for hiding this comment

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

I would put this on the next line using $line = __LINE__ - 1; instead. The current code does not comply with our coding standards, and would force to exclude the whole HttpKernel.php file from the CS tooling to avoid having PHP-CS-Fixer breaking it on each run.

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@lyrixx lyrixx force-pushed the http-kernel-exception-controller branch from 93ecc0b to 36dacd7 Compare May 3, 2018 15:24
'line' => $r->getStartLine(),
);
} catch (\ReflectionException $e) {
return null;
Copy link
Member

Choose a reason for hiding this comment

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

try new \ReflectionClass($controller[0])?

Copy link
Member Author

Choose a reason for hiding this comment

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

To get only the file?

Copy link
Member
@nicolas-grekas nicolas-grekas May 3, 2018

Choose a reason for hiding this comment

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

Yes, WDYT ? And start line of the class of course.

Copy link
Member Author

Choose a reason for hiding this comment

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

Why not, But I don't know how to "simulate" this fail :/ Do you know how to?

Copy link
Member

Choose a reason for hiding this comment

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

Looking at RequestDataCollector I'd say using __call?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't understand. Sorry.
If the method does not exist in the first place Symfony throw an error.
I don't want to add dead code to Symfony, so please give me a reproducer ;)

@nicolas-grekas
Copy link
Member

WDYT of moving all the added logic to a new exception class, child of LogicException?

@nicolas-grekas nicolas-grekas added this to the next milestone May 3, 2018
@lyrixx lyrixx force-pushed the http-kernel-exception-controller branch 2 times, most recently from 8c5d7b2 to c8f75e5 Compare May 4, 2018 12:15
@lyrixx
Copy link
Member Author
lyrixx commented May 4, 2018

@nicolas-grekas I added the new Exception class.

Note: Exception::trace is private, So I need reflection. line and file are protected ;).
and get* methods are final

@@ -162,7 +163,8 @@ private function handleRaw(Request $request, int $type = self::MASTER_REQUEST)
if (null === $response) {
$msg .= ' Did you forget to add a return statement somewhere in your controller?';
}
throw new \LogicException($msg);

throw new ControllerDoesNotReturnResponseException($msg, $controller, __FILE__, __LINE__ - 17);
Copy link
Member

Choose a reason for hiding this comment

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

we need a test case to ensure we won't miss updating this "17" in the future I suppose

Copy link
Member Author

Choose a reason for hiding this comment

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

Tests added

@lyrixx lyrixx force-pushed the http-kernel-exception-controller branch from c8f75e5 to f1e9aa4 Compare May 7, 2018 08:40
@fabpot
Copy link
Member
fabpot commented May 9, 2018

Thank you @lyrixx.

@fabpot fabpot merged commit f1e9aa4 into symfony:master May 9, 2018
fabpot added a commit that referenced this pull request May 9, 2018
… returns nothing (lyrixx)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[HttpKernel] Better exception page when the controller returns nothing

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

---

Before:

![before](https://user-images.githubusercontent.com/408368/39580501-9c8d5e0a-4ee9-11e8-84a9-aad8566da4b6.png)

after:

![after](https://user-images.githubusercontent.com/408368/39580504-a23e3b76-4ee9-11e8-9a89-01e519b94a20.png)

Commits
-------

f1e9aa4 [HttpKernel] Better exception page when the controller returns nothing
@lyrixx lyrixx deleted the http-kernel-exception-controller branch May 9, 2018 08:31
@nicolas-grekas nicolas-grekas removed this from the next milestone Nov 1, 2018
@nicolas-grekas nicolas-grekas added this to the 4.1 milestone Nov 1, 2018
This was referenced Nov 3, 2018
fabpot added a commit that referenced this pull request Mar 5, 2019
…controller returns nothing (dimabory)

This PR was merged into the 4.3-dev branch.

Discussion
----------

[HttpKernel] Better exception page when the invokable controller returns nothing

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

---

__Prerequisites__
_Configure invokable controller_
```php
# config/routes.yaml
index:
    path: /
    controller: App\Controller\Start
```

__Before:__
![before](https://user-images.githubusercontent.com/11414342/53577698-ca739000-3b7e-11e9-98ac-8c8e27626fbe.png)

__After:__
![after](https://user-images.githubusercontent.com/11414342/53577733-df502380-3b7e-11e9-8377-a4a97ea73df8.png)

---

Take a look for an enhancement/refactoring in `HttpKernel.php`

Commits
-------

f6c1622 [HttpKernel] Better exception page when the invokable controller returns nothing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0