diff --git a/composer.json b/composer.json index fb26977..5be45d9 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "psr/http-server-middleware": "^1.0" }, "require-dev": { - "httpsoft/http-request": "^1.0", + "httpsoft/http-server-request": "^1.0", "phpunit/phpunit": "^9.3", "squizlabs/php_codesniffer": "^3.5", "vimeo/psalm": "^3.14" diff --git a/psalm.xml b/psalm.xml index e202c3d..295b545 100644 --- a/psalm.xml +++ b/psalm.xml @@ -14,6 +14,8 @@ + + diff --git a/src/ErrorResponseGenerator.php b/src/ErrorResponseGenerator.php index 14755d2..955fd15 100644 --- a/src/ErrorResponseGenerator.php +++ b/src/ErrorResponseGenerator.php @@ -6,7 +6,6 @@ use HttpSoft\Response\HtmlResponse; use HttpSoft\Response\JsonResponse; -use HttpSoft\Response\ResponseStatusCodeInterface; use HttpSoft\Response\TextResponse; use HttpSoft\Response\XmlResponse; use Psr\Http\Message\ResponseInterface; @@ -21,7 +20,7 @@ use function trim; use function uasort; -final class ErrorResponseGenerator implements ErrorResponseGeneratorInterface, ResponseStatusCodeInterface +final class ErrorResponseGenerator implements ErrorResponseGeneratorInterface { /** * {@inheritDoc} @@ -31,12 +30,12 @@ public function generate(Throwable $error, ServerRequestInterface $request): Res $errorCode = (int) $error->getCode(); $responseCode = self::STATUS_INTERNAL_SERVER_ERROR; - if ($errorCode >= 400 && $errorCode < 600 && array_key_exists($errorCode, self::PHRASES)) { + if (array_key_exists($errorCode, self::ERROR_PHRASES)) { $responseCode = $errorCode; } $requestMimeTypes = $this->getSortedMimeTypesByRequest($request); - return $this->getResponse($responseCode, self::PHRASES[$responseCode], $requestMimeTypes); + return $this->getResponse($responseCode, self::ERROR_PHRASES[$responseCode], $requestMimeTypes); } /** diff --git a/src/ErrorResponseGeneratorInterface.php b/src/ErrorResponseGeneratorInterface.php index 393ab33..a9b06be 100644 --- a/src/ErrorResponseGeneratorInterface.php +++ b/src/ErrorResponseGeneratorInterface.php @@ -4,12 +4,63 @@ namespace HttpSoft\ErrorHandler; +use HttpSoft\Response\ResponseStatusCodeInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Throwable; -interface ErrorResponseGeneratorInterface +interface ErrorResponseGeneratorInterface extends ResponseStatusCodeInterface { + /** + * Map of error HTTP status code and reason phrases. + * + * @link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + */ + public const ERROR_PHRASES = [ + // Client Errors 4xx + self::STATUS_BAD_REQUEST => 'Bad Request', + self::STATUS_UNAUTHORIZED => 'Unauthorized', + self::STATUS_PAYMENT_REQUIRED => 'Payment Required', + self::STATUS_FORBIDDEN => 'Forbidden', + self::STATUS_NOT_FOUND => 'Not Found', + self::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed', + self::STATUS_NOT_ACCEPTABLE => 'Not Acceptable', + self::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required', + self::STATUS_REQUEST_TIMEOUT => 'Request Timeout', + self::STATUS_CONFLICT => 'Conflict', + self::STATUS_GONE => 'Gone', + self::STATUS_LENGTH_REQUIRED => 'Length Required', + self::STATUS_PRECONDITION_FAILED => 'Precondition Failed', + self::STATUS_PAYLOAD_TOO_LARGE => 'Payload Too Large', + self::STATUS_URI_TOO_LONG => 'URI Too Long', + self::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type', + self::STATUS_RANGE_NOT_SATISFIABLE => 'Range Not Satisfiable', + self::STATUS_EXPECTATION_FAILED => 'Expectation Failed', + self::STATUS_IM_A_TEAPOT => 'I\'m a teapot', + self::STATUS_MISDIRECTED_REQUEST => 'Misdirected Request', + self::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', + self::STATUS_LOCKED => 'Locked', + self::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', + self::STATUS_TOO_EARLY => 'Too Early', + self::STATUS_UPGRADE_REQUIRED => 'Upgrade Required', + self::STATUS_PRECONDITION_REQUIRED => 'Precondition Required', + self::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', + self::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', + self::STATUS_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons', + // Server Errors 5xx + self::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error', + self::STATUS_NOT_IMPLEMENTED => 'Not Implemented', + self::STATUS_BAD_GATEWAY => 'Bad Gateway', + self::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable', + self::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout', + self::STATUS_VERSION_NOT_SUPPORTED => 'HTTP Version Not Supported', + self::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates', + self::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', + self::STATUS_LOOP_DETECTED => 'Loop Detected', + self::STATUS_NOT_EXTENDED => 'Not Extended', + self::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', + ]; + /** * Generates an instance of `Psr\Http\Message\ResponseInterface` with information about the handled error. * diff --git a/tests/ErrorHandlerMiddlewareTest.php b/tests/ErrorHandlerMiddlewareTest.php index 5076a0d..4be64d1 100644 --- a/tests/ErrorHandlerMiddlewareTest.php +++ b/tests/ErrorHandlerMiddlewareTest.php @@ -6,7 +6,7 @@ use HttpSoft\ErrorHandler\ErrorHandlerMiddleware; use HttpSoft\ErrorHandler\ErrorResponseGeneratorInterface; -use HttpSoft\Request\ServerRequestFactory; +use HttpSoft\ServerRequest\ServerRequestCreator; use HttpSoft\Response\ResponseStatusCodeInterface; use HttpSoft\Tests\ErrorHandler\TestAsset\ErrorRequestHandler; use HttpSoft\Tests\ErrorHandler\TestAsset\ThrowableRequestHandler; @@ -25,6 +25,8 @@ class ErrorHandlerMiddlewareTest extends TestCase implements ResponseStatusCodeInterface { + private const PHRASES = ErrorResponseGeneratorInterface::ERROR_PHRASES; + /** * @var int */ @@ -43,7 +45,7 @@ class ErrorHandlerMiddlewareTest extends TestCase implements ResponseStatusCodeI public function setUp(): void { $this->errorHandler = new ErrorHandlerMiddleware(); - $this->request = ServerRequestFactory::create(); + $this->request = ServerRequestCreator::create(); $this->errorReporting = error_reporting(); } @@ -57,7 +59,7 @@ public function testWithRequestHandlerAndWithStatusOk(): void $response = $this->errorHandler->process($this->request, $this->createRequestHandler()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); } public function testWithRequestHandlerAndWithStatusCreated(): void @@ -65,7 +67,7 @@ public function testWithRequestHandlerAndWithStatusCreated(): void $response = $this->errorHandler->process($this->request, $this->createRequestHandler(self::STATUS_CREATED)); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_CREATED, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_CREATED], $response->getReasonPhrase()); + $this->assertSame('Created', $response->getReasonPhrase()); } public function testWithRequestHandlerAndWithErrorResponseGeneratorMock(): void @@ -74,7 +76,7 @@ public function testWithRequestHandlerAndWithErrorResponseGeneratorMock(): void $response = $errorHandler->process($this->request, $this->createRequestHandler()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); } public function testWithThrowableRequestHandlerAndWithDefaultError(): void @@ -112,7 +114,7 @@ public function testWithErrorRequestHandlerAndWithoutCaughtError(): void $response = $this->errorHandler->process($this->request, $this->createErrorRequestHandler(E_ERROR)); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); } public function testWithErrorRequestHandlerAndWithCaughtError(): void @@ -134,7 +136,7 @@ public function testWithRequestHandlerAndWithAdditionOfListeners(): void $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); $this->assertFalse($firstListener->triggered()); $this->assertFalse($secondListener->triggered()); diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index d626c3a..194cdf4 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -6,7 +6,7 @@ use HttpSoft\ErrorHandler\ErrorHandler; use HttpSoft\ErrorHandler\ErrorResponseGeneratorInterface; -use HttpSoft\Request\ServerRequestFactory; +use HttpSoft\ServerRequest\ServerRequestCreator; use HttpSoft\Response\ResponseStatusCodeInterface; use HttpSoft\Tests\ErrorHandler\TestAsset\ErrorRequestHandler; use HttpSoft\Tests\ErrorHandler\TestAsset\ThrowableRequestHandler; @@ -25,6 +25,8 @@ class ErrorHandlerTest extends TestCase implements ResponseStatusCodeInterface { + private const PHRASES = ErrorResponseGeneratorInterface::ERROR_PHRASES; + /** * @var int */ @@ -37,7 +39,7 @@ class ErrorHandlerTest extends TestCase implements ResponseStatusCodeInterface public function setUp(): void { - $this->request = ServerRequestFactory::create(); + $this->request = ServerRequestCreator::create(); $this->errorReporting = error_reporting(); } @@ -52,7 +54,7 @@ public function testWithRequestHandlerAndWithStatusOk(): void $response = $errorHandler->handle($this->request); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); } public function testWithRequestHandlerAndWithStatusCreated(): void @@ -61,7 +63,7 @@ public function testWithRequestHandlerAndWithStatusCreated(): void $response = $errorHandler->handle($this->request); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_CREATED, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_CREATED], $response->getReasonPhrase()); + $this->assertSame('Created', $response->getReasonPhrase()); } public function testWithRequestHandlerAndWithErrorResponseGeneratorMock(): void @@ -71,7 +73,7 @@ public function testWithRequestHandlerAndWithErrorResponseGeneratorMock(): void $response = $errorHandler->handle($this->request); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); } public function testWithThrowableRequestHandlerAndWithDefaultError(): void @@ -107,7 +109,7 @@ public function testWithErrorRequestHandlerAndWithoutCaughtError(): void $response = $errorHandler->handle($this->request); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); } public function testWithErrorRequestHandlerAndWithCaughtError(): void @@ -128,7 +130,7 @@ public function testWithRequestHandlerAndWithAdditionOfListeners(): void $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame(self::STATUS_OK, $response->getStatusCode()); - $this->assertSame(self::PHRASES[self::STATUS_OK], $response->getReasonPhrase()); + $this->assertSame('OK', $response->getReasonPhrase()); $this->assertFalse($firstListener->triggered()); $this->assertFalse($secondListener->triggered()); diff --git a/tests/ErrorResponseGeneratorTest.php b/tests/ErrorResponseGeneratorTest.php index 279bac8..37ff34d 100644 --- a/tests/ErrorResponseGeneratorTest.php +++ b/tests/ErrorResponseGeneratorTest.php @@ -6,7 +6,8 @@ use Exception; use HttpSoft\ErrorHandler\ErrorResponseGenerator; -use HttpSoft\Request\ServerRequest; +use HttpSoft\ErrorHandler\ErrorResponseGeneratorInterface; +use HttpSoft\Message\ServerRequest; use HttpSoft\Response\HtmlResponse; use HttpSoft\Response\JsonResponse; use HttpSoft\Response\ResponseStatusCodeInterface; @@ -19,6 +20,8 @@ class ErrorResponseGeneratorTest extends TestCase implements ResponseStatusCodeInterface { + private const PHRASES = ErrorResponseGeneratorInterface::ERROR_PHRASES; + private ErrorResponseGenerator $generator; public function setUp(): void diff --git a/tests/TestAsset/ErrorRequestHandler.php b/tests/TestAsset/ErrorRequestHandler.php index 6f01576..da119b1 100644 --- a/tests/TestAsset/ErrorRequestHandler.php +++ b/tests/TestAsset/ErrorRequestHandler.php @@ -4,7 +4,7 @@ namespace HttpSoft\Tests\ErrorHandler\TestAsset; -use HttpSoft\Response\ResponseFactory; +use HttpSoft\Message\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -21,6 +21,6 @@ public function handle(ServerRequestInterface $request): ResponseInterface { $array = []; $array['undefined']; - return ResponseFactory::create(); + return new Response(); } } diff --git a/tests/TestAsset/RequestHandler.php b/tests/TestAsset/RequestHandler.php index dd28718..77b0853 100644 --- a/tests/TestAsset/RequestHandler.php +++ b/tests/TestAsset/RequestHandler.php @@ -4,7 +4,7 @@ namespace HttpSoft\Tests\ErrorHandler\TestAsset; -use HttpSoft\Response\ResponseFactory; +use HttpSoft\Message\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -30,6 +30,6 @@ public function __construct(int $code = null) */ public function handle(ServerRequestInterface $request): ResponseInterface { - return $this->code ? ResponseFactory::create($this->code) : ResponseFactory::create(); + return $this->code ? new Response($this->code) : new Response(); } }