diff --git a/Slim/Handlers/ErrorHandler.php b/Slim/Handlers/ErrorHandler.php index be8ed9e73..4d0607406 100644 --- a/Slim/Handlers/ErrorHandler.php +++ b/Slim/Handlers/ErrorHandler.php @@ -11,6 +11,7 @@ namespace Slim\Handlers; +use http\Env\Response; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -79,6 +80,11 @@ class ErrorHandler implements ErrorHandlerInterface */ protected $request; + /** + * @var ResponseInterface + */ + protected $response; + /** * @var Throwable */ @@ -94,24 +100,11 @@ class ErrorHandler implements ErrorHandlerInterface */ protected $statusCode; - /** - * @var ResponseFactoryInterface - */ - protected $responseFactory; - - /** - * ErrorHandler constructor. - * @param ResponseFactoryInterface $responseFactory - */ - public function __construct(ResponseFactoryInterface $responseFactory) - { - $this->responseFactory = $responseFactory; - } - /** * Invoke error handler * * @param ServerRequestInterface $request The most recent Request object + * @param ResponseInterface $response The most recent Response object * @param Throwable $exception The caught Exception object * @param bool $displayErrorDetails Whether or not to display the error details * @param bool $logErrors Whether or not to log errors @@ -121,6 +114,7 @@ public function __construct(ResponseFactoryInterface $responseFactory) */ public function __invoke( ServerRequestInterface $request, + ResponseInterface $response, Throwable $exception, bool $displayErrorDetails, bool $logErrors, @@ -130,6 +124,7 @@ public function __invoke( $this->logErrors = $logErrors; $this->logErrorDetails = $logErrorDetails; $this->request = $request; + $this->response = $response; $this->exception = $exception; $this->method = $request->getMethod(); $this->statusCode = $this->determineStatusCode(); @@ -253,7 +248,7 @@ protected function determineStatusCode(): int */ protected function respond(): ResponseInterface { - $response = $this->responseFactory->createResponse($this->statusCode); + $response = $this->response->withStatus($this->statusCode); $response = $response->withHeader('Content-type', $this->contentType); if ($this->exception instanceof HttpMethodNotAllowedException) { diff --git a/Slim/Interfaces/ErrorHandlerInterface.php b/Slim/Interfaces/ErrorHandlerInterface.php index 6a78e793c..f8b39a667 100644 --- a/Slim/Interfaces/ErrorHandlerInterface.php +++ b/Slim/Interfaces/ErrorHandlerInterface.php @@ -25,6 +25,7 @@ interface ErrorHandlerInterface { /** * @param ServerRequestInterface $request + * @param ResponseInterface $response * @param Throwable $exception * @param bool $displayErrorDetails * @param bool $logErrors @@ -33,6 +34,7 @@ interface ErrorHandlerInterface */ public function __invoke( ServerRequestInterface $request, + ResponseInterface $response, Throwable $exception, bool $displayErrorDetails, bool $logErrors, diff --git a/Slim/Middleware/ErrorMiddleware.php b/Slim/Middleware/ErrorMiddleware.php index 8f488d949..beb956f96 100644 --- a/Slim/Middleware/ErrorMiddleware.php +++ b/Slim/Middleware/ErrorMiddleware.php @@ -113,8 +113,10 @@ public function handleException(ServerRequestInterface $request, Throwable $exce $exceptionType = get_class($exception); $handler = $this->getErrorHandler($exceptionType); + $response = $this->responseFactory->createResponse($exception->getCode()); $params = [ $request, + $response, $exception, $this->displayErrorDetails, $this->logErrors, @@ -150,7 +152,9 @@ public function getErrorHandler(string $type) * 1. Instance of \Psr\Http\Message\ServerRequestInterface * 2. Instance of \Psr\Http\Message\ResponseInterface * 3. Instance of \Exception - * 4. Boolean displayErrorDetails (optional) + * 4. Boolean displayErrorDetails + * 5. Boolean logErrors + * 6. Boolean logErrorDetails * * The callable MUST return an instance of * \Psr\Http\Message\ResponseInterface. @@ -172,7 +176,9 @@ public function setErrorHandler(string $type, $handler) * 1. Instance of \Psr\Http\Message\ServerRequestInterface * 2. Instance of \Psr\Http\Message\ResponseInterface * 3. Instance of \Exception - * 4. Boolean displayErrorDetails (optional) + * 4. Boolean displayErrorDetails + * 5. Boolean logErrors + * 6. Boolean logErrorDetails * * The callable MUST return an instance of * \Psr\Http\Message\ResponseInterface. @@ -195,6 +201,6 @@ public function getDefaultErrorHandler() return $this->callableResolver->resolve($this->defaultErrorHandler); } - return new ErrorHandler($this->responseFactory); + return new ErrorHandler(); } } diff --git a/tests/Handlers/ErrorHandlerTest.php b/tests/Handlers/ErrorHandlerTest.php index fdeb99318..ea2c6211b 100644 --- a/tests/Handlers/ErrorHandlerTest.php +++ b/tests/Handlers/ErrorHandlerTest.php @@ -97,10 +97,6 @@ public function testDetermineStatusCode() ->getMock(); $class = new ReflectionClass(ErrorHandler::class); - $reflectionProperty = $class->getProperty('responseFactory'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($handler, $this->getResponseFactory()); - $reflectionProperty = $class->getProperty('exception'); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($handler, new HttpNotFoundException($request)); @@ -135,10 +131,6 @@ public function testHalfValidContentType() $class = new ReflectionClass(ErrorHandler::class); - $reflectionProperty = $class->getProperty('responseFactory'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($handler, $this->getResponseFactory()); - $reflectionProperty = $class->getProperty('knownContentTypes'); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($handler, $newTypes); @@ -166,10 +158,6 @@ public function testAcceptableMediaTypeIsNotFirstInList() $method = $class->getMethod('determineContentType'); $method->setAccessible(true); - $reflectionProperty = $class->getProperty('responseFactory'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($class, $this->getResponseFactory()); - // use a mock object here as ErrorHandler cannot be directly instantiated $handler = $this ->getMockBuilder(ErrorHandler::class) @@ -185,12 +173,13 @@ public function testAcceptableMediaTypeIsNotFirstInList() public function testOptions() { $request = $this->createServerRequest('/', 'OPTIONS'); - $handler = new ErrorHandler($this->getResponseFactory()); + $handler = new ErrorHandler(); $exception = new HttpMethodNotAllowedException($request); $exception->setAllowedMethods(['POST', 'PUT']); + $response = $this->getResponseFactory()->createResponse(); /** @var ResponseInterface $res */ - $res = $handler->__invoke($request, $exception, true, true, true); + $res = $handler->__invoke($request, $response, $exception, true, true, true); $this->assertSame(200, $res->getStatusCode()); $this->assertTrue($res->hasHeader('Allow')); @@ -203,8 +192,9 @@ public function testWriteToErrorLog() ->createServerRequest('/', 'GET') ->withHeader('Accept', 'application/json'); + $response = $this->getResponseFactory()->createResponse(); + $handler = $this->getMockBuilder(ErrorHandler::class) - ->setConstructorArgs(['responseFactory' => $this->getResponseFactory()]) ->setMethods(['writeToErrorLog', 'logError']) ->getMock(); @@ -213,6 +203,6 @@ public function testWriteToErrorLog() $handler->expects($this->once()) ->method('writeToErrorLog'); - $handler->__invoke($request, $exception, true, true, true); + $handler->__invoke($request, $response, $exception, true, true, true); } } diff --git a/tests/Middleware/ErrorMiddlewareTest.php b/tests/Middleware/ErrorMiddlewareTest.php index 9761d04b1..91283ce60 100644 --- a/tests/Middleware/ErrorMiddlewareTest.php +++ b/tests/Middleware/ErrorMiddlewareTest.php @@ -10,6 +10,7 @@ use Closure; use Error; +use Throwable; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; @@ -116,7 +117,7 @@ public function testErrorHandlerHandlesThrowables() }; $app->add($mw2); - $handler = function (ServerRequestInterface $request, $exception) { + $handler = function (ServerRequestInterface $request, ResponseInterface $response, Throwable $exception) { $response = $this->createResponse(); $response->getBody()->write($exception->getMessage()); return $response;