diff options
-rw-r--r-- | src/Http/Exceptions/HttpException.php | 51 | ||||
-rw-r--r-- | src/Middleware/ErrorHandler.php | 21 | ||||
-rw-r--r-- | tests/Unit/Http/Exceptions/HttpExceptionTest.php | 26 | ||||
-rw-r--r-- | tests/Unit/Middleware/ErrorHandlerTest.php | 40 |
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); + } } |