From 44e989d1f11e3895b77871d4537ebe2f799c96d9 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Sat, 22 Apr 2023 12:16:57 +0200 Subject: [PATCH 1/2] Allow custom headers in Response --- example/example.php | 12 +++++++++ src/Router/Entities/JsonResponse.php | 4 +-- src/Router/Entities/Response.php | 12 +++++++-- tests/Feature/Router/RouterResponseTest.php | 28 +++++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/example/example.php b/example/example.php index df7a6ee..16de34c 100644 --- a/example/example.php +++ b/example/example.php @@ -5,6 +5,7 @@ require_once \dirname(__DIR__) . '/vendor/autoload.php'; use Gacela\Router\Entities\Request; +use Gacela\Router\Entities\Response; use Gacela\Router\Router; use Gacela\Router\Routes; @@ -34,6 +35,14 @@ public function customAction(int $number = 0): string { return "customAction(number: {$number})"; } + + public function customHeaders(): Response + { + return new Response('{"custom": "headers"}', [ + 'Access-Control-Allow-Origin: *', + 'Content-Type: application/json', + ]); + } } Router::configure(static function (Routes $routes): void { @@ -48,4 +57,7 @@ public function customAction(int $number = 0): string # Try it out: http://localhost:8081/custom $routes->any('custom', Controller::class); + + # Try it out: http://localhost:8081/headers + $routes->any('headers', Controller::class, 'customHeaders'); }); diff --git a/src/Router/Entities/JsonResponse.php b/src/Router/Entities/JsonResponse.php index eb3f6c6..605212f 100644 --- a/src/Router/Entities/JsonResponse.php +++ b/src/Router/Entities/JsonResponse.php @@ -6,9 +6,9 @@ final class JsonResponse extends Response { - public function __construct(array $json) + public function __construct(array $json, array $headers = []) { - parent::__construct(json_encode($json, JSON_THROW_ON_ERROR)); + parent::__construct(json_encode($json, JSON_THROW_ON_ERROR), $headers); } public function __toString(): string diff --git a/src/Router/Entities/Response.php b/src/Router/Entities/Response.php index 21a6bac..2272fc3 100644 --- a/src/Router/Entities/Response.php +++ b/src/Router/Entities/Response.php @@ -6,13 +6,21 @@ class Response { + /** + * @param list $headers + */ public function __construct( - private string $body, + private string $content, + private array $headers = [], ) { } public function __toString(): string { - return $this->body; + foreach ($this->headers as $header) { + header($header); + } + + return $this->content; } } diff --git a/tests/Feature/Router/RouterResponseTest.php b/tests/Feature/Router/RouterResponseTest.php index 6a1e04b..bc75fab 100644 --- a/tests/Feature/Router/RouterResponseTest.php +++ b/tests/Feature/Router/RouterResponseTest.php @@ -48,4 +48,32 @@ public function test_json_response(): void ], ], $this->headers()); } + + public function test_response_headers(): void + { + $_SERVER['REQUEST_URI'] = 'https://example.org/uri'; + $_SERVER['REQUEST_METHOD'] = Request::METHOD_GET; + + Router::configure(static function (Routes $routes): void { + $routes->get('uri', static fn () => new Response('{"key":"value"}', [ + 'Access-Control-Allow-Origin: *', + 'Content-Type: application/json', + ])); + }); + + $this->expectOutputString('{"key":"value"}'); + + self::assertSame([ + [ + 'header' => 'Access-Control-Allow-Origin: *', + 'replace' => true, + 'response_code' => 0, + ], + [ + 'header' => 'Content-Type: application/json', + 'replace' => true, + 'response_code' => 0, + ], + ], $this->headers()); + } } From 0a24735425350f20879b752c2e54a270becb2e05 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Sat, 22 Apr 2023 12:21:21 +0200 Subject: [PATCH 2/2] Avoid duplicated headers for JsonResponse --- src/Router/Entities/JsonResponse.php | 15 +++++------ tests/Feature/Router/RouterResponseTest.php | 28 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/Router/Entities/JsonResponse.php b/src/Router/Entities/JsonResponse.php index 605212f..a70a9da 100644 --- a/src/Router/Entities/JsonResponse.php +++ b/src/Router/Entities/JsonResponse.php @@ -4,17 +4,18 @@ namespace Gacela\Router\Entities; +use function in_array; + final class JsonResponse extends Response { + /** + * @param list $headers + */ public function __construct(array $json, array $headers = []) { + if (!in_array('Content-Type: application/json', $headers, true)) { + $headers[] = 'Content-Type: application/json'; + } parent::__construct(json_encode($json, JSON_THROW_ON_ERROR), $headers); } - - public function __toString(): string - { - header('Content-Type: application/json'); - - return parent::__toString(); - } } diff --git a/tests/Feature/Router/RouterResponseTest.php b/tests/Feature/Router/RouterResponseTest.php index bc75fab..8a2c0d5 100644 --- a/tests/Feature/Router/RouterResponseTest.php +++ b/tests/Feature/Router/RouterResponseTest.php @@ -76,4 +76,32 @@ public function test_response_headers(): void ], ], $this->headers()); } + + public function test_json_response_headers(): void + { + $_SERVER['REQUEST_URI'] = 'https://example.org/uri'; + $_SERVER['REQUEST_METHOD'] = Request::METHOD_GET; + + Router::configure(static function (Routes $routes): void { + $routes->get('uri', static fn () => new JsonResponse(['key' => 'value'], [ + 'Access-Control-Allow-Origin: *', + 'Content-Type: application/json', + ])); + }); + + $this->expectOutputString('{"key":"value"}'); + + self::assertSame([ + [ + 'header' => 'Access-Control-Allow-Origin: *', + 'replace' => true, + 'response_code' => 0, + ], + [ + 'header' => 'Content-Type: application/json', + 'replace' => true, + 'response_code' => 0, + ], + ], $this->headers()); + } }