Added a default error handler to handle all uncaught exceptions

This commit is contained in:
Chris Kankiewicz
2020-02-21 18:50:20 -07:00
parent 09ee4e62ac
commit 6d2d214c49
4 changed files with 128 additions and 1 deletions

View File

@@ -51,6 +51,9 @@ class AppManager
'text/json' => '+1 hour',
]));
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler(ErrorHandler::class);
return $app;
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Bootstrap;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\ErrorHandlerInterface;
use Slim\Psr7\Response;
use Slim\Views\Twig;
use Throwable;
class ErrorHandler implements ErrorHandlerInterface
{
/** @const The default error message string */
protected const DEFAULT_ERROR_MESSAGE = 'An unexpected error occured';
/** @var Twig Twig templating component */
protected $view;
/**
* Create a new ErrorHandler object.
*
* @param \Slim\Views\Twig $view
*/
public function __construct(Twig $view)
{
$this->view = $view;
}
/**
* Invoke the ErrorHandler class.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @param \Throwable $exception
* @param bool $displayErrorDetails
* @param bool $logErrors
* @param bool $logErrorDetails
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke(
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
): ResponseInterface {
$response = (new Response)->withStatus(500);
if (in_array('application/json', explode(',', $request->getHeaderLine('Accept')))) {
$response->getBody()->write(json_encode([
'error' => ['message' => self::DEFAULT_ERROR_MESSAGE]
]));
return $response->withHeader('Content-Type', 'application/json');
}
return $this->view->render($response, 'error.twig', [
'message' => self::DEFAULT_ERROR_MESSAGE,
'subtext' => 'Enable debugging for additional information',
]);
}
}

View File

@@ -4,10 +4,14 @@
{% block content %}
{% include 'components/header.twig' %}
<div id="content" class="flex-grow container flex justify-center items-center mx-auto px-4">
<div id="content" class="flex-grow container flex flex-col justify-center items-center mx-auto px-4">
<p class="font-thin text-4xl text-gray-600">
{{ message | default('An unexpected error occured') }}
</p>
<p class="text-lg text-gray-400">
{{ subtext }}
</p>
</div>
{% include 'components/footer.twig' %}

View File

@@ -0,0 +1,57 @@
<?php
namespace Tests\Bootstrap;
use App\Bootstrap\ErrorHandler;
use App\Providers\TwigProvider;
use Exception;
use Slim\Psr7\Request;
use Slim\Views\Twig;
use Tests\TestCase;
class ErrorHandlerTest extends TestCase
{
public function test_it_returns_an_error(): void
{
$this->container->call(TwigProvider::class);
$errorHandler = new ErrorHandler($this->container->get(Twig::class));
$response = $errorHandler(
$this->createMock(Request::class),
new Exception('Test exception; please ignore'),
true,
true,
true
);
$this->assertEquals(500, $response->getStatusCode());
$this->assertEquals('text/html', finfo_buffer(
finfo_open(), (string) $response->getBody(), FILEINFO_MIME_TYPE
));
}
public function test_it_returns_an_error_for_a_json_request(): void
{
$this->container->call(TwigProvider::class);
$errorHandler = new ErrorHandler($this->container->get(Twig::class));
$request = $this->createMock(Request::class);
$request->expects($this->once())->method('getHeaderLine')->willReturn(
'application/json'
);
$response = $errorHandler(
$request,
new Exception('Test exception; please ignore'),
true,
true,
true
);
$this->assertEquals(500, $response->getStatusCode());
$this->assertEquals('application/json', $response->getHeaderLine('Content-Type'));
$this->assertEquals('An unexpected error occured', json_decode(
(string) $response->getBody()
)->error->message);
}
}