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..705c005 --- /dev/null +++ b/src/Middleware/AcceptProvider/RequestParameterAcceptProvider.php @@ -0,0 +1,63 @@ +getMethod() === Method::GET + ? $this->fromQueryParams($request) + : [...$this->fromParsedBody($request), ...$this->fromQueryParams($request)]; + } + + /** + * @return string[] + */ + public function fromQueryParams(ServerRequestInterface $request): array + { + return $this->prepareValue($request->getQueryParams()[$this->name] ?? null); + } + + /** + * @return string[] + */ + private function fromParsedBody(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..f1bc99a 100644 --- a/src/Middleware/ContentNegotiator.php +++ b/src/Middleware/ContentNegotiator.php @@ -11,7 +11,8 @@ use RuntimeException; use Yiisoft\DataResponse\DataResponse; use Yiisoft\DataResponse\DataResponseFormatterInterface; -use Yiisoft\Http\Header; +use Yiisoft\DataResponse\Middleware\AcceptProvider\AcceptProviderInterface; +use Yiisoft\DataResponse\Middleware\AcceptProvider\HeaderAcceptProvider; use function gettype; use function is_string; @@ -35,8 +36,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,13 +64,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->contentFormatters as $contentType => $formatter) { - if (str_contains($accept, $contentType)) { - return $response->withResponseFormatter($formatter); - } + foreach ($this->acceptProvider->get($request) as $accept) { + if (isset($this->contentFormatters[$accept])) { + return $response->withResponseFormatter($this->contentFormatters[$accept]); } } }