Reputation: 1328
Lumen 5.4.
class AfterMiddleware
{
public function handle($request, Closure $next)
{
try {
return $next($request);
} catch (IpValidationException $e) {
return response()->json($e->getMessage(), 422);
} catch (RemoteException $e) {
return response()->json($e->getMessage(), 503);
} catch (BaseException $e) {
return response()->json($e->getMessage(), 400);
} catch (\Exception $e) {
return response()->json($e->getMessage(), $e->getCode());
}
}
}
After the exception is raised, the $next($request)
goes to the following function in Laravel\Lumen\Routing
:
/**
* Get the initial slice to begin the stack call.
*
* @param \Closure $destination
* @return \Closure
*/
protected function prepareDestination(BaseClosure $destination)
{
return function ($passable) use ($destination) {
try {
return call_user_func($destination, $passable);
} catch (Exception $e) {
return $this->handleException($passable, $e);
} catch (Throwable $e) {
return $this->handleException($passable, new FatalThrowableError($e));
}
};
}
And it's catched there, so I my AfterMiddleware
is useless. Any ideas how to circumvent it? I've found a solution and moved all the exceptions to render()
in my Handler
class, but it is much more convienient to use middleware.
Upvotes: 0
Views: 3170
Reputation: 701
This is how I handle mine, its working on Lumen 5.5.* and php 7.1.
Late answer, but hopefully it will helps someone else. 😀
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Illuminate\Http\Exception\HttpResponseException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e)
{
parent::report($e);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
// if (env('APP_DEBUG')) {
// return parent::render($request, $e);
// }
$response = [
'success' => false
];
$response['status'] = null;
if ($e instanceof HttpResponseException) {
$response['status'] = Response::HTTP_INTERNAL_SERVER_ERROR;
} elseif ($e instanceof MethodNotAllowedHttpException) {
$response['status'] = Response::HTTP_METHOD_NOT_ALLOWED;
} elseif ($e instanceof NotFoundHttpException) {
$response['status'] = Response::HTTP_NOT_FOUND;
} elseif ($e instanceof AuthorizationException) {
$response['status'] = Response::HTTP_FORBIDDEN;
$e = new AuthorizationException('HTTP_FORBIDDEN', $response['status']);
} elseif ($e instanceof ValidationException && $e->getResponse()) {
$response['status'] = Response::HTTP_BAD_REQUEST;
$e = new ValidationException('HTTP_BAD_REQUEST', $response['status'], $e);
} elseif ($e instanceof ValidationException) {
$response['status'] = 422;
$response['errors'] = $e->validator->errors();
} elseif ($e instanceof ModelNotFoundException) {
$response['status'] = 404;
} elseif ($e instanceof UnableToExecuteRequestException) {
$response['status'] = $e->getCode();
} elseif ($e instanceof FatalThrowableError) {
$response['status'] = Response::HTTP_INTERNAL_SERVER_ERROR;
} elseif ($e) {
$response['status'] = Response::HTTP_INTERNAL_SERVER_ERROR;
$response['unhandled'] = 'exception-lumen-ksoft';
}
if ($response['status']) {
$response['message'] = $e->getMessage();
$response['error_code'] = $e->getCode() ?? '';
// $response['exception'] = $e->getTraceAsString() ?? '';
if (app()->environment() == 'local'){
$response['file'] = $e->getFile() ?? '';
$response['line'] = $e->getLine() ?? '';
}
return response()->json($response, $response['status']);
} else {
return parent::render($request, $e);
}
}
}
Upvotes: 0
Reputation: 2543
I haven't tried this, but from Lumen's code, I think it is possible.
The handleException
function invoked from prepareDestination
checks if the ExceptionHanlder is bound to the container or not. If it is not, it is throwing the exception.
protected function handleException($passable, Exception $e)
{
if (! $this->container->bound(ExceptionHandler::class) || ! $passable instanceof Request) {
throw $e;
}
$handler = $this->container->make(ExceptionHandler::class);
$handler->report($e);
return $handler->render($passable, $e);
}
So, try by removing the below ExceptionHandler binding from bootstrap/app.php
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
Upvotes: 1