Skip to content

Commit 7ebbf4e

Browse files
authored
Fix #82: Add HeadersProvider
1 parent 9928602 commit 7ebbf4e

File tree

4 files changed

+94
-9
lines changed

4 files changed

+94
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## 3.0.1 under development
44

5-
- no changes in this release.
5+
- Enh #82: Add `HeadersProvider` (@xepozz)
66

77
## 3.0.0 February 14, 2023
88

src/HeadersProvider.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\ErrorHandler;
6+
7+
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
8+
9+
/**
10+
* `HeadersProvider` provides headers for error response.
11+
* It is used by {@see ErrorCatcher} to add headers to response in case of error.
12+
*/
13+
final class HeadersProvider
14+
{
15+
/**
16+
* @param array<string, string[]> $headers Default headers list.
17+
*/
18+
public function __construct(
19+
private array $headers = [],
20+
) {
21+
}
22+
23+
/**
24+
* Adds a header to the list of headers.
25+
*
26+
* @param string $name The header name.
27+
* @param string|string[] $values The header value.
28+
*/
29+
public function add(string $name, string|array $values): void
30+
{
31+
$this->headers[$name] = (array)$values;
32+
}
33+
34+
/**
35+
* Returns all headers.
36+
*
37+
* @return array<string, string[]> The headers list.
38+
*/
39+
public function getAll(): array
40+
{
41+
return $this->headers;
42+
}
43+
}

src/Middleware/ErrorCatcher.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Psr\Http\Server\RequestHandlerInterface;
1414
use Throwable;
1515
use Yiisoft\ErrorHandler\ErrorHandler;
16+
use Yiisoft\ErrorHandler\HeadersProvider;
1617
use Yiisoft\ErrorHandler\Renderer\HeaderRenderer;
1718
use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;
1819
use Yiisoft\ErrorHandler\Renderer\JsonRenderer;
@@ -37,6 +38,8 @@
3738
*/
3839
final class ErrorCatcher implements MiddlewareInterface
3940
{
41+
private HeadersProvider $headersProvider;
42+
4043
/**
4144
* @psalm-var array<string,class-string<ThrowableRendererInterface>>
4245
*/
@@ -54,7 +57,9 @@ public function __construct(
5457
private ResponseFactoryInterface $responseFactory,
5558
private ErrorHandler $errorHandler,
5659
private ContainerInterface $container,
60+
HeadersProvider $headersProvider = null,
5761
) {
62+
$this->headersProvider = $headersProvider ?? new HeadersProvider();
5863
}
5964

6065
/**
@@ -137,7 +142,9 @@ private function generateErrorResponse(Throwable $t, ServerRequestInterface $req
137142

138143
$data = $this->errorHandler->handle($t, $renderer, $request);
139144
$response = $this->responseFactory->createResponse(Status::INTERNAL_SERVER_ERROR);
140-
145+
foreach ($this->headersProvider->getAll() as $name => $value) {
146+
$response = $response->withHeader($name, $value);
147+
}
141148
return $data->addToResponse($response->withHeader(Header::CONTENT_TYPE, $contentType));
142149
}
143150

tests/Middleware/ErrorCatcherTest.php

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
use Psr\Http\Server\RequestHandlerInterface;
1414
use Psr\Log\LoggerInterface;
1515
use RuntimeException;
16-
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
1716
use Yiisoft\ErrorHandler\ErrorHandler;
17+
use Yiisoft\ErrorHandler\HeadersProvider;
18+
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
1819
use Yiisoft\ErrorHandler\Renderer\HeaderRenderer;
1920
use Yiisoft\ErrorHandler\Renderer\PlainTextRenderer;
2021
use Yiisoft\ErrorHandler\ThrowableRendererInterface;
@@ -203,16 +204,50 @@ public function testForceContentTypeSetInvalidType(): void
203204
->forceContentType('image/gif');
204205
}
205206

206-
private function createErrorHandler(): ErrorHandler
207+
public function testAddedHeaders(): void
207208
{
208-
$logger = $this->createMock(LoggerInterface::class);
209-
return new ErrorHandler($logger, new PlainTextRenderer());
209+
$provider = new HeadersProvider([
210+
'X-Default' => 'default',
211+
'Content-Type' => 'incorrect',
212+
]);
213+
$provider->add('X-Test', 'test');
214+
$provider->add('X-Test2', ['test2', 'test3']);
215+
$catcher = $this
216+
->createErrorCatcher(provider: $provider)
217+
->withRenderer('*/*', PlainTextRenderer::class);
218+
$response = $catcher->process(
219+
$this->createServerRequest('GET', ['Accept' => ['test/test']]),
220+
$this->createRequestHandlerWithThrowable(),
221+
);
222+
$headers = $response->getHeaders();
223+
224+
$this->assertArrayHasKey('Content-Type', $headers);
225+
$this->assertNotEquals('incorrect', $headers['Content-Type']);
226+
227+
$this->assertArrayHasKey('X-Default', $headers);
228+
$this->assertEquals(['default'], $headers['X-Default']);
229+
$this->assertArrayHasKey('X-Test', $headers);
230+
$this->assertEquals(['test'], $headers['X-Test']);
231+
$this->assertArrayHasKey('X-Test2', $headers);
232+
$this->assertEquals(['test2', 'test3'], $headers['X-Test2']);
210233
}
211234

212-
private function createErrorCatcher(): ErrorCatcher
213-
{
235+
private function createErrorCatcher(
236+
HeadersProvider $provider = null,
237+
): ErrorCatcher {
214238
$container = new SimpleContainer([], fn (string $className): object => new $className());
215-
return new ErrorCatcher(new ResponseFactory(), $this->createErrorHandler(), $container);
239+
return new ErrorCatcher(
240+
new ResponseFactory(),
241+
$this->createErrorHandler(),
242+
$container,
243+
$provider ?? new HeadersProvider()
244+
);
245+
}
246+
247+
private function createErrorHandler(): ErrorHandler
248+
{
249+
$logger = $this->createMock(LoggerInterface::class);
250+
return new ErrorHandler($logger, new PlainTextRenderer());
216251
}
217252

218253
private function createServerRequest(string $method, array $headers = []): ServerRequestInterface

0 commit comments

Comments
 (0)