Skip to content

Instantly share code, notes, and snippets.

@mathieutu
Created April 6, 2018 14:12
Show Gist options
  • Save mathieutu/774fb7c8bd67bc322c0eb0f0bf21e001 to your computer and use it in GitHub Desktop.
Save mathieutu/774fb7c8bd67bc322c0eb0f0bf21e001 to your computer and use it in GitHub Desktop.
Exception Handler Symfony with GuzzleHttp Handling.
<?php
namespace App\Infrastructure\Http;
use Exception;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\KernelInterface;
use Tightenco\Collect\Support\Arr;
class ExceptionHandler implements EventSubscriberInterface
{
private $isDebug;
public function __construct(KernelInterface $kernel)
{
$this->isDebug = $kernel->isDebug();
}
public static function getSubscribedEvents()
{
return [
KernelEvents::EXCEPTION => 'handleException',
];
}
public function handleException(GetResponseForExceptionEvent $event)
{
if ($this->expectsJson($event->getRequest())) {
$event->setResponse($this->prepareJsonResponse($event->getException()));
}
}
private function expectsJson(Request $request): bool
{
return ($request->isXmlHttpRequest() && $this->acceptsAnyContentType($request)) || $this->wantsJson($request);
}
private function acceptsAnyContentType(Request $request): bool
{
$acceptable = $request->getAcceptableContentTypes();
return count($acceptable) === 0
|| (isset($acceptable[0]) && ($acceptable[0] === '*/*' || $acceptable[0] === '*'));
}
private function wantsJson(Request $request): bool
{
$acceptable = $request->getAcceptableContentTypes();
return isset($acceptable[0]) && strpos($acceptable[0], 'json') !== false;
}
private function prepareJsonResponse(Exception $e): JsonResponse
{
$status = $this->getStatusCode($e);
$headers = $this->getHeaders($e);
return (new JsonResponse($this->convertExceptionToArray($e), $status, $headers))
->setEncodingOptions(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
private function convertExceptionToArray(Exception $e): array
{
return $this->isDebug ? [
'message' => $this->getMessage($e),
'exception' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => collect($e->getTrace())->map(function ($trace) {
return Arr::except($trace, ['args']);
})->all(),
] : [
'message' => $this->getMessage($e),
];
}
private function getStatusCode(Exception $e)
{
if ($e instanceof HttpException) {
return $e->getStatusCode();
}
if ($e instanceof RequestException) {
return $e->getResponse()->getStatusCode();
}
return Response::HTTP_INTERNAL_SERVER_ERROR;
}
private function getHeaders(Exception $e)
{
if ($e instanceof HttpException) {
return $e->getHeaders();
}
if ($e instanceof RequestException) {
return $e->getResponse()->getHeaders();
}
return [];
}
private function getMessage(Exception $e)
{
if ($e instanceof RequestException) {
if ($e->hasResponse() && $response = json_decode($e->getResponse()->getBody(), true)) {
return $response['message'] ?? $response;
}
return RequestException::getResponseBodySummary($e->getResponse());
}
if ($e instanceof HttpException || $this->isDebug) {
return $e->getMessage();
}
return 'Server Error';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment