From 0412758247a5a4f05225a1cd2450a4a6803f2736 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Sep 2025 14:49:41 +0300 Subject: [PATCH 1/4] Introduce accept provider for content negotiator --- .../AcceptProviderInterface.php | 16 +++++ .../AcceptProvider/HeaderAcceptProvider.php | 26 ++++++++ .../RequestParameterAcceptProvider.php | 64 +++++++++++++++++++ src/Middleware/ContentNegotiator.php | 14 ++-- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/Middleware/AcceptProvider/AcceptProviderInterface.php create mode 100644 src/Middleware/AcceptProvider/HeaderAcceptProvider.php create mode 100644 src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php diff --git a/src/Middleware/AcceptProvider/AcceptProviderInterface.php b/src/Middleware/AcceptProvider/AcceptProviderInterface.php new file mode 100644 index 0000000..d56adf1 --- /dev/null +++ b/src/Middleware/AcceptProvider/AcceptProviderInterface.php @@ -0,0 +1,16 @@ +getHeader(Header::ACCEPT) as $headerValue) { + $values[] = array_filter( + array_map( + trim(...), + explode(',', $headerValue), + ), + static fn(string $value) => $value !== '', + ); + } + return array_merge(...$values); + } +} diff --git a/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php new file mode 100644 index 0000000..fa096d7 --- /dev/null +++ b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php @@ -0,0 +1,64 @@ +getMethod() === Method::GET + ? $this->fget($request) + : [...$this->post($request), ...$this->fget($request)]; + } + + /** + * @return string[] + */ + public function fget(ServerRequestInterface $request): array + { + return $this->prepareValue($request->getQueryParams()[$this->name] ?? null); + } + + /** + * @return string[] + */ + private function post(ServerRequestInterface $request): array + { + $body = $request->getParsedBody(); + return is_array($body) + ? $this->prepareValue($body[$this->name] ?? null) + : []; + } + + /** + * @return string[] + */ + private function prepareValue(mixed $value): array + { + if (!is_string($value)) { + return []; + } + + return array_filter( + array_map( + trim(...), + explode(',', $value), + ), + static fn(string $accept) => $accept !== '', + ); + } +} diff --git a/src/Middleware/ContentNegotiator.php b/src/Middleware/ContentNegotiator.php index c03973e..728e155 100644 --- a/src/Middleware/ContentNegotiator.php +++ b/src/Middleware/ContentNegotiator.php @@ -11,6 +11,8 @@ use RuntimeException; use Yiisoft\DataResponse\DataResponse; use Yiisoft\DataResponse\DataResponseFormatterInterface; +use Yiisoft\DataResponse\Middleware\AcceptProvider\AcceptProviderInterface; +use Yiisoft\DataResponse\Middleware\AcceptProvider\HeaderAcceptProvider; use Yiisoft\Http\Header; use function gettype; @@ -35,8 +37,10 @@ final class ContentNegotiator implements MiddlewareInterface * * @psalm-param array $contentFormatters */ - public function __construct(array $contentFormatters) - { + public function __construct( + array $contentFormatters, + private readonly AcceptProviderInterface $acceptProvider = new HeaderAcceptProvider(), + ) { $this->checkFormatters($contentFormatters); $this->contentFormatters = $contentFormatters; } @@ -61,11 +65,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface { $response = $handler->handle($request); if ($response instanceof DataResponse && !$response->hasResponseFormatter()) { - $accepted = $request->getHeader(Header::ACCEPT); - - foreach ($accepted as $accept) { + foreach ($this->acceptProvider->get($request) as $accept) { foreach ($this->contentFormatters as $contentType => $formatter) { - if (str_contains($accept, $contentType)) { + if ($contentType === $accept) { return $response->withResponseFormatter($formatter); } } From 3f87bd1bc2c2564aed93c69c52f4221cb9fbe6be Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Sep 2025 14:51:09 +0300 Subject: [PATCH 2/4] rename --- .../AcceptProvider/RequestParameterAcceptProvider.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php index fa096d7..563b8cd 100644 --- a/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php +++ b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php @@ -21,14 +21,14 @@ public function __construct( public function get(ServerRequestInterface $request): array { return $request->getMethod() === Method::GET - ? $this->fget($request) - : [...$this->post($request), ...$this->fget($request)]; + ? $this->fromQueryParams($request) + : [...$this->fromParsedBody($request), ...$this->fromQueryParams($request)]; } /** * @return string[] */ - public function fget(ServerRequestInterface $request): array + public function fromQueryParams(ServerRequestInterface $request): array { return $this->prepareValue($request->getQueryParams()[$this->name] ?? null); } @@ -36,7 +36,7 @@ public function fget(ServerRequestInterface $request): array /** * @return string[] */ - private function post(ServerRequestInterface $request): array + private function fromParsedBody(ServerRequestInterface $request): array { $body = $request->getParsedBody(); return is_array($body) From 453cebe2717aabc580e95e44e33547de3c3175f9 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 10 Sep 2025 11:51:26 +0000 Subject: [PATCH 3/4] Apply fixes from StyleCI --- src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php | 1 - src/Middleware/ContentNegotiator.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php index 563b8cd..705c005 100644 --- a/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php +++ b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php @@ -5,7 +5,6 @@ namespace Yiisoft\DataResponse\Middleware\AcceptProvider; use Psr\Http\Message\ServerRequestInterface; - use Yiisoft\Http\Method; use function is_array; diff --git a/src/Middleware/ContentNegotiator.php b/src/Middleware/ContentNegotiator.php index 728e155..fecce3f 100644 --- a/src/Middleware/ContentNegotiator.php +++ b/src/Middleware/ContentNegotiator.php @@ -13,7 +13,6 @@ use Yiisoft\DataResponse\DataResponseFormatterInterface; use Yiisoft\DataResponse\Middleware\AcceptProvider\AcceptProviderInterface; use Yiisoft\DataResponse\Middleware\AcceptProvider\HeaderAcceptProvider; -use Yiisoft\Http\Header; use function gettype; use function is_string; From de829225bd9fa4dd451460755a814b896c22e19e Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 10 Sep 2025 14:54:31 +0300 Subject: [PATCH 4/4] improve --- src/Middleware/ContentNegotiator.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Middleware/ContentNegotiator.php b/src/Middleware/ContentNegotiator.php index fecce3f..f1bc99a 100644 --- a/src/Middleware/ContentNegotiator.php +++ b/src/Middleware/ContentNegotiator.php @@ -65,10 +65,8 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $response = $handler->handle($request); if ($response instanceof DataResponse && !$response->hasResponseFormatter()) { foreach ($this->acceptProvider->get($request) as $accept) { - foreach ($this->contentFormatters as $contentType => $formatter) { - if ($contentType === $accept) { - return $response->withResponseFormatter($formatter); - } + if (isset($this->contentFormatters[$accept])) { + return $response->withResponseFormatter($this->contentFormatters[$accept]); } } }