
Using Exceptions in Symfony 2
- Tutorial
Not so long ago I talked with a colleague on the topic of using exceptions in Symfony. A brief overview of information on the Internet and of. The website of the framework showed that the topic in the documentation is not disclosed too deeply and a number of system capabilities remain behind the scenes. With this post, I decided to fill this gap a bit and share what I managed to find by delving into the code of the framework.
To use the tool correctly, it is important to understand how it works. Exception handling, in the case of a typical request via the web, is outlined here . A very useful HttpExceptionInterface is mentioned there, which I will write about below.
There are no revelations in this post for those who delved into the symfony 2.x code and its components. Such readers can safely skip this post.
If the developer did not catch exceptions himself, then HttpKernel will catch them , namely the handleException method. In fact, this method only triggers an event through the dispatcher that notifies all interested services about an emergency. Next we will see how the framework handles some types of exceptions.
What happens when exceptions happen in console commands? about the same thing. An exception is caught in the Application class, after which 2 events are sent: ConsoleEvents :: EXCEPTION and ConsoleEvents :: TERMINATE. The processing principle is the same as on the web. Exceptions raise events, the dispatcher sends them, the listeners do their job. For example, you can roll back transactions in case of an error during the execution of a command and not mix error handling with the main command code.
Out of the box, Symfony 2 can handle security exceptions (AuthenticationException, AccessDeniedException, LogoutException) and exceptions that implement HttpExceptionInterface.
HttpExceptionInterface-compatible - exceptions allow you to adjust the status code of the http response and its headers, this can be useful to redirect or clarify the error code in an exceptional situation.
Interestingly, the handling of this exception is not done through EventDispatcher, but is protected directly in HttpKernel ...
... in this way, if you throw such an exception, then instead of 500 code, you can pass something like 402 to the client, which can be useful when writing various APIs, you can also initiate a redirect from almost anywhere in the code, which is of course convenient but not always good and right. It is unlikely that anyone will appreciate the initiation of a redirect, say from TwigExtension or the business logic in the model. It is important that this type of exception cannot affect the content of the server’s response, only the header.
Also, the framework code has a security exception handler that allows you to handle 3 types of exceptions:
AuthenticationException- the parent of many other exceptions of various types handled in the SecurityBundle and Security Component. Throw this exception if you find that actions that are available only to registered users are attempted by a user who is not logged in.
The exception handler responds to it by trying to initiate authentication. In the most common case, it will give the user an authorization form, instead of the requested page.
It is worth noting that if the security layer is correctly configured in your project, then you are unlikely to have to throw this exception yourself or its descendants. The SecurityBundle will cope on its own and will not let anyone-do-not-do-it-yourself.
AccessDeniedException- This exception is similar to an AuthenticationException, but it should happen if the user rights do not meet the requirements. For example, an unprivileged user is trying to get into the admin panel. If an exception occurs, the user will see a page with a message about the lack of rights (the author hopes that he is not native - a symphony). Also, by means of this exception, you can send a user for re-authorization if, for example, he is authorized through a remember-cookie and you want to make sure once again that he is it.
Like the previous exception, you are unlikely to have to throw it yourself, it is better to entrust it with symphony, but still it seems to me that cases where such an action may be useful to the developer are more common.
LogoutException- This is an exception during logout. For example, the wrong form token or any problems with the session. The handler of this exception does nothing, only writes to the log.
Unlike HttpException, security exceptions are processed by the means of a standard listener, organically fitting into the architecture of the framework.
I did not find any more system exception handlers in standard assembly 2.5,despite the hints in the documentation .
The developer, as always, can do a lot. By adding your own types of exceptions and listeners for them, you can achieve almost any desired behavior. For example, errors in business logic, which in a certain environment will simply be written to the log, in another, can lead to the transfer of the user, say, to the logging panel, or to the object editor, in order to eliminate any drawbacks in it.
The author of this, to be honest, has not yet practiced, but he can imagine the tasks where this may be required.
You can say exactly what the developer should not do. Do not duplicate the functionality of existing framework handlers and neglect its capabilities. You should not refuse separate classes for various exceptions, even if when writing you just need to interrupt the execution of one or another code. Subsequently, logically separated exceptions can easily solve a complex problem.
How Exception Catching Works
To use the tool correctly, it is important to understand how it works. Exception handling, in the case of a typical request via the web, is outlined here . A very useful HttpExceptionInterface is mentioned there, which I will write about below.
There are no revelations in this post for those who delved into the symfony 2.x code and its components. Such readers can safely skip this post.
Who "catches" exceptions
If the developer did not catch exceptions himself, then HttpKernel will catch them , namely the handleException method. In fact, this method only triggers an event through the dispatcher that notifies all interested services about an emergency. Next we will see how the framework handles some types of exceptions.
What happens when exceptions happen in console commands? about the same thing. An exception is caught in the Application class, after which 2 events are sent: ConsoleEvents :: EXCEPTION and ConsoleEvents :: TERMINATE. The processing principle is the same as on the web. Exceptions raise events, the dispatcher sends them, the listeners do their job. For example, you can roll back transactions in case of an error during the execution of a command and not mix error handling with the main command code.
Built-in Exception Handlers
Out of the box, Symfony 2 can handle security exceptions (AuthenticationException, AccessDeniedException, LogoutException) and exceptions that implement HttpExceptionInterface.
Learn more about system exceptions.
HttpExceptionInterface-compatible - exceptions allow you to adjust the status code of the http response and its headers, this can be useful to redirect or clarify the error code in an exceptional situation.
Interestingly, the handling of this exception is not done through EventDispatcher, but is protected directly in HttpKernel ...
$response = $event->getResponse();
// the developer asked for a specific status code
if ($response->headers->has('X-Status-Code')) {
$response->setStatusCode($response->headers->get('X-Status-Code'));
$response->headers->remove('X-Status-Code');
} elseif (!$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {
// ensure that we actually have an error response
if ($e instanceof HttpExceptionInterface) {
// keep the HTTP status code and headers
$response->setStatusCode($e->getStatusCode());
$response->headers->add($e->getHeaders());
} else {
$response->setStatusCode(500);
}
}
... in this way, if you throw such an exception, then instead of 500 code, you can pass something like 402 to the client, which can be useful when writing various APIs, you can also initiate a redirect from almost anywhere in the code, which is of course convenient but not always good and right. It is unlikely that anyone will appreciate the initiation of a redirect, say from TwigExtension or the business logic in the model. It is important that this type of exception cannot affect the content of the server’s response, only the header.
Also, the framework code has a security exception handler that allows you to handle 3 types of exceptions:
AuthenticationException- the parent of many other exceptions of various types handled in the SecurityBundle and Security Component. Throw this exception if you find that actions that are available only to registered users are attempted by a user who is not logged in.
The exception handler responds to it by trying to initiate authentication. In the most common case, it will give the user an authorization form, instead of the requested page.
It is worth noting that if the security layer is correctly configured in your project, then you are unlikely to have to throw this exception yourself or its descendants. The SecurityBundle will cope on its own and will not let anyone-do-not-do-it-yourself.
AccessDeniedException- This exception is similar to an AuthenticationException, but it should happen if the user rights do not meet the requirements. For example, an unprivileged user is trying to get into the admin panel. If an exception occurs, the user will see a page with a message about the lack of rights (the author hopes that he is not native - a symphony). Also, by means of this exception, you can send a user for re-authorization if, for example, he is authorized through a remember-cookie and you want to make sure once again that he is it.
Like the previous exception, you are unlikely to have to throw it yourself, it is better to entrust it with symphony, but still it seems to me that cases where such an action may be useful to the developer are more common.
LogoutException- This is an exception during logout. For example, the wrong form token or any problems with the session. The handler of this exception does nothing, only writes to the log.
Unlike HttpException, security exceptions are processed by the means of a standard listener, organically fitting into the architecture of the framework.
I did not find any more system exception handlers in standard assembly 2.5,
Instead of a conclusion
The developer, as always, can do a lot. By adding your own types of exceptions and listeners for them, you can achieve almost any desired behavior. For example, errors in business logic, which in a certain environment will simply be written to the log, in another, can lead to the transfer of the user, say, to the logging panel, or to the object editor, in order to eliminate any drawbacks in it.
The author of this, to be honest, has not yet practiced, but he can imagine the tasks where this may be required.
You can say exactly what the developer should not do. Do not duplicate the functionality of existing framework handlers and neglect its capabilities. You should not refuse separate classes for various exceptions, even if when writing you just need to interrupt the execution of one or another code. Subsequently, logically separated exceptions can easily solve a complex problem.