From b89d1a527f2f478875bd17d791810e9a7ef5340b Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Tue, 9 Sep 2025 15:00:15 +0700 Subject: [PATCH 1/7] #121: Make logger in ErrorHandler optional #144: Mark ErrorException and UserException as final #146: Remove deprecated Yiisoft\ErrorHandler\Factory\ThrowableResponseFactory rename ThrowableResponseFactory to ThrowableResponseAction change parameters order in ThrowableResponseActionInterface --- config/di-web.php | 26 +- src/ErrorHandler.php | 6 +- src/Exception/ErrorException.php | 2 +- src/Exception/UserException.php | 2 +- src/Factory/ThrowableResponseFactory.php | 190 ------------- src/Middleware/ErrorCatcher.php | 8 +- ...actory.php => ThrowableResponseAction.php} | 11 +- ...p => ThrowableResponseActionInterface.php} | 6 +- tests/ErrorHandlerTest.php | 5 +- .../Factory/ThrowableResponseFactoryTest.php | 258 ------------------ tests/Middleware/ErrorCatcherTest.php | 14 +- ...st.php => ThrowableResponseActionTest.php} | 26 +- 12 files changed, 59 insertions(+), 495 deletions(-) delete mode 100644 src/Factory/ThrowableResponseFactory.php rename src/{ThrowableResponseFactory.php => ThrowableResponseAction.php} (68%) rename src/{ThrowableResponseFactoryInterface.php => ThrowableResponseActionInterface.php} (52%) delete mode 100644 tests/Factory/ThrowableResponseFactoryTest.php rename tests/{ThrowableResponseFactoryTest.php => ThrowableResponseActionTest.php} (75%) diff --git a/config/di-web.php b/config/di-web.php index b6bc5d6..7e8aa8b 100644 --- a/config/di-web.php +++ b/config/di-web.php @@ -2,10 +2,16 @@ declare(strict_types=1); -use Yiisoft\ErrorHandler\Factory\ThrowableResponseFactory; +use Psr\Container\ContainerInterface; +use Yiisoft\Definitions\DynamicReference; +use Yiisoft\Definitions\Reference; +use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; +use Yiisoft\ErrorHandler\RendererProvider\CompositeRendererProvider; +use Yiisoft\ErrorHandler\RendererProvider\ContentTypeRendererProvider; +use Yiisoft\ErrorHandler\RendererProvider\HeadRendererProvider; use Yiisoft\ErrorHandler\ThrowableRendererInterface; -use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; +use Yiisoft\ErrorHandler\ThrowableResponseAction; /** * @var array $params @@ -13,5 +19,19 @@ return [ ThrowableRendererInterface::class => HtmlRenderer::class, - ThrowableResponseFactoryInterface::class => ThrowableResponseFactory::class, + ErrorCatcher::class => [ + '__construct()' => [ + 'throwableResponseAction' => Reference::to(ThrowableResponseAction::class), + ], + ], + ThrowableResponseAction::class => [ + '__construct()' => [ + 'rendererProvider' => DynamicReference::to( + static fn(ContainerInterface $container) => new CompositeRendererProvider( + new HeadRendererProvider(), + new ContentTypeRendererProvider($container), + ) + ), + ], + ], ]; diff --git a/src/ErrorHandler.php b/src/ErrorHandler.php index f9c4aa0..c21e97c 100644 --- a/src/ErrorHandler.php +++ b/src/ErrorHandler.php @@ -41,14 +41,14 @@ final class ErrorHandler private bool $initialized = false; /** - * @param LoggerInterface $logger Logger to write errors to. * @param ThrowableRendererInterface $defaultRenderer Default throwable renderer. + * @param LoggerInterface|null $logger Logger to write errors to. * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events. * @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last. */ public function __construct( - private readonly LoggerInterface $logger, private readonly ThrowableRendererInterface $defaultRenderer, + private readonly ?LoggerInterface $logger = null, private readonly ?EventDispatcherInterface $eventDispatcher = null, private readonly int $exitShutdownHandlerDepth = 2 ) { @@ -68,7 +68,7 @@ public function handle( $renderer ??= $this->defaultRenderer; try { - $this->logger->error($t->getMessage(), ['throwable' => $t]); + $this->logger?->error($t->getMessage(), ['throwable' => $t]); return $this->debug ? $renderer->renderVerbose($t, $request) : $renderer->render($t, $request); } catch (Throwable $t) { return new ErrorData((string) $t); diff --git a/src/Exception/ErrorException.php b/src/Exception/ErrorException.php index 5f61d77..b2f88dc 100644 --- a/src/Exception/ErrorException.php +++ b/src/Exception/ErrorException.php @@ -18,7 +18,7 @@ * * @final */ -class ErrorException extends \ErrorException implements FriendlyExceptionInterface +final class ErrorException extends \ErrorException implements FriendlyExceptionInterface { /** @psalm-suppress MissingClassConstType Private constants never change. */ private const ERROR_NAMES = [ diff --git a/src/Exception/UserException.php b/src/Exception/UserException.php index 8c78b1e..63d253a 100644 --- a/src/Exception/UserException.php +++ b/src/Exception/UserException.php @@ -23,7 +23,7 @@ * @final */ #[Attribute(Attribute::TARGET_CLASS)] -class UserException extends Exception +final class UserException extends Exception { public static function isUserException(Throwable $throwable): bool { diff --git a/src/Factory/ThrowableResponseFactory.php b/src/Factory/ThrowableResponseFactory.php deleted file mode 100644 index 6a16c1b..0000000 --- a/src/Factory/ThrowableResponseFactory.php +++ /dev/null @@ -1,190 +0,0 @@ -> - */ - private array $renderers = [ - 'application/json' => JsonRenderer::class, - 'application/xml' => XmlRenderer::class, - 'text/xml' => XmlRenderer::class, - 'text/plain' => PlainTextRenderer::class, - 'text/html' => HtmlRenderer::class, - '*/*' => HtmlRenderer::class, - ]; - private ?string $contentType = null; - - public function __construct( - private readonly ResponseFactoryInterface $responseFactory, - private readonly ErrorHandler $errorHandler, - private readonly ContainerInterface $container, - ?HeadersProvider $headersProvider = null, - ) { - $this->headersProvider = $headersProvider ?? new HeadersProvider(); - } - - public function create(Throwable $throwable, ServerRequestInterface $request): ResponseInterface - { - $contentType = $this->contentType ?? $this->getContentType($request); - $renderer = $request->getMethod() === Method::HEAD ? new HeaderRenderer() : $this->getRenderer($contentType); - - $data = $this->errorHandler->handle($throwable, $renderer, $request); - $response = $this->responseFactory->createResponse(Status::INTERNAL_SERVER_ERROR); - foreach ($this->headersProvider->getAll() as $name => $value) { - $response = $response->withHeader($name, $value); - } - return $data->addToResponse($response->withHeader(Header::CONTENT_TYPE, $contentType)); - } - - /** - * Returns a new instance with the specified content type and renderer class. - * - * @param string $contentType The content type to add associated renderers for. - * @param string $rendererClass The classname implementing the {@see ThrowableRendererInterface}. - */ - public function withRenderer(string $contentType, string $rendererClass): self - { - if (!is_subclass_of($rendererClass, ThrowableRendererInterface::class)) { - throw new InvalidArgumentException(sprintf( - 'Class "%s" does not implement "%s".', - $rendererClass, - ThrowableRendererInterface::class, - )); - } - - $new = clone $this; - $new->renderers[$this->normalizeContentType($contentType)] = $rendererClass; - return $new; - } - - /** - * Returns a new instance without renderers by the specified content types. - * - * @param string[] $contentTypes The content types to remove associated renderers for. - * If not specified, all renderers will be removed. - */ - public function withoutRenderers(string ...$contentTypes): self - { - $new = clone $this; - - if (count($contentTypes) === 0) { - $new->renderers = []; - return $new; - } - - foreach ($contentTypes as $contentType) { - unset($new->renderers[$this->normalizeContentType($contentType)]); - } - - return $new; - } - - /** - * Force content type to respond with regardless of request. - * - * @param string $contentType The content type to respond with regardless of request. - */ - public function forceContentType(string $contentType): self - { - $contentType = $this->normalizeContentType($contentType); - - if (!isset($this->renderers[$contentType])) { - throw new InvalidArgumentException(sprintf('The renderer for %s is not set.', $contentType)); - } - - $new = clone $this; - $new->contentType = $contentType; - return $new; - } - - /** - * Returns the renderer by the specified content type, or null if the renderer was not set. - * - * @param string $contentType The content type associated with the renderer. - */ - private function getRenderer(string $contentType): ?ThrowableRendererInterface - { - if (isset($this->renderers[$contentType])) { - /** @var ThrowableRendererInterface */ - return $this->container->get($this->renderers[$contentType]); - } - - return null; - } - - /** - * Returns the priority content type from the accept request header. - * - * @return string The priority content type. - */ - private function getContentType(ServerRequestInterface $request): string - { - try { - foreach (HeaderValueHelper::getSortedAcceptTypes($request->getHeader(Header::ACCEPT)) as $header) { - if (array_key_exists($header, $this->renderers)) { - return $header; - } - } - } catch (InvalidArgumentException) { - // The Accept header contains an invalid q factor. - } - - return '*/*'; - } - - /** - * Normalizes the content type. - * - * @param string $contentType The raw content type. - * - * @return string Normalized content type. - */ - private function normalizeContentType(string $contentType): string - { - if (!str_contains($contentType, '/')) { - throw new InvalidArgumentException('Invalid content type.'); - } - - return strtolower(trim($contentType)); - } -} diff --git a/src/Middleware/ErrorCatcher.php b/src/Middleware/ErrorCatcher.php index 097e3da..c220f4f 100644 --- a/src/Middleware/ErrorCatcher.php +++ b/src/Middleware/ErrorCatcher.php @@ -12,16 +12,16 @@ use Psr\Http\Server\RequestHandlerInterface; use Yiisoft\ErrorHandler\CompositeException; use Yiisoft\ErrorHandler\Event\ApplicationError; -use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; +use Yiisoft\ErrorHandler\ThrowableResponseActionInterface; /** * `ErrorCatcher` catches all throwables from the next middlewares - * and renders it with a handler that implements the `ThrowableResponseFactoryInterface`. + * and renders it with a handler that implements the `ThrowableResponseActionInterface`. */ final class ErrorCatcher implements MiddlewareInterface { public function __construct( - private readonly ThrowableResponseFactoryInterface $throwableResponseFactory, + private readonly ThrowableResponseActionInterface $throwableResponseAction, private readonly ?EventDispatcherInterface $eventDispatcher = null, ) { } @@ -37,7 +37,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $t = new CompositeException($e, $t); } - return $this->throwableResponseFactory->create($t, $request); + return $this->throwableResponseAction->handle($request, $t); } } } diff --git a/src/ThrowableResponseFactory.php b/src/ThrowableResponseAction.php similarity index 68% rename from src/ThrowableResponseFactory.php rename to src/ThrowableResponseAction.php index 7e69099..367696b 100644 --- a/src/ThrowableResponseFactory.php +++ b/src/ThrowableResponseAction.php @@ -12,22 +12,19 @@ use Yiisoft\Http\Status; /** - * `ThrowableResponseFactory` produces a response with rendered `Throwable` object. + * `ThrowableResponseAction` produces a response with rendered `Throwable` object. */ -final class ThrowableResponseFactory implements ThrowableResponseFactoryInterface +final class ThrowableResponseAction implements ThrowableResponseActionInterface { - private readonly HeadersProvider $headersProvider; - public function __construct( private readonly ResponseFactoryInterface $responseFactory, private readonly ErrorHandler $errorHandler, private readonly RendererProviderInterface $rendererProvider, - ?HeadersProvider $headersProvider = null, + private readonly HeadersProvider $headersProvider = new HeadersProvider(), ) { - $this->headersProvider = $headersProvider ?? new HeadersProvider(); } - public function create(Throwable $throwable, ServerRequestInterface $request): ResponseInterface + public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface { $renderer = $this->rendererProvider->get($request); diff --git a/src/ThrowableResponseFactoryInterface.php b/src/ThrowableResponseActionInterface.php similarity index 52% rename from src/ThrowableResponseFactoryInterface.php rename to src/ThrowableResponseActionInterface.php index 1a16cb9..061e822 100644 --- a/src/ThrowableResponseFactoryInterface.php +++ b/src/ThrowableResponseActionInterface.php @@ -9,12 +9,12 @@ use Psr\Http\Message\ServerRequestInterface; /** - * `ThrowableResponseFactoryInterface` produces a response for `Throwable` object. + * `ThrowableResponseActionInterface` produces a response for `Throwable` object. */ -interface ThrowableResponseFactoryInterface +interface ThrowableResponseActionInterface { /** * Handles a `Throwable` object and produces a response. */ - public function create(Throwable $throwable, ServerRequestInterface $request): ResponseInterface; + public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface; } diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index a315bb5..ef2eb76 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\Attributes\WithoutErrorHandler; use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; use RuntimeException; use Throwable; use Yiisoft\ErrorHandler\ErrorHandler; @@ -16,14 +15,12 @@ final class ErrorHandlerTest extends TestCase { private ErrorHandler $errorHandler; - private LoggerInterface $loggerMock; private ThrowableRendererInterface $throwableRendererMock; protected function setUp(): void { - $this->loggerMock = $this->createMock(LoggerInterface::class); $this->throwableRendererMock = $this->createMock(ThrowableRendererInterface::class); - $this->errorHandler = new ErrorHandler($this->loggerMock, $this->throwableRendererMock); + $this->errorHandler = new ErrorHandler($this->throwableRendererMock); $this->errorHandler->memoryReserveSize(0); } diff --git a/tests/Factory/ThrowableResponseFactoryTest.php b/tests/Factory/ThrowableResponseFactoryTest.php deleted file mode 100644 index 0c9ae08..0000000 --- a/tests/Factory/ThrowableResponseFactoryTest.php +++ /dev/null @@ -1,258 +0,0 @@ -createThrowableResponseFactory() - ->create( - $this->createThrowable(), - $this->createServerRequest('HEAD', ['Accept' => ['test/html']]) - ); - $response->getBody()->rewind(); - $content = $response->getBody()->getContents(); - - $this->assertEmpty($content); - $this->assertSame([HeaderRenderer::DEFAULT_ERROR_MESSAGE], $response->getHeader('X-Error-Message')); - } - - public function testHandleWithFailAcceptRequestHeader(): void - { - $response = $this - ->createThrowableResponseFactory() - ->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['text/plain;q=2.0']]) - ); - $response - ->getBody() - ->rewind(); - $content = $response - ->getBody() - ->getContents(); - - $this->assertNotSame(PlainTextRenderer::DEFAULT_ERROR_MESSAGE, $content); - $this->assertStringContainsString('createThrowableResponseFactory() - ->withRenderer($mimeType, PlainTextRenderer::class); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => [$mimeType]]) - ); - $response - ->getBody() - ->rewind(); - $content = $response - ->getBody() - ->getContents(); - - $this->assertSame(PlainTextRenderer::DEFAULT_ERROR_MESSAGE, $content); - } - - public function testThrownExceptionWithRendererIsNotImplementThrowableRendererInterface() - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( - 'Class "' . self::class . '" does not implement "' . ThrowableRendererInterface::class . '".', - ); - $this - ->createThrowableResponseFactory() - ->withRenderer('test/test', self::class); - } - - public function testThrownExceptionWithInvalidContentType() - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid content type.'); - $this - ->createThrowableResponseFactory() - ->withRenderer('test invalid content type', PlainTextRenderer::class); - } - - public function testWithoutRenderers(): void - { - $factory = $this - ->createThrowableResponseFactory() - ->withoutRenderers(); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['test/html']]) - ); - $response - ->getBody() - ->rewind(); - $content = $response - ->getBody() - ->getContents(); - - $this->assertSame(PlainTextRenderer::DEFAULT_ERROR_MESSAGE, $content); - } - - public function testWithoutRenderer(): void - { - $factory = $this - ->createThrowableResponseFactory() - ->withoutRenderers('*/*'); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['test/html']]) - ); - $response - ->getBody() - ->rewind(); - $content = $response - ->getBody() - ->getContents(); - - $this->assertSame(PlainTextRenderer::DEFAULT_ERROR_MESSAGE, $content); - } - - public function testAdvancedAcceptHeader(): void - { - $contentType = 'text/html;version=2'; - $factory = $this - ->createThrowableResponseFactory() - ->withRenderer($contentType, PlainTextRenderer::class); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['text/html', $contentType]]) - ); - $response - ->getBody() - ->rewind(); - $content = $response - ->getBody() - ->getContents(); - - $this->assertSame(PlainTextRenderer::DEFAULT_ERROR_MESSAGE, $content); - } - - public function testDefaultContentType(): void - { - $factory = $this - ->createThrowableResponseFactory() - ->withRenderer('*/*', PlainTextRenderer::class); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['test/test']]) - ); - $response - ->getBody() - ->rewind(); - $content = $response - ->getBody() - ->getContents(); - - $this->assertSame(PlainTextRenderer::DEFAULT_ERROR_MESSAGE, $content); - } - - public function testForceContentType(): void - { - $factory = $this - ->createThrowableResponseFactory() - ->forceContentType('application/json'); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['text/xml']]) - ); - $response - ->getBody() - ->rewind(); - - $this->assertSame('application/json', $response->getHeaderLine(Header::CONTENT_TYPE)); - } - - public function testForceContentTypeSetInvalidType(): void - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The renderer for image/gif is not set.'); - $this - ->createThrowableResponseFactory() - ->forceContentType('image/gif'); - } - - public function testAddedHeaders(): void - { - $provider = new HeadersProvider([ - 'X-Default' => 'default', - 'Content-Type' => 'incorrect', - ]); - $provider->add('X-Test', 'test'); - $provider->add('X-Test2', ['test2', 'test3']); - $factory = $this - ->createThrowableResponseFactory(provider: $provider) - ->withRenderer('*/*', PlainTextRenderer::class); - $response = $factory->create( - $this->createThrowable(), - $this->createServerRequest('GET', ['Accept' => ['test/test']]) - ); - $headers = $response->getHeaders(); - - $this->assertArrayHasKey('Content-Type', $headers); - $this->assertNotEquals('incorrect', $headers['Content-Type']); - - $this->assertArrayHasKey('X-Default', $headers); - $this->assertEquals(['default'], $headers['X-Default']); - $this->assertArrayHasKey('X-Test', $headers); - $this->assertEquals(['test'], $headers['X-Test']); - $this->assertArrayHasKey('X-Test2', $headers); - $this->assertEquals(['test2', 'test3'], $headers['X-Test2']); - } - - private function createThrowableResponseFactory( - ?HeadersProvider $provider = null, - ): ThrowableResponseFactoryInterface { - $container = new SimpleContainer([], fn (string $className): object => new $className()); - return new ThrowableResponseFactory( - new ResponseFactory(), - $this->createErrorHandler(), - $container, - $provider ?? new HeadersProvider() - ); - } - - private function createErrorHandler(): ErrorHandler - { - $logger = $this->createMock(LoggerInterface::class); - return new ErrorHandler($logger, new PlainTextRenderer()); - } - - private function createServerRequest(string $method, array $headers = []): ServerRequestInterface - { - return new ServerRequest([], [], [], [], [], $method, '/', $headers); - } - - private function createThrowable(): Throwable - { - return new RuntimeException(); - } -} diff --git a/tests/Middleware/ErrorCatcherTest.php b/tests/Middleware/ErrorCatcherTest.php index e274aa8..a9f8405 100644 --- a/tests/Middleware/ErrorCatcherTest.php +++ b/tests/Middleware/ErrorCatcherTest.php @@ -14,7 +14,7 @@ use RuntimeException; use Throwable; use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; -use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; +use Yiisoft\ErrorHandler\ThrowableResponseActionInterface; use Yiisoft\Http\Status; final class ErrorCatcherTest extends TestCase @@ -22,7 +22,7 @@ final class ErrorCatcherTest extends TestCase public function testSuccess(): void { $errorCatcher = new ErrorCatcher( - $this->createThrowableResponseFactory(), + $this->createThrowableResponseAction(), ); $handler = new class () implements RequestHandlerInterface { public function handle(ServerRequestInterface $request): ResponseInterface @@ -41,7 +41,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface public function testError(): void { $errorCatcher = new ErrorCatcher( - $this->createThrowableResponseFactory(), + $this->createThrowableResponseAction(), ); $response = $errorCatcher->process( new ServerRequest(), @@ -56,7 +56,7 @@ public function testErrorWithEventDispatcher(): void $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $eventDispatcher->method('dispatch')->willThrowException(new RuntimeException('Event dispatcher error')); $errorCatcher = new ErrorCatcher( - $this->createThrowableResponseFactory(), + $this->createThrowableResponseAction(), $eventDispatcher, ); $response = $errorCatcher->process( @@ -66,10 +66,10 @@ public function testErrorWithEventDispatcher(): void $this->assertSame(Status::INTERNAL_SERVER_ERROR, $response->getStatusCode()); } - private function createThrowableResponseFactory(): ThrowableResponseFactoryInterface + private function createThrowableResponseAction(): ThrowableResponseActionInterface { - return new class () implements ThrowableResponseFactoryInterface { - public function create(Throwable $throwable, ServerRequestInterface $request): ResponseInterface + return new class () implements ThrowableResponseActionInterface { + public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface { return new Response(Status::INTERNAL_SERVER_ERROR); } diff --git a/tests/ThrowableResponseFactoryTest.php b/tests/ThrowableResponseActionTest.php similarity index 75% rename from tests/ThrowableResponseFactoryTest.php rename to tests/ThrowableResponseActionTest.php index ed5d045..c9a7cc4 100644 --- a/tests/ThrowableResponseFactoryTest.php +++ b/tests/ThrowableResponseActionTest.php @@ -14,20 +14,19 @@ use Yiisoft\ErrorHandler\RendererProvider\ContentTypeRendererProvider; use Yiisoft\ErrorHandler\Tests\Support\TestHelper; use Yiisoft\ErrorHandler\ThrowableRendererInterface; -use Yiisoft\ErrorHandler\ThrowableResponseFactory; +use Yiisoft\ErrorHandler\ThrowableResponseAction; use Yiisoft\Test\Support\Container\SimpleContainer; use function PHPUnit\Framework\assertSame; use function PHPUnit\Framework\assertTrue; -final class ThrowableResponseFactoryTest extends TestCase +final class ThrowableResponseActionTest extends TestCase { public function testBase(): void { - $factory = new ThrowableResponseFactory( + $action = new ThrowableResponseAction( new ResponseFactory(), new ErrorHandler( - new NullLogger(), new PlainTextRenderer(), ), new ContentTypeRendererProvider( @@ -35,10 +34,10 @@ public function testBase(): void ), ); - $response = $factory->create( - new LogicException('test message'), - TestHelper::createRequest(), - ); + $response = $action->handle( + TestHelper::createRequest(), + new LogicException('test message') + ); assertSame(500, $response->getStatusCode()); assertSame(ThrowableRendererInterface::DEFAULT_ERROR_MESSAGE, TestHelper::getResponseContent($response)); @@ -46,10 +45,9 @@ public function testBase(): void public function testHeaders(): void { - $factory = new ThrowableResponseFactory( + $action = new ThrowableResponseAction( new ResponseFactory(), new ErrorHandler( - new NullLogger(), new PlainTextRenderer(), ), new ContentTypeRendererProvider( @@ -58,10 +56,10 @@ public function testHeaders(): void new HeadersProvider(['X-Test' => ['on'], 'X-Test-Custom' => 'hello']) ); - $response = $factory->create( - new LogicException('test message'), - TestHelper::createRequest(), - ); + $response = $action->handle( + TestHelper::createRequest(), + new LogicException('test message') + ); assertTrue($response->hasHeader('X-Test')); assertSame('on', $response->getHeaderLine('X-Test')); From 272c8854fc97d2f465f5222f348dc8e890eb331f Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Tue, 9 Sep 2025 15:07:12 +0700 Subject: [PATCH 2/7] update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f55575d..3ade5b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Yii Error Handler Change Log +## 5.0 under development + +- Chg #121: Make logger in ErrorHandler optional (@olegbaturin) +- Chg #144: Mark ErrorException and UserException as final (@olegbaturin) +- Chg #146: Remove deprecated `Yiisoft\ErrorHandler\Factory\ThrowableResponseFactory` (@olegbaturin) +- Chg #157: Rename `Yiisoft\ErrorHandler\ThrowableResponseFactory` to `Yiisoft\ErrorHandler\ThrowableResponseAction` (@olegbaturin) +- Chg #157: Change parameters order in `ThrowableResponseActionInterface` (@olegbaturin) + ## 4.3.1 under development - no changes in this release. From b71c00d25c0851fd47d46aa8f210771c14804431 Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Tue, 9 Sep 2025 15:08:47 +0700 Subject: [PATCH 3/7] fix style --- tests/ThrowableResponseActionTest.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/ThrowableResponseActionTest.php b/tests/ThrowableResponseActionTest.php index c9a7cc4..4a47a87 100644 --- a/tests/ThrowableResponseActionTest.php +++ b/tests/ThrowableResponseActionTest.php @@ -7,7 +7,6 @@ use HttpSoft\Message\ResponseFactory; use LogicException; use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; use Yiisoft\ErrorHandler\ErrorHandler; use Yiisoft\ErrorHandler\HeadersProvider; use Yiisoft\ErrorHandler\Renderer\PlainTextRenderer; @@ -35,9 +34,9 @@ public function testBase(): void ); $response = $action->handle( - TestHelper::createRequest(), - new LogicException('test message') - ); + TestHelper::createRequest(), + new LogicException('test message') + ); assertSame(500, $response->getStatusCode()); assertSame(ThrowableRendererInterface::DEFAULT_ERROR_MESSAGE, TestHelper::getResponseContent($response)); @@ -57,9 +56,9 @@ public function testHeaders(): void ); $response = $action->handle( - TestHelper::createRequest(), - new LogicException('test message') - ); + TestHelper::createRequest(), + new LogicException('test message') + ); assertTrue($response->hasHeader('X-Test')); assertSame('on', $response->getHeaderLine('X-Test')); From 6f7c6ca734bbf9066d1ffe30dcbb44cbfe376d47 Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Tue, 9 Sep 2025 16:27:14 +0700 Subject: [PATCH 4/7] fix exceptions --- src/Exception/ErrorException.php | 2 -- src/Exception/UserException.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Exception/ErrorException.php b/src/Exception/ErrorException.php index b2f88dc..efc0612 100644 --- a/src/Exception/ErrorException.php +++ b/src/Exception/ErrorException.php @@ -15,8 +15,6 @@ /** * `ErrorException` represents a PHP error. * @psalm-type DebugBacktraceType = list, class?: class-string, file?: string, function?: string, line?: int, object?: object, type?: string}> - * - * @final */ final class ErrorException extends \ErrorException implements FriendlyExceptionInterface { diff --git a/src/Exception/UserException.php b/src/Exception/UserException.php index 63d253a..bd2f9fc 100644 --- a/src/Exception/UserException.php +++ b/src/Exception/UserException.php @@ -19,8 +19,6 @@ * - throw directly (`throw new UserException(...)`) for explicit user-facing errors; * - annotate any exception class with the `#[UserException]` attribute * to mark its messages as user-facing without extending this class. - * - * @final */ #[Attribute(Attribute::TARGET_CLASS)] final class UserException extends Exception From 714e586cee3de65987ef48ba83bbefdf64426854 Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Tue, 16 Sep 2025 16:07:41 +0700 Subject: [PATCH 5/7] rename ThrowableResponseFactory use NullLogger as default logger --- CHANGELOG.md | 7 +++---- config/di-web.php | 13 ++++-------- src/ErrorHandler.php | 7 ++++--- src/Middleware/ErrorCatcher.php | 8 +++---- ...ction.php => ThrowableResponseFactory.php} | 4 ++-- ... => ThrowableResponseFactoryInterface.php} | 4 ++-- tests/ConfigTest.php | 15 +++++++++---- tests/ErrorHandlerTest.php | 21 +++++++++++++++++-- tests/Middleware/ErrorCatcherTest.php | 12 +++++------ ...t.php => ThrowableResponseFactoryTest.php} | 10 ++++----- 10 files changed, 60 insertions(+), 41 deletions(-) rename src/{ThrowableResponseAction.php => ThrowableResponseFactory.php} (87%) rename src/{ThrowableResponseActionInterface.php => ThrowableResponseFactoryInterface.php} (73%) rename tests/{ThrowableResponseActionTest.php => ThrowableResponseFactoryTest.php} (90%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ade5b6..4028f5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,10 @@ ## 5.0 under development -- Chg #121: Make logger in ErrorHandler optional (@olegbaturin) -- Chg #144: Mark ErrorException and UserException as final (@olegbaturin) +- Chg #121: Use `NullLogger` as the default logger in the `ErrorHandler` (@olegbaturin) +- Chg #144: Mark `ErrorException` and `UserException` as final (@olegbaturin) - Chg #146: Remove deprecated `Yiisoft\ErrorHandler\Factory\ThrowableResponseFactory` (@olegbaturin) -- Chg #157: Rename `Yiisoft\ErrorHandler\ThrowableResponseFactory` to `Yiisoft\ErrorHandler\ThrowableResponseAction` (@olegbaturin) -- Chg #157: Change parameters order in `ThrowableResponseActionInterface` (@olegbaturin) +- Chg #157: Change parameters order in the `ThrowableResponseActionInterface` (@olegbaturin) ## 4.3.1 under development diff --git a/config/di-web.php b/config/di-web.php index 7e8aa8b..241673c 100644 --- a/config/di-web.php +++ b/config/di-web.php @@ -4,14 +4,13 @@ use Psr\Container\ContainerInterface; use Yiisoft\Definitions\DynamicReference; -use Yiisoft\Definitions\Reference; -use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; use Yiisoft\ErrorHandler\RendererProvider\CompositeRendererProvider; use Yiisoft\ErrorHandler\RendererProvider\ContentTypeRendererProvider; use Yiisoft\ErrorHandler\RendererProvider\HeadRendererProvider; use Yiisoft\ErrorHandler\ThrowableRendererInterface; -use Yiisoft\ErrorHandler\ThrowableResponseAction; +use Yiisoft\ErrorHandler\ThrowableResponseFactory; +use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; /** * @var array $params @@ -19,12 +18,8 @@ return [ ThrowableRendererInterface::class => HtmlRenderer::class, - ErrorCatcher::class => [ - '__construct()' => [ - 'throwableResponseAction' => Reference::to(ThrowableResponseAction::class), - ], - ], - ThrowableResponseAction::class => [ + ThrowableResponseFactoryInterface::class => ThrowableResponseFactory::class, + ThrowableResponseFactory::class => [ '__construct()' => [ 'rendererProvider' => DynamicReference::to( static fn(ContainerInterface $container) => new CompositeRendererProvider( diff --git a/src/ErrorHandler.php b/src/ErrorHandler.php index c21e97c..e862099 100644 --- a/src/ErrorHandler.php +++ b/src/ErrorHandler.php @@ -7,6 +7,7 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use Throwable; use Yiisoft\ErrorHandler\Event\ApplicationError; use Yiisoft\ErrorHandler\Exception\ErrorException; @@ -42,13 +43,13 @@ final class ErrorHandler /** * @param ThrowableRendererInterface $defaultRenderer Default throwable renderer. - * @param LoggerInterface|null $logger Logger to write errors to. + * @param LoggerInterface $logger Logger to write errors to. * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events. * @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last. */ public function __construct( private readonly ThrowableRendererInterface $defaultRenderer, - private readonly ?LoggerInterface $logger = null, + private readonly LoggerInterface $logger = new NullLogger(), private readonly ?EventDispatcherInterface $eventDispatcher = null, private readonly int $exitShutdownHandlerDepth = 2 ) { @@ -68,7 +69,7 @@ public function handle( $renderer ??= $this->defaultRenderer; try { - $this->logger?->error($t->getMessage(), ['throwable' => $t]); + $this->logger->error($t->getMessage(), ['throwable' => $t]); return $this->debug ? $renderer->renderVerbose($t, $request) : $renderer->render($t, $request); } catch (Throwable $t) { return new ErrorData((string) $t); diff --git a/src/Middleware/ErrorCatcher.php b/src/Middleware/ErrorCatcher.php index c220f4f..f264774 100644 --- a/src/Middleware/ErrorCatcher.php +++ b/src/Middleware/ErrorCatcher.php @@ -12,16 +12,16 @@ use Psr\Http\Server\RequestHandlerInterface; use Yiisoft\ErrorHandler\CompositeException; use Yiisoft\ErrorHandler\Event\ApplicationError; -use Yiisoft\ErrorHandler\ThrowableResponseActionInterface; +use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; /** * `ErrorCatcher` catches all throwables from the next middlewares - * and renders it with a handler that implements the `ThrowableResponseActionInterface`. + * and renders it with a handler that implements the `ThrowableResponseFactoryInterface`. */ final class ErrorCatcher implements MiddlewareInterface { public function __construct( - private readonly ThrowableResponseActionInterface $throwableResponseAction, + private readonly ThrowableResponseFactoryInterface $throwableResponseFactory, private readonly ?EventDispatcherInterface $eventDispatcher = null, ) { } @@ -37,7 +37,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $t = new CompositeException($e, $t); } - return $this->throwableResponseAction->handle($request, $t); + return $this->throwableResponseFactory->handle($request, $t); } } } diff --git a/src/ThrowableResponseAction.php b/src/ThrowableResponseFactory.php similarity index 87% rename from src/ThrowableResponseAction.php rename to src/ThrowableResponseFactory.php index 367696b..f16c5da 100644 --- a/src/ThrowableResponseAction.php +++ b/src/ThrowableResponseFactory.php @@ -12,9 +12,9 @@ use Yiisoft\Http\Status; /** - * `ThrowableResponseAction` produces a response with rendered `Throwable` object. + * `ThrowableResponseFactory` produces a response with rendered `Throwable` object. */ -final class ThrowableResponseAction implements ThrowableResponseActionInterface +final class ThrowableResponseFactory implements ThrowableResponseFactoryInterface { public function __construct( private readonly ResponseFactoryInterface $responseFactory, diff --git a/src/ThrowableResponseActionInterface.php b/src/ThrowableResponseFactoryInterface.php similarity index 73% rename from src/ThrowableResponseActionInterface.php rename to src/ThrowableResponseFactoryInterface.php index 061e822..088157f 100644 --- a/src/ThrowableResponseActionInterface.php +++ b/src/ThrowableResponseFactoryInterface.php @@ -9,9 +9,9 @@ use Psr\Http\Message\ServerRequestInterface; /** - * `ThrowableResponseActionInterface` produces a response for `Throwable` object. + * `ThrowableResponseFactoryInterface` produces a response for `Throwable` object. */ -interface ThrowableResponseActionInterface +interface ThrowableResponseFactoryInterface { /** * Handles a `Throwable` object and produces a response. diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 838edf0..0ea518d 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -4,11 +4,15 @@ namespace Yiisoft\ErrorHandler\Tests; +use HttpSoft\Message\ResponseFactory; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseFactoryInterface; use Yiisoft\Di\Container; use Yiisoft\Di\ContainerConfig; use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; use Yiisoft\ErrorHandler\ThrowableRendererInterface; +use Yiisoft\ErrorHandler\ThrowableResponseFactory; +use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; final class ConfigTest extends TestCase { @@ -17,16 +21,19 @@ public function testDiWeb(): void $container = $this->createContainer('web'); $throwableRenderer = $container->get(ThrowableRendererInterface::class); - $this->assertInstanceOf(HtmlRenderer::class, $throwableRenderer); + + $throwableResponseFactory = $container->get(ThrowableResponseFactoryInterface::class); + $this->assertInstanceOf(ThrowableResponseFactory::class, $throwableResponseFactory); } private function createContainer(?string $postfix = null): Container { return new Container( - ContainerConfig::create()->withDefinitions( - $this->getDiConfig($postfix) - ) + ContainerConfig::create()->withDefinitions([ + ResponseFactoryInterface::class => ResponseFactory::class, + ...$this->getDiConfig($postfix) + ]) ); } diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index ef2eb76..f4845de 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\Attributes\WithoutErrorHandler; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; use RuntimeException; use Throwable; use Yiisoft\ErrorHandler\ErrorHandler; @@ -15,17 +16,21 @@ final class ErrorHandlerTest extends TestCase { private ErrorHandler $errorHandler; + private LoggerInterface $loggerMock; private ThrowableRendererInterface $throwableRendererMock; protected function setUp(): void { + $this->loggerMock = $this->createMock(LoggerInterface::class); $this->throwableRendererMock = $this->createMock(ThrowableRendererInterface::class); - $this->errorHandler = new ErrorHandler($this->throwableRendererMock); + $this->errorHandler = new ErrorHandler($this->throwableRendererMock, $this->loggerMock); $this->errorHandler->memoryReserveSize(0); } - public function testHandleThrowableCallsDefaultRendererWhenNonePassed(): void + public function testHandleThrowableCallsDefaultRendererWithoutLogger(): void { + $errorHandler = new ErrorHandler($this->throwableRendererMock); + $errorHandler->memoryReserveSize(0); $throwable = new RuntimeException(); $this @@ -34,6 +39,18 @@ public function testHandleThrowableCallsDefaultRendererWhenNonePassed(): void ->method('render') ->with($throwable); + $errorHandler->handle($throwable); + } + + public function testHandleThrowableCallsDefaultRendererWhenNonePassed(): void + { + $throwable = new RuntimeException(); + + $this + ->throwableRendererMock + ->expects($this->once()) + ->method('render') + ->with($throwable); $this->errorHandler->handle($throwable); } diff --git a/tests/Middleware/ErrorCatcherTest.php b/tests/Middleware/ErrorCatcherTest.php index a9f8405..fb70036 100644 --- a/tests/Middleware/ErrorCatcherTest.php +++ b/tests/Middleware/ErrorCatcherTest.php @@ -14,7 +14,7 @@ use RuntimeException; use Throwable; use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; -use Yiisoft\ErrorHandler\ThrowableResponseActionInterface; +use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; use Yiisoft\Http\Status; final class ErrorCatcherTest extends TestCase @@ -22,7 +22,7 @@ final class ErrorCatcherTest extends TestCase public function testSuccess(): void { $errorCatcher = new ErrorCatcher( - $this->createThrowableResponseAction(), + $this->createThrowableResponseFactory(), ); $handler = new class () implements RequestHandlerInterface { public function handle(ServerRequestInterface $request): ResponseInterface @@ -41,7 +41,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface public function testError(): void { $errorCatcher = new ErrorCatcher( - $this->createThrowableResponseAction(), + $this->createThrowableResponseFactory(), ); $response = $errorCatcher->process( new ServerRequest(), @@ -56,7 +56,7 @@ public function testErrorWithEventDispatcher(): void $eventDispatcher = $this->createMock(EventDispatcherInterface::class); $eventDispatcher->method('dispatch')->willThrowException(new RuntimeException('Event dispatcher error')); $errorCatcher = new ErrorCatcher( - $this->createThrowableResponseAction(), + $this->createThrowableResponseFactory(), $eventDispatcher, ); $response = $errorCatcher->process( @@ -66,9 +66,9 @@ public function testErrorWithEventDispatcher(): void $this->assertSame(Status::INTERNAL_SERVER_ERROR, $response->getStatusCode()); } - private function createThrowableResponseAction(): ThrowableResponseActionInterface + private function createThrowableResponseFactory(): ThrowableResponseFactoryInterface { - return new class () implements ThrowableResponseActionInterface { + return new class () implements ThrowableResponseFactoryInterface { public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface { return new Response(Status::INTERNAL_SERVER_ERROR); diff --git a/tests/ThrowableResponseActionTest.php b/tests/ThrowableResponseFactoryTest.php similarity index 90% rename from tests/ThrowableResponseActionTest.php rename to tests/ThrowableResponseFactoryTest.php index 4a47a87..17fd80b 100644 --- a/tests/ThrowableResponseActionTest.php +++ b/tests/ThrowableResponseFactoryTest.php @@ -4,8 +4,8 @@ namespace Yiisoft\ErrorHandler\Tests; -use HttpSoft\Message\ResponseFactory; use LogicException; +use HttpSoft\Message\ResponseFactory; use PHPUnit\Framework\TestCase; use Yiisoft\ErrorHandler\ErrorHandler; use Yiisoft\ErrorHandler\HeadersProvider; @@ -13,17 +13,17 @@ use Yiisoft\ErrorHandler\RendererProvider\ContentTypeRendererProvider; use Yiisoft\ErrorHandler\Tests\Support\TestHelper; use Yiisoft\ErrorHandler\ThrowableRendererInterface; -use Yiisoft\ErrorHandler\ThrowableResponseAction; +use Yiisoft\ErrorHandler\ThrowableResponseFactory; use Yiisoft\Test\Support\Container\SimpleContainer; use function PHPUnit\Framework\assertSame; use function PHPUnit\Framework\assertTrue; -final class ThrowableResponseActionTest extends TestCase +final class ThrowableResponseFactoryTest extends TestCase { public function testBase(): void { - $action = new ThrowableResponseAction( + $action = new ThrowableResponseFactory( new ResponseFactory(), new ErrorHandler( new PlainTextRenderer(), @@ -44,7 +44,7 @@ public function testBase(): void public function testHeaders(): void { - $action = new ThrowableResponseAction( + $action = new ThrowableResponseFactory( new ResponseFactory(), new ErrorHandler( new PlainTextRenderer(), From a5b5d18b2498bbcf8c85a2beab80f8f53af5dc9c Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Tue, 16 Sep 2025 16:14:37 +0700 Subject: [PATCH 6/7] fix styles --- tests/ConfigTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 0ea518d..34aa468 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -32,7 +32,7 @@ private function createContainer(?string $postfix = null): Container return new Container( ContainerConfig::create()->withDefinitions([ ResponseFactoryInterface::class => ResponseFactory::class, - ...$this->getDiConfig($postfix) + ...$this->getDiConfig($postfix), ]) ); } From ddd497ced9a89eb3269f2d8f6064a7f9732cefdf Mon Sep 17 00:00:00 2001 From: Oleg Baturin Date: Wed, 17 Sep 2025 16:22:46 +0700 Subject: [PATCH 7/7] rename factory method to `create` --- src/Middleware/ErrorCatcher.php | 2 +- src/ThrowableResponseFactory.php | 2 +- src/ThrowableResponseFactoryInterface.php | 2 +- tests/Middleware/ErrorCatcherTest.php | 2 +- tests/ThrowableResponseFactoryTest.php | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Middleware/ErrorCatcher.php b/src/Middleware/ErrorCatcher.php index f264774..eab1bd9 100644 --- a/src/Middleware/ErrorCatcher.php +++ b/src/Middleware/ErrorCatcher.php @@ -37,7 +37,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $t = new CompositeException($e, $t); } - return $this->throwableResponseFactory->handle($request, $t); + return $this->throwableResponseFactory->create($request, $t); } } } diff --git a/src/ThrowableResponseFactory.php b/src/ThrowableResponseFactory.php index f16c5da..0b706e9 100644 --- a/src/ThrowableResponseFactory.php +++ b/src/ThrowableResponseFactory.php @@ -24,7 +24,7 @@ public function __construct( ) { } - public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface + public function create(ServerRequestInterface $request, Throwable $throwable): ResponseInterface { $renderer = $this->rendererProvider->get($request); diff --git a/src/ThrowableResponseFactoryInterface.php b/src/ThrowableResponseFactoryInterface.php index 088157f..5daf425 100644 --- a/src/ThrowableResponseFactoryInterface.php +++ b/src/ThrowableResponseFactoryInterface.php @@ -16,5 +16,5 @@ interface ThrowableResponseFactoryInterface /** * Handles a `Throwable` object and produces a response. */ - public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface; + public function create(ServerRequestInterface $request, Throwable $throwable): ResponseInterface; } diff --git a/tests/Middleware/ErrorCatcherTest.php b/tests/Middleware/ErrorCatcherTest.php index fb70036..2b46a31 100644 --- a/tests/Middleware/ErrorCatcherTest.php +++ b/tests/Middleware/ErrorCatcherTest.php @@ -69,7 +69,7 @@ public function testErrorWithEventDispatcher(): void private function createThrowableResponseFactory(): ThrowableResponseFactoryInterface { return new class () implements ThrowableResponseFactoryInterface { - public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface + public function create(ServerRequestInterface $request, Throwable $throwable): ResponseInterface { return new Response(Status::INTERNAL_SERVER_ERROR); } diff --git a/tests/ThrowableResponseFactoryTest.php b/tests/ThrowableResponseFactoryTest.php index 17fd80b..00e5275 100644 --- a/tests/ThrowableResponseFactoryTest.php +++ b/tests/ThrowableResponseFactoryTest.php @@ -23,7 +23,7 @@ final class ThrowableResponseFactoryTest extends TestCase { public function testBase(): void { - $action = new ThrowableResponseFactory( + $factory = new ThrowableResponseFactory( new ResponseFactory(), new ErrorHandler( new PlainTextRenderer(), @@ -33,7 +33,7 @@ public function testBase(): void ), ); - $response = $action->handle( + $response = $factory->create( TestHelper::createRequest(), new LogicException('test message') ); @@ -44,7 +44,7 @@ public function testBase(): void public function testHeaders(): void { - $action = new ThrowableResponseFactory( + $factory = new ThrowableResponseFactory( new ResponseFactory(), new ErrorHandler( new PlainTextRenderer(), @@ -55,7 +55,7 @@ public function testHeaders(): void new HeadersProvider(['X-Test' => ['on'], 'X-Test-Custom' => 'hello']) ); - $response = $action->handle( + $response = $factory->create( TestHelper::createRequest(), new LogicException('test message') );