Catch different Exception types - php

I have a very simple function to check whether an Entity exists in a bundle:
public function checkExists($bundle, $val)
{
try{
$this->em->getRepository($bundle.':'.$val);
}catch (MappingException $e){
return false;
}
return true;
}
So I have the following cases:
Input | Expected | Actual
'AppBundle', 'Company' | true | true
'AppBundle', 'NONEXISTANT' | false | false (MappingException caught)
'NONEXISTANT', 'Company' | false | 500 (ORMException not caught)
'NONEXISTANT', 'NONEXISTANT' | false | 500 (ORMException not caught)
So I see that the problem is that there are different exceptions thrown, but how could I return false for either of the cases of one part non-existant? Is there a "general" way to catch exceptions in symfony as catch (Exception $e) with use Symfony\Component\Config\Definition\Exception\Exception; does not catch it.

There's a couple of things to do:
You can catch all exceptions firstly, then you can handle each one differently:
public function checkExists($bundle, $val)
{
try{
$this->em->getRepository($bundle.':'.$val);
} catch (\Exception $e){ // \Exception is the global scope exception
if ($e instanceof MappingException || $e instanceof ORMException) {
return false;
}
throw $e; //Rethrow it if you can't handle it here.
}
return true;
}
Alternatevely have multiple catches:
public function checkExists($bundle, $val)
{
try{
$this->em->getRepository($bundle.':'.$val);
} catch (MappingException $e){
return false;
} catch (ORMException $e) {
return false;
} //Other exceptions are still unhandled.
return true;
}
If you're using PHP 7.1 + then you can also do:
public function checkExists($bundle, $val)
{
try{
$this->em->getRepository($bundle.':'.$val);
} catch (MappingException | ORMException $e){ //Catch either MappingException or ORMException
return false;
} //Other exceptions are still unhandled.
return true;
}

Create Exception Listener and handle them there.
class ExceptionListener
{
/** #var LoggerInterface */
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$e = $event->getException();
if ($e instanceof ValidationException) {
$this->logger->notice('Validation error' , $e->getViolations());
} elseif ($e instanceof DomainException) {
$this->logger->warning('Exception ' . get_class($e) , ['message' => $e->getMessage()]);
$event->setResponse(
new JsonResponse(['error' => $this->translator->trans($e->getOutMessage())], 400)
);
} else {
$event->setResponse(
new JsonResponse(['error' => $this->translator->trans('http.internal_server_error')], 500)
);
}
}
}
Update services.yml
app.exception_listener:
class: Application\Listeners\ExceptionListener
arguments: ['#domain.logger']
tags:
- { name: kernel.event_listener, event: kernel.exception }
Further reading about listeners and events https://symfony.com/doc/current/event_dispatcher.html
I am not sure that you should create situations that throw Mapping exceptions, when your application is shipped.

Related

Laravel create custom exception with parameters & return as JSON

I want to throw a custom exception if the variable is null and return it as JSON.
I've tried like this:
Controller
try {
$check_api_key = $attendance_libraries->check_api_key($this->request);
if ($check_api_key == null) {
throw new NullException(false, 'API Key Not Found', null, 500);
}
} catch (NullException $e) {
return $e;
} catch (\Exception $e) {
// do something else
}
Custom Exception
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Http\Response;
class NullException extends Exception
{
public $is_success;
public $message;
public $code;
public $data;
public function __construct($is_success, $message, $code, $data = null, Exception $previous = NULL)
{
$this->is_success = $is_success;
$this->message = $message;
$this->code = $code;
$this->data = $data;
}
public function render()
{
return response()->json([
'success' => $this->is_success,
'message' => $this->message,
'data' => $this->data,
], $this->code);
}
}
But when I am trying to test it using postman, the return I got is not the same as I wrote in NullException. It becomes like this:
In your case you are returning the exception as a response instead of throwing it. That's why it's displayed like this.
You could just have to throw the exception without the try/catch:
$check_api_key = $attendance_libraries->check_api_key($this->request);
if ($check_api_key == null) {
throw new NullException(false, 'API Key Not Found', null, 500);
}
The laravel error handler will catch the exception & render it.
EDIT: Or as #miken32 pointed out you could re throw the exception to handle other exceptions:
try {
//...
} catch (NullException $e) {
throw $e;
} catch (// other exceptions) {
}
Instead of Returning the render method from Exception you are returning the Exception. And also you are passing the arguments in wrong order.
Route::get('exception', function () {
try {
$check_api_key = null;
if ($check_api_key == null) {
throw new NullException(
is_success: false,
message: "API Key Not Found",
code: 500
);
}
} catch (NullException $e) {
return $e->render();
} catch (\Exception $e) {
}
});

