Scroll down to the script below, click on any sentence (including terminal blocks!) to jump to that spot in the video!
With a Subscription, click any sentence in the script to jump to that part of the video!Login Subscribe
The job of this
ErrorController is to turn the
Exception that was thrown into a
Response. By the way, the
error_controller is actually configurable. So if you want to control the error response on your site, you have two options so far. First, register a listener to
kernel.exception. Or second, override the error controller via the
But... if you did that, you would be responsible for rendering both the normal exception pages and production error pages. If you want to change how an error page looks, there are better ways. We'll see.
__invoke() method, the
ErrorController... is lazy! It immediately offloads the work to someone else - something called the
errorRenderer. That returns some sort of exception... which apparently has
getHeaders() methods. It uses these to create & return the
Let's... find out what this
errorRenderer thing is:
|... lines 1 - 25|
|... lines 28 - 38|
|public function __invoke(\Throwable $exception): Response|
|... lines 42 - 44|
|... lines 46 - 62|
Move over and refresh. Ok cool: it's something called
SerializerErrorRenderer. And actually, it only uses this class because this project has the serializer component installed. If you did not, this would be a different class - one that we'll see in a few minutes. And, by the way, this whole "error renderer" thing is part of a Symfony component called
error-handler that's new in Symfony 4.4.
Let dig in! I'll close a class, then hit Shift + Shift to open
ErrorController calls this
render() method, which immediately calls
FlattenException is basically a visual representation of an exception. And notice: the
render() method returns a
Hold Command or Ctrl to jump into this class. Yea, see: it's not actually an exception - it doesn't extend
Exception or implement
Throwable. But it does contain a lot of the same info, like the exception
$previous and the stack trace.
FlattenException::createFromThrowable - if we jump to that - is a way to easily create this "visual representation" based on a real exception. And this contains some pretty important stuff. For example, if
$exception is an instance of
HttpExceptionInterface, then it calls
$exception->getStatusCode() to get the status code and
$exception->getHeaders() to get the headers. Both the status code and headers are ultimately stored on this
FlattenException object and used by
ErrorController when it creates the final
So... what is this
HttpExceptionInterface thing? We've actually seen it. Go back to
ArticleController. We know that
$this->createNotFoundException() is a shortcut to instantiate a new
NotFoundHttpException. Click to open that class... and click again to open its base class
HttpException. Here it is:
This is a long way of showing you that certain exception classes in Symfony - like
NotFoundHttpException - map to a specific status code. This works because they implement
HttpExceptionInterface and because
FlattenException uses this.
NotFoundHttpException specifically map to a 404. It calls
parent::__construct() with 404... that is set to a
$statusCode property... and then returned from
getStatusCode(). You can also pass custom
$headers to the exception.
And there are a bunch of other exception classes like this. I'll double-click on the
Exception directory at the top of PhpStorm. Wow! There are more than 15 in this directory alone, like
BadRequestsHttpException, which will give you a 400 status code,
PreconditionFailedHttpException, which will be a 412 and many more. Hmm, where's the
If you throw any of these exceptions from anywhere in your app, they will trigger an error page with the correct status code. This is a powerful thing to understand.
FlattenException, there is also another type of exception interface called
RequestExceptionInterface. It's not as important and it always maps to a 400 status code.
If the exception doesn't implement either of these interfaces, the status code will be 500.
These are the most important parts of the
FlattenException. Close it and go back to
SerializerErrorRenderer. The job of this method is to create a
FlattenException object from the exception and make sure it contains three things that the
ErrorController needs: the status code, headers and a string representation of the error, which will become the body of the response. We've got the status code & headers... but we still need to somehow generate a "string" representation of this exception. Let's see how that's done next.