Skip to content
This repository has been archived by the owner on Jul 6, 2024. It is now read-only.

Decouples AcceptAndContentTypeMiddleware from ResponseManagerInterface #3

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
58 changes: 58 additions & 0 deletions src/Manager/AcceptAndContentTypeMiddlewareResponseManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Chubbyphp\ApiHttp\Manager;

use Chubbyphp\ApiHttp\ApiProblem\ClientError\NotAcceptable;
use Chubbyphp\ApiHttp\ApiProblem\ClientError\UnsupportedMediaType;
use Chubbyphp\ApiHttp\Middleware\AcceptAndContentTypeMiddlewareResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;

final class AcceptAndContentTypeMiddlewareResponseManager implements AcceptAndContentTypeMiddlewareResponseFactoryInterface
{

/**
* @var ResponseManagerInterface
*/
private $responseManager;

public function __construct(ResponseManagerInterface $responseManager)
{
$this->responseManager = $responseManager;
}

/**
* @param string $accept
* @param array<int, string> $acceptableMimeTypes
* @param string $mimeType
* @return ResponseInterface
*/
public function createForNotAcceptable(
string $accept,
array $acceptableMimeTypes,
string $mimeType
): ResponseInterface {
return $this->responseManager->createFromApiProblem(
new NotAcceptable($accept, $acceptableMimeTypes),
$mimeType
);
}

/**
* @param string $mediaType
* @param array<int, string> $supportedMediaTypes
* @param string $mimeType
* @return ResponseInterface
*/
public function createForUnsupportedMediaType(
string $mediaType,
array $supportedMediaTypes,
string $mimeType
): ResponseInterface {
return $this->responseManager->createFromApiProblem(
new UnsupportedMediaType($mediaType, $supportedMediaTypes),
$mimeType
);
}
}
4 changes: 4 additions & 0 deletions src/Manager/ResponseManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public function __construct()

