summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Http/Exceptions/HttpException.php51
-rw-r--r--src/Middleware/ErrorHandler.php21
-rw-r--r--tests/Unit/Http/Exceptions/HttpExceptionTest.php26
-rw-r--r--tests/Unit/Middleware/ErrorHandlerTest.php40
4 files changed, 137 insertions, 1 deletions
diff --git a/src/Http/Exceptions/HttpException.php b/src/Http/Exceptions/HttpException.php
new file mode 100644
index 00000000..07853d1e
--- /dev/null
+++ b/src/Http/Exceptions/HttpException.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Engelsystem\Http\Exceptions;
+
+use RuntimeException;
+use Throwable;
+
+class HttpException extends RuntimeException
+{
+ /** @var int */
+ protected $statusCode;
+
+ /** @var array */
+ protected $headers = [];
+
+ /**
+ * @param int $statusCode
+ * @param string $message
+ * @param array $headers
+ * @param int $code
+ * @param Throwable|null $previous
+ */
+ public function __construct(
+ int $statusCode,
+ string $message = '',
+ array $headers = [],
+ int $code = 0,
+ Throwable $previous = null
+ ) {
+ $this->headers = $headers;
+ $this->statusCode = $statusCode;
+
+ parent::__construct($message, $code, $previous);
+ }
+
+ /**
+ * @return array
+ */
+ public function getHeaders(): array
+ {
+ return $this->headers;
+ }
+
+ /**
+ * @return int
+ */
+ public function getStatusCode(): int
+ {
+ return $this->statusCode;
+ }
+} \ No newline at end of file
diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php
index a7c4cfe6..c99ac24f 100644
--- a/src/Middleware/ErrorHandler.php
+++ b/src/Middleware/ErrorHandler.php
@@ -2,6 +2,7 @@
namespace Engelsystem\Middleware;
+use Engelsystem\Http\Exceptions\HttpException;
use Engelsystem\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
@@ -38,7 +39,11 @@ class ErrorHandler implements MiddlewareInterface
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
- $response = $handler->handle($request);
+ try {
+ $response = $handler->handle($request);
+ } catch (HttpException $e) {
+ $response = $this->createResponse($e->getMessage(), $e->getStatusCode(), $e->getHeaders());
+ }
$statusCode = $response->getStatusCode();
if ($statusCode < 400 || !$response instanceof Response) {
@@ -77,4 +82,18 @@ class ErrorHandler implements MiddlewareInterface
return 'default';
}
+
+ /**
+ * Create a new response
+ *
+ * @param string $content
+ * @param int $status
+ * @param array $headers
+ * @return Response
+ * @codeCoverageIgnore
+ */
+ protected function createResponse(string $content = '', int $status = 200, array $headers = [])
+ {
+ return response($content, $status, $headers);
+ }
}
diff --git a/tests/Unit/Http/Exceptions/HttpExceptionTest.php b/tests/Unit/Http/Exceptions/HttpExceptionTest.php
new file mode 100644
index 00000000..ce2b064d
--- /dev/null
+++ b/tests/Unit/Http/Exceptions/HttpExceptionTest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Engelsystem\Test\Unit\Http\Exceptions;
+
+use Engelsystem\Http\Exceptions\HttpException;
+use PHPUnit\Framework\TestCase;
+
+class HttpExceptionTest extends TestCase
+{
+ /**
+ * @covers \Engelsystem\Http\Exceptions\HttpException::__construct
+ * @covers \Engelsystem\Http\Exceptions\HttpException::getStatusCode
+ * @covers \Engelsystem\Http\Exceptions\HttpException::getHeaders
+ */
+ public function testConstruct()
+ {
+ $exception = new HttpException(123);
+ $this->assertEquals(123, $exception->getStatusCode());
+ $this->assertEquals('', $exception->getMessage());
+ $this->assertEquals([], $exception->getHeaders());
+
+ $exception = new HttpException(404, 'Nothing found', ['page' => '/test']);
+ $this->assertEquals('Nothing found', $exception->getMessage());
+ $this->assertEquals(['page' => '/test'], $exception->getHeaders());
+ }
+}
diff --git a/tests/Unit/Middleware/ErrorHandlerTest.php b/tests/Unit/Middleware/ErrorHandlerTest.php
index abf9c52f..c0834591 100644
--- a/tests/Unit/Middleware/ErrorHandlerTest.php
+++ b/tests/Unit/Middleware/ErrorHandlerTest.php
@@ -2,6 +2,7 @@
namespace Engelsystem\Test\Unit\Middleware;
+use Engelsystem\Http\Exceptions\HttpException;
use Engelsystem\Http\Response;
use Engelsystem\Middleware\ErrorHandler;
use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddlewareHandler;
@@ -85,4 +86,43 @@ class ErrorHandlerTest extends TestCase
$errorHandler->process($request, $returnResponseHandler);
$errorHandler->process($request, $returnResponseHandler);
}
+
+ /**
+ * @covers \Engelsystem\Middleware\ErrorHandler::process
+ */
+ public function testProcessException()
+ {
+ /** @var ServerRequestInterface|MockObject $request */
+ $request = $this->createMock(ServerRequestInterface::class);
+ /** @var ResponseInterface|MockObject $psrResponse */
+ $psrResponse = $this->getMockForAbstractClass(ResponseInterface::class);
+ /** @var ReturnResponseMiddlewareHandler|MockObject $returnResponseHandler */
+ $returnResponseHandler = $this->getMockBuilder(ReturnResponseMiddlewareHandler::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $psrResponse->expects($this->once())
+ ->method('getStatusCode')
+ ->willReturn(300);
+
+ $returnResponseHandler->expects($this->once())
+ ->method('handle')
+ ->willReturnCallback(function () {
+ throw new HttpException(300, 'Some response', ['lor' => 'em']);
+ });
+
+ /** @var ErrorHandler|MockObject $errorHandler */
+ $errorHandler = $this->getMockBuilder(ErrorHandler::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['createResponse'])
+ ->getMock();
+
+ $errorHandler->expects($this->once())
+ ->method('createResponse')
+ ->with('Some response', 300, ['lor' => 'em'])
+ ->willReturn($psrResponse);
+
+ $return = $errorHandler->process($request, $returnResponseHandler);
+ $this->assertEquals($psrResponse, $return);
+ }
}