Laravel handle custom Exceptions

I want to handle custom Exceptions (PDOException, ...)
In App/Exceptions/Handler.php I add the following functions:
public function report(Exception $e)
{
if ($e instanceof \PDOException) {
//$this->renderHttpException($e);
//Doesn't work
}
else
{
parent::report($e);
}
}
public function render($request, Exception $e)
{
if($this->isHttpException($e))
{
return $this->renderHttpException($e);
}
else
{
return parent::render($request, $e);
}
}
protected function renderHttpException(HttpException $e)
{
if (view()->exists('errors.'.$e->getStatusCode()))
{
return response()->view('errors.'.$e->getStatusCode(), [], $e->getStatusCode());
}
else
{
//comes later
return null;
}
}
If I have a PDOException I can't handle it, because the PDOException doesn't look like a default Laravel Exception.
I know that it can't work, but I don't know how to make it work.
Here is the Laravel (5.1) Error:
Argument 1 passed to App\Exceptions\Handler::renderHttpException() must be
an instance of
Symfony\Component\HttpKernel\Exception\HttpException, instance of
PDOException given, called in /home/****/Workspace/****/app/Exceptions/Handler.php
on line 37 and defined
The function source is from
mattstauffer.co

How to catch ReflectionException in Laravel 5?

$module - is one of my classes, based on Interface and must be have public function getController. I can forget to add getController function in class, and after run i have this error:
ReflectionException in Container.php line 776:
Class App\Http\Controllers\ does not exist
and want to catch this exception, but this code not work:
try
{
\Route::get($module->getUrl(), $module->getController() . '#index');
}
catch (\ReflectionException $e)
{
echo 123123;
}
Code example:
namespace App\MyModules;
MyModuleManager::bindRoute();
interface MyModuleInterface
{
public function getUrl();
public function getController();
}
class MyClass implements MyModuleInterface
{
public function getUrl()
{
return '/url';
}
/*
* for example: this method i forgdet to add
* and in ModuleManager::bindRoute i want to cath exception
*
public function getController()
{
}
*/
}
class MyModuleManager
{
static public function bindRoute()
{
$module = new MyClass();
try
{
\Route::get($module->getUrl(), $module->getController() . '#index');
}
catch (\ReflectionException $e)
{
echo 123123;
}
}
}
In L5 you can handle this exception globally:
// Exceptions/Handler.php
use ReflectionException;
public function render($request, \Exception $e)
{
if ($e instanceof ReflectionException) {
// …
}
return parent::render($request, $e);
}

Why is my exception thrown from a closure not caught?

