📜 ⬆️ ⬇️

Using exceptions in symfony 2

Not so long ago I talked with a colleague about the use of exceptions in symfony. Overview of information on the Internet and of. The framework site showed that the topic in the documentation is not revealed 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 could find by digging into the framework code.

How does the "catching" of exceptions

To properly use the tool, it is important to understand how it works. Exception handling, in the case of a typical web request, is described here in general terms. There is also mentioned a very useful HttpExceptionInterface, which I will write below.

In this post there are no revelations for those who delved into the symfony 2.x code and its components. So readers can safely skip this post.
')

Who "catches" exceptions

If the developer did not catch the exceptions himself, then HttpKernel , namely the handleException method, will catch them. In fact, this method only launches an event through the dispatcher that notifies all interested services of the occurrence of an exceptional situation. Next we look at how the framework handles some types of exceptions.

What happens when exceptions happen in console commands? about the same. An exception is caught in the Application class, after which 2 events are dispatched: ConsoleEvents :: EXCEPTION and ConsoleEvents :: TERMINATE. The processing principle is the same as in the web. Exceptions generate events, the controller dispatches them, listeners do their work. For example, you can roll back transactions in the event 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.

More about system exceptions.

HttpExceptionInterface-compatible - exceptions allow you to adjust the http-response status code and its headers, it can be useful to redirect or clarify the error code in an exceptional situation.

Interestingly, the handling of this exception is not done via 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); } } 


... so, in case you throw such an exception, instead of code 500, you can transfer something like 402 to the client, which can be useful when writing various APIs, you can also initiate a redirect from almost any point of the code, which of course is convenient , but not always well and correctly. It is unlikely that someone will appreciate the initiation of a redirect, say from TwigExtension or business logic in the model. It is important that the content of the server's response to this type of exception can not affect only the title.

Also in the framework code, there is a security exception handler that allows you to handle 3 types of exceptions:

AuthenticationException is the parent of many other types of exceptions that are handled by the SecurityBundle and Security Component. This exception should be thrown if you find that actions that are available only to registered users are attempted by a non-logged-in user.

The exception handler responds to it by attempting to initiate authentication. In the most common case - 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, you will hardly have to generate this exception yourself or its descendants. SecurityBundle will cope on its own and will not let anyone not-need somewhere-not.

AccessDeniedException - this exception is similar to AuthenticationException, but it should happen if the user's rights do not meet the requirements. For example, an unprivileged user tries to get into the administration panel. If an exception happens - the user will see a page with a message about the lack of rights (the author hopes that the non-native one is a symphony). Also by means of this exception, you can send the user to re-authorization, if he, for example, is authorized through a remember-cookie and you want to make sure once again that he is he.
Like the previous exception, you hardly have to throw it out yourself, it is better to entrust it with a symphony, but still it seems to me that cases where the developer may need this option are more common.

LogoutException 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 handled by the standard listener, organically fitting into the framework architecture.
I did not find any more system exception handlers in the standard 2.5 build, despite the hints in the documentation .

Instead of conclusion

The developer, as always, can very much. 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 recorded in 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 flaws in it.
The author of this, to be honest, has not yet practiced, but a wave can present tasks where it may be required.

You can say for sure what the developer shouldn’t do. You should not duplicate the functionality of the existing framework handlers and neglect its capabilities. You should not give up individual classes for different exceptions, even if when writing you just need to interrupt the execution of a particular code. Subsequently, logically separated exceptions can easily solve a complex problem.

Source: https://habr.com/ru/post/227807/


All Articles