/**
* @param object $object
* @param string $accept
* @param int $status
* @param NormalizerContextInterface|null $context
* @return ResponseInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useless phpdoc, its already typesafe by design

*/
public function create(
$object,
Expand Down
27 changes: 10 additions & 17 deletions src/Middleware/AcceptAndContentTypeMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

namespace Chubbyphp\ApiHttp\Middleware;

use Chubbyphp\ApiHttp\ApiProblem\ClientError\NotAcceptable;
use Chubbyphp\ApiHttp\ApiProblem\ClientError\UnsupportedMediaType;
use Chubbyphp\ApiHttp\Manager\ResponseManagerInterface;
use Chubbyphp\Negotiation\AcceptNegotiatorInterface;
use Chubbyphp\Negotiation\ContentTypeNegotiatorInterface;
use Psr\Http\Message\ResponseInterface;
Expand All @@ -27,30 +24,28 @@ final class AcceptAndContentTypeMiddleware implements MiddlewareInterface
private $contentTypeNegotiator;

/**
* @var ResponseManagerInterface
* @var AcceptAndContentTypeMiddlewareResponseFactoryInterface
*/
private $responseManager;
private $responseFactory;

public function __construct(
AcceptNegotiatorInterface $acceptNegotiator,
ContentTypeNegotiatorInterface $contentTypeNegotiator,
ResponseManagerInterface $responseManager
AcceptAndContentTypeMiddlewareResponseFactoryInterface $responseFactory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a BC, both arguments should be possible, if the old is given, @trigger_error with user deprecation

) {
$this->acceptNegotiator = $acceptNegotiator;
$this->contentTypeNegotiator = $contentTypeNegotiator;
$this->responseManager = $responseManager;
$this->responseFactory = $responseFactory;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (null === $accept = $this->acceptNegotiator->negotiate($request)) {
$supportedMediaTypes = $this->acceptNegotiator->getSupportedMediaTypes();

return $this->responseManager->createFromApiProblem(
new NotAcceptable(
$request->getHeaderLine('Accept'),
$supportedMediaTypes
),
return $this->responseFactory->createForNotAcceptable(
$request->getHeaderLine('Accept'),
$supportedMediaTypes,
$supportedMediaTypes[0]
);
}
Expand All @@ -59,11 +54,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface

if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'], true)) {
if (null === $contentType = $this->contentTypeNegotiator->negotiate($request)) {
return $this->responseManager->createFromApiProblem(
new UnsupportedMediaType(
$request->getHeaderLine('Content-Type'),
$this->contentTypeNegotiator->getSupportedMediaTypes()
),
return $this->responseFactory->createForUnsupportedMediaType(
$request->getHeaderLine('Content-Type'),
$this->contentTypeNegotiator->getSupportedMediaTypes(),
$accept->getValue()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Chubbyphp\ApiHttp\Middleware;

use Psr\Http\Message\ResponseInterface;

interface AcceptAndContentTypeMiddlewareResponseFactoryInterface
{
/**
* @param string $accept
* @param array<int, string> $acceptableMimeTypes
* @param string $mimeType
* @return ResponseInterface
*/
public function createForNotAcceptable(
string $accept,
array $acceptableMimeTypes,
string $mimeType
): ResponseInterface;

/**
* @param string $mediaType
* @param array<int, string> $supportedMediaTypes
* @param string $mimeType
* @return ResponseInterface
*/
public function createForUnsupportedMediaType(
string $mediaType,
array $supportedMediaTypes,
string $mimeType
): ResponseInterface;
}
47 changes: 17 additions & 30 deletions tests/Unit/Middleware/AcceptAndContentTypeMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Chubbyphp\ApiHttp\ApiProblem\ClientError\UnsupportedMediaType;
use Chubbyphp\ApiHttp\Manager\ResponseManagerInterface;
use Chubbyphp\ApiHttp\Middleware\AcceptAndContentTypeMiddleware;
use Chubbyphp\ApiHttp\Middleware\AcceptAndContentTypeMiddlewareResponseFactoryInterface;
use Chubbyphp\Mock\Argument\ArgumentCallback;
use Chubbyphp\Mock\Call;
use Chubbyphp\Mock\MockByCallsTrait;
Expand Down Expand Up @@ -55,21 +56,14 @@ public function handle(ServerRequestInterface $request): ResponseInterface
/** @var ContentTypeNegotiatorInterface|MockObject $contentTypeNegotiator */
$contentTypeNegotiator = $this->getMockByCalls(ContentTypeNegotiatorInterface::class, []);

/** @var ResponseManagerInterface|MockObject $responseManager */
$responseManager = $this->getMockByCalls(ResponseManagerInterface::class, [
Call::create('createFromApiProblem')
->with(
new ArgumentCallback(function (NotAcceptable $apiProblem): void {
self::assertSame('application/xml', $apiProblem->getAccept());
self::assertSame(['application/json'], $apiProblem->getAcceptables());
}),
'application/json',
null
)
/** @var AcceptAndContentTypeMiddlewareResponseFactoryInterface|MockObject $responseFactory */
$responseFactory = $this->getMockByCalls(AcceptAndContentTypeMiddlewareResponseFactoryInterface::class, [
Call::create('createForNotAcceptable')
->with('application/xml', ['application/json'], 'application/json')
->willReturn($response),
]);

$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseManager);
$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseFactory);

self::assertSame($response, $middleware->process($request, $requestHandler));
}
Expand Down Expand Up @@ -115,10 +109,10 @@ public function handle(ServerRequestInterface $request): ResponseInterface
/** @var ContentTypeNegotiatorInterface|MockObject $contentTypeNegotiator */
$contentTypeNegotiator = $this->getMockByCalls(ContentTypeNegotiatorInterface::class, []);

/** @var ResponseManagerInterface|MockObject $responseManager */
$responseManager = $this->getMockByCalls(ResponseManagerInterface::class, []);
/** @var AcceptAndContentTypeMiddlewareResponseFactoryInterface|MockObject $responseFactory */
$responseFactory = $this->getMockByCalls(AcceptAndContentTypeMiddlewareResponseFactoryInterface::class, []);

$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseManager);
$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseFactory);

self::assertSame($response, $middleware->process($request, $requestHandler));
}
Expand Down Expand Up @@ -159,21 +153,14 @@ public function handle(ServerRequestInterface $request): ResponseInterface
Call::create('getSupportedMediaTypes')->with()->willReturn(['application/json']),
]);

/** @var ResponseManagerInterface|MockObject $responseManager */
$responseManager = $this->getMockByCalls(ResponseManagerInterface::class, [
Call::create('createFromApiProblem')
->with(
new ArgumentCallback(function (UnsupportedMediaType $apiProblem): void {
self::assertSame('application/xml', $apiProblem->getMediaType());
self::assertSame(['application/json'], $apiProblem->getSupportedMediaTypes());
}),
'application/json',
null
)
/** @var AcceptAndContentTypeMiddlewareResponseFactoryInterface|MockObject $responseFactory */
$responseFactory = $this->getMockByCalls(AcceptAndContentTypeMiddlewareResponseFactoryInterface::class, [
Call::create('createForUnsupportedMediaType')
->with('application/xml', ['application/json'], 'application/json')
->willReturn($response),
]);

$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseManager);
$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseFactory);

self::assertSame($response, $middleware->process($request, $requestHandler));
}
Expand Down Expand Up @@ -227,10 +214,10 @@ public function handle(ServerRequestInterface $request): ResponseInterface
Call::create('negotiate')->with($request)->willReturn($contentType),
]);

/** @var ResponseManagerInterface|MockObject $responseManager */
$responseManager = $this->getMockByCalls(ResponseManagerInterface::class, []);
/** @var AcceptAndContentTypeMiddlewareResponseFactoryInterface|MockObject $responseFactory */
$responseFactory = $this->getMockByCalls(AcceptAndContentTypeMiddlewareResponseFactoryInterface::class, []);

$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseManager);
$middleware = new AcceptAndContentTypeMiddleware($acceptNegotiator, $contentTypeNegotiator, $responseFactory);

self::assertSame($response, $middleware->process($request, $requestHandler));
}
Expand Down