I've written a PHPUnit test that checks if an exception is thrown from a closure when a method is invoked. The closure function is passed in as an argument to the method with an exception being thrown from it.
public function testExceptionThrownFromClosure()
{
try {
$this->_externalResourceTemplate->get(
$this->_expectedUrl,
$this->_paramsOne,
function ($anything) {
throw new Some_Exception('message');
}
);
$this->fail("Expected exception has not been found");
} catch (Some_Exception $e) {
var_dump($e->getMessage()); die;
}
}
The code for the get function specified on the ExternalResourceTemplate is
public function get($url, $params, $closure)
{
try {
$this->_getHttpClient()->setUri($url);
foreach ($params as $key => $value) {
$this->_getHttpClient()->setParameterGet($key, $value);
}
$response = $this->_getHttpClient()->request();
return $closure($response->getBody());
} catch (Exception $e) {
//Log
//Monitor
}
}
Any ideas why the fail assert statement is called? Can you not catch exceptions thrown from closures in PHP or is there a specific way of dealing with them I don't know about.
For me the exception should just propagate out the return stack, but it doesn't appear to. Is this a bug? FYI I'm running PHP 5.3.3
Thanks for the answers...
Managed to figure out the issue. It looks like the problem is that the try-catch block that's being invoked is the one where the closure is invoked. Which makes sense...
So the code above should be
public function get($url, $params, $closure)
{
try {
$this->_getHttpClient()->setUri($url);
foreach ($params as $key => $value) {
$this->_getHttpClient()->setParameterGet($key, $value);
}
$response = $this->_getHttpClient()->request();
return $closure($response->getBody());
} catch (Exception $e) {
//Log
//Monitor
throw new Some_Specific_Exception("Exception is actually caught here");
}
}
So it looks like PHP 5.3.3 doesn't have a bug after all which was mentioned. My mistake.
I cannot reproduce the behavior, my example script
<?php
class Some_Exception extends Exception { }
echo 'php ', phpversion(), "\n";
$foo = new Foo;
$foo->testExceptionThrownFromClosure();
class Foo {
public function __construct() {
$this->_externalResourceTemplate = new Bar();
$this->_expectedUrl = '_expectedUrl';
$this->_paramsOne = '_paramsOne';
}
public function testExceptionThrownFromClosure()
{
try {
$this->_externalResourceTemplate->get(
$this->_expectedUrl,
$this->_paramsOne,
function ($anything) {
throw new Some_Exception('message');
}
);
$this->fail("Expected exception has not been found");
} catch (Some_Exception $e) {
var_dump('my exception handler', $e->getMessage()); die;
}
}
}
class Bar {
public function get($url, $p, $fn) {
$fn(1);
}
}
prints
php 5.4.7
string(20) "my exception handler"
string(7) "message"
as expected

php manual exception example

So I was reading the php manual on Extending Exceptions and read the example code. My question about the following code is: why does var_dump($o) evaluate to null? Is it because the constructor of the class TestException throws an exception, hence not allowing the completion of the object? I am almost certain that is the reason.
Nevertheless here is the code for examination:
<?php
/**
* Define a custom exception class
*/
class MyException extends Exception
{
// Redefine the exception so message isn't optional
public function __construct($message, $code = 0, Exception $previous = null) {
// some code
// make sure everything is assigned properly
parent::__construct($message, $code, $previous);
}
// custom string representation of object
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "A custom function for this type of exception\n";
}
}
/**
* Create a class to test the exception
*/
class TestException
{
public $var;
const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;
function __construct($avalue = self::THROW_NONE) {
switch ($avalue) {
case self::THROW_CUSTOM:
// throw custom exception
throw new MyException('1 is an invalid parameter', 5);
break;
case self::THROW_DEFAULT:
// throw default one.
throw new Exception('2 is not allowed as a parameter', 6);
break;
default:
// No exception, object will be created.
$this->var = $avalue;
break;
}
}
}
// Example 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) { // Will be caught
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // Skipped
echo "Caught Default Exception\n", $e;
}
// Continue execution
var_dump($o); // Null
?>
Have a look at PHP exception from PHP official site.
Example:
<?php
class MyException extends Exception { }
class Test {
public function testing() {
try {
try {
throw new MyException('foo!');
} catch (MyException $e) {
/* rethrow it */
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
}
$foo = new Test;
$foo->testing();
?>

Categories