I am working on the development of a centralized authentication web app with Symfony 3.4 and I encounter a problem with the auto-management of exception that Symfony provides. The problem is that I want to catch a ConnectionException raised by the LDAP component when the connexion to the Active Directory fails. The objective is to use this exception to notice when it fails and to redirect to a specific page. But at the very moment when the Exception is raised by the LDAP component, Symfony notice a kernel.exception event and then render a debug exception page instead of letting the program go and catch the exception.
How could I do to fix that problem and be sure that the Exception is caught and use by my code and not automatically by Symfony ?
I join you the sample of code and the page rendered:
<?php
namespace App\Utils;
use App\Entity\User;
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Ldap\Exception\ConnectionException;
class ActiveDirectoryStuff
{
private $domain = 'myDomain';
private $ldapString = 'ldap://';
public function __construct()
{}
public function connection($username, $password)
{
try {
$dn = $username.'#'.$this->domain;
$ldap = Ldap::create('ext_ldap', array(
'connection_string' => $this->ldapString . $this->domain,
));
$ldap->bind($dn, $password); //where the ConnectionException is raised
return $ldap;
} catch (\ConnectionException $ce) {
throw $ce;
}
}
}
Image of the Page Rendered Automatically
You're catching the exception, doing nothing then throwing, this is the same as having no try catch at this level of code
Based on what you said use your framework to redirect to a specific page from within the catch and any other logic you want to run when this error happens, then remove throw $ce; that will stop the default error handler from running which I assume is Symfony's
Related
I am studying the Symfony\Component\Debug\Debug.
As far as I know the AppKernel's constructor can accept a second argument to define whether to use the debug modality or not (true/false).
What I actually don't understand is the usage and complementarity of Debug::enable() as it is indicated in the app_dev.php on the official Symfony Github's repository.
For example I tried to throw an Exception on a Controller in order to see the effect and I commented Debug::enable(); within app_dev.php but I always see the error page.
Why am I still seeing error traces in spite of commenting out Debug::enable();?
Short explanation
The Debug::enable() method registers a fallback error handler, which will be called if your application failed to handle an error.
The error page you see when kernel is booted with the $debug flag set to true, is a result of your application error handling (implemented by an exception listener). Set the flag to false to disable stack traces. If you're only after testing you can also disable error pages in development.
The page shown by the Debug component is not as nice as the one provided by the exception listener, but it's nicer than the PHP one.
Detailed explanation
The front controller calls your application kernel:
$kernel = new AppKernel('dev', true);
$response = $kernel->handle(Request::createFromGlobals());
The application kernel boots itself, creates the container and calls the http kernel to handle the request:
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
The http kernel will use the event dispatcher to trigger certain events (kernel.request, kernel.response, kernel.exception etc). When an exception is thrown while handling the request, the http kernel will catch it and trigger the kernel.exception event:
// the following code is simplified to show the point
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
try {
return $this->handleRaw($request, $type);
} catch (\Exception $e) {
return $this->handleException($e, $request, $type);
}
}
private function handleException(\Exception $e, $request, $type)
{
$event = new GetResponseForExceptionEvent($this, $request, $type, $e);
$this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event);
// ...
}
One of the listeners registered by default in the Symfony Standard Edition is the Symfony\Component\HttpKernel\EventListener\ExceptionListener. It's responsible for rendering nice error pages.
However, it will only handle exceptions thrown while handling a request in the http kernel. So if anything goes wrong outside of this call, it won't be handled (have a look at the catch blog in the previous code example).
This is where the Debug component comes in. The Debug::enable() method registers an error handler, an exception handler and a special class loader. You can use it in any PHP project without the http kernel. It is sort of a fallback error handler which will be called if your application failed to handle an error. It has no relation to the $debug constructor argument in the kernel.
I am new in zendframework. I am using apigility for rest services and ApiProblemListner to return the response if any error occures.
I have one function in model and this function just through an exception using php exception to use in catch block
I am using model function as the utility function in controller to catch those Exception. While catching exception I am using as
try{
imageUploade(); // this function in model and throwing exception if any error
}catch(\Exception $e){
return new ApiProblemResponse(new ApiProblem(500 , $e->getMessage()));
}
if imageUploade() throw an exception if the image size is more then I am able to catch the exception in catch block. I tried echo $e->getMessage(); and its printing the exception bt if I use new ApiProblem(500 , $e->getMessage()) it is not retuning the json error response with the 500 message. It is returning nothing. even it is not showing any error.
Seems like it is unable to render the error with this class. I am not sure if any event needs to add.
I have tried to search for documents but unable to find it.
Thanks in advance.
Normally it should work if you return an ApiProblemResponse straight from a controller action.
Are you sure your Api-Problem module is active?
Try once like this:
<?php
Application\Namespace;
use ZF\ApiProblem\ApiProblem;
use ZF\ApiProblem\ApiProblemResponse;
class IndexController
{
/**
* #return ApiProblemResponse
*/
public function indexAction()
{
return new ApiProblemResponse(new ApiProblem(500, 'test'));
}
}
If that doesn't work then I think your Api-Problem module is not running or the exception is never caught.
I am using Symfony 2.4 and am trying to create a more powerful exceptions handler that, on certain PDO / Doctrine exceptions, changes the status code of the response from 500 to 503 to display a different custom error message than our standard (in other words, it returns the error503.html.twig template rather than error500.html.twig). So far, I have created a custom Exceptions controller that extends the TwigBundle ExceptionController, I have changed the Twig exception parameter in config.yml, and I am able to catch any and all exceptions that are thrown once Symfony calls handle(...) in HttpKernel.php:185 (so it's really the second time that handle is called -- this time being on the HttpKernel rather than the AppKernel). I'll refrain from posting all that code, and instead direct the reader here to learn more about my method if they are unfamiliar. All of that code is working just fine -- I am able to modify any applications that are thrown within my application, so you can assume that I'm using the aforementioned approach properly.
The issue I am running into is that in addition to catching exceptions that are thrown within Symfony, I also want to also be able to catch exceptions that are thrown before the HttpKernel's handle method is called (an example being a PDO Access Denied exception that is thrown from improper database credentials). To give you a more specific rundown, in app_dev.php, you have:
$response = $kernel->handle($request);
which calls:
/**
* {#inheritdoc}
*
* #api
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
Now, if an exception gets thrown in $this->boot(), it doesn't look like it gets caught anywhere, and because of that, I can't see any way of gracefully handling said exception in Symfony. It's only if the exception gets thrown within the try / catch block contained in $this->getHttpKernel()->handle($request, $type, $catch) that it will be caught and gracefully handled using Symfony code. Am I wrong about that? Does anyone know of an approach to handling exceptions that are thrown in this context that utilizes Symfony? My apologies in advance if this has already been answered elsewhere.
I ran into a similar problem, I didn't see a neat way around this but was able to get nice error pages for my specific problem simply by generating a Response object and sending that. I placed the following in some code which was called by boot()
try {
someExceptionFunction();
} catch (Exception $e) {
$response = new Response('<html><body>'.$e->getMessage().'</body></html>');
$response->send();
exit;
}
You could easily add some more logic to the catch block, catching different exceptions. It's not as clean/abstract as it could be, but since the entire framework fails to boot I don't know of any option you could use it to parse an error page.
Hope this helps
How to handle exceptions manually in symfony2 in case like this:
class Foo {
// ..
public function __toString()
{
try {
$this->render();
}
catch (\Exception $e)
{
// log $e
// handle $e - display 500 error page in prod mode
}
}
}
Redirect? But how.
EDIT
My solution so far is to dispatch exception event, and it works.
$dispatcher->dispatch(KernelEvents::EXCEPTION, $event)
But i requires creating an event. Is there some better solution?
You can also define your own exception controller and perform needed behavior.
Check How to customize Error Pages and Configuration: exception_controller
UPD
Creating event listener is a good solution to catch exceptions.
We can also customize specific TWIG error templates according to the HTTP status ( returned )code. For example, create a app/Resources/TwigBundle/views/Exception/error404.html.twig template to display a special page for 404 (page not found) errors.
OR, we can also customize exceptionController.
The problem
I'm building a small application with Silex. It's divided between a REST application and a website. (two controllers, same app).
The website has installed its own custom error handler, which returns a user friendly html page. The problem is that in the part dedicated REST application, I should somehow handle exceptions to return type [json] and content different from the error handler's custom website.
With Symfony2
This argument can also be applied to Symfony2, I would like also possible solution for it!
A first solution for Silex
Wrap the methods in try-catch block in order to rethrowing the exception to handler.
$app->get('/api/show-list', function() use($app){
try {
$show = // db query, etc.
return $app->json(array('show' => $show), 200);
} catch (Exception $e) {
throw new MyException;
}
});
$app->error(function (MyException $e, $code) {
// error api
});
The issue is that if an exception is thrown out of my controllor the default error handler will be used. Some tips?
And with Symfony?
I have been using the following in my Silex RESTful app to return errors in json format:
$app->error(function (\Exception $e, $code) use($app) {
return $app->json(array("error" => $e->getMessage()),$code);
});
Not sure if this is the right way, but it works for me.
This is documented on the Silex site:
http://silex.sensiolabs.org/doc/usage.html#error-handlers
On Symfony2 you can use the ExceptionHandler. On the Exception you have the stack trace, so you can identify where it was thrown.
Also, in Symfony2 you can customize depending on the expected format. It's well explained in it's documentation.
For instance, if you replace the ExceptionController with one of yours, the third parameter shows the expected format:
Reference on where to change the ExceptionController
ExceptionController API