Skip to content

Commit

Permalink
Allow raw formatter returning complete PSR 7 response
Browse files Browse the repository at this point in the history
  • Loading branch information
hiqsol committed Jun 24, 2020
1 parent e30be10 commit dca9c89
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 39 deletions.
22 changes: 22 additions & 0 deletions src/BodyOnlyFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Lcobucci\ContentNegotiation;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;

abstract class BodyOnlyFormatter implements Formatter
{
/**
* @throws ContentCouldNotBeFormatted
*/
public function format(UnformattedResponse $response, StreamFactoryInterface $streamFactory): ResponseInterface
{
return $response->withBody($this->formatBody($response, $streamFactory));
}

abstract protected function formatBody(UnformattedResponse $response, StreamFactoryInterface $streamFactory): StreamInterface;
}
20 changes: 20 additions & 0 deletions src/ContentFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Lcobucci\ContentNegotiation;

use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;

abstract class ContentFormatter extends BodyOnlyFormatter
{
protected function formatBody(UnformattedResponse $response, StreamFactoryInterface $streamFactory): StreamInterface
{
return $streamFactory->createStream(
$this->formatContent($response->getUnformattedContent(), $response->getAttributes())
);
}

abstract protected function formatContent($content, array $attributes = []): string;
}
23 changes: 8 additions & 15 deletions src/ContentTypeMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace Lcobucci\ContentNegotiation;

use Fig\Http\Message\StatusCodeInterface;
use Middlewares\ContentType;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -18,6 +17,8 @@ final class ContentTypeMiddleware implements MiddlewareInterface
private MiddlewareInterface $negotiator;
private StreamFactoryInterface $streamFactory;

public const NOT_ACCEPTABLE = 'NOT ACCEPTABLE';

/**
* @var Formatter[]
*/
Expand Down Expand Up @@ -66,9 +67,9 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
}

$contentType = $this->extractContentType($response->getHeaderLine('Content-Type'));
$formatter = $this->formatters[$contentType] ?? null;
$formatter = $this->formatters[$contentType] ?? $this->getNotAcceptableFormatter();

return $this->formatResponse($response, $formatter);
return $formatter->format($response, $this->streamFactory);
}

private function extractContentType(string $contentType): string
Expand All @@ -82,20 +83,12 @@ private function extractContentType(string $contentType): string
return substr($contentType, 0, $charsetSeparatorPosition);
}

/**
* @throws ContentCouldNotBeFormatted
*/
private function formatResponse(UnformattedResponse $response, ?Formatter $formatter): ResponseInterface
private function getNotAcceptableFormatter(): Formatter
{
if ($formatter === null) {
return $response->withBody($this->streamFactory->createStream())
->withStatus(StatusCodeInterface::STATUS_NOT_ACCEPTABLE);
if (empty($this->formatters[self::NOT_ACCEPTABLE])) {
$this->formatters[self::NOT_ACCEPTABLE] = new NotAcceptableFormatter();
}

return $response->withBody(
$this->streamFactory->createStream(
$formatter->format($response->getUnformattedContent(), $response->getAttributes())
)
);
return $this->formatters[self::NOT_ACCEPTABLE];
}
}
8 changes: 4 additions & 4 deletions src/Formatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

namespace Lcobucci\ContentNegotiation;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;

interface Formatter
{
/**
* @param mixed $content
* @param mixed[] $attributes
*
* @throws ContentCouldNotBeFormatted
*/
public function format($content, array $attributes = []): string;
public function format(UnformattedResponse $response, StreamFactoryInterface $streamFactory): ResponseInterface;
}
6 changes: 3 additions & 3 deletions src/Formatter/JmsSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

use JMS\Serializer\SerializerInterface;
use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter;
use Lcobucci\ContentNegotiation\ContentFormatter;
use Throwable;
use function sprintf;

final class JmsSerializer implements Formatter
final class JmsSerializer extends ContentFormatter
{
private SerializerInterface $serializer;
private string $format;
Expand All @@ -23,7 +23,7 @@ public function __construct(SerializerInterface $serializer, string $format)
/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
public function formatContent($content, array $attributes = []): string
{
try {
return $this->serializer->serialize($content, $this->format);
Expand Down
6 changes: 3 additions & 3 deletions src/Formatter/Json.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Lcobucci\ContentNegotiation\Formatter;

use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter;
use Lcobucci\ContentNegotiation\ContentFormatter;
use Throwable;
use function json_encode;
use function sprintf;
Expand All @@ -15,7 +15,7 @@
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;

final class Json implements Formatter
final class Json extends ContentFormatter
{
private const DEFAULT_FLAGS = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES;

Expand All @@ -29,7 +29,7 @@ public function __construct(int $flags = self::DEFAULT_FLAGS)
/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
public function formatContent($content, array $attributes = []): string
{
try {
return json_encode($content, $this->flags | JSON_THROW_ON_ERROR);
Expand Down
6 changes: 3 additions & 3 deletions src/Formatter/Plates.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
namespace Lcobucci\ContentNegotiation\Formatter;

use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter;
use Lcobucci\ContentNegotiation\ContentFormatter;
use League\Plates\Engine;
use Throwable;

final class Plates implements Formatter
final class Plates extends ContentFormatter
{
private const DEFAULT_ATTRIBUTE = 'template';

Expand All @@ -24,7 +24,7 @@ public function __construct(Engine $engine, string $attributeName = self::DEFAUL
/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
public function formatContent($content, array $attributes = []): string
{
try {
return $this->render($content, $attributes);
Expand Down
6 changes: 3 additions & 3 deletions src/Formatter/StringCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
namespace Lcobucci\ContentNegotiation\Formatter;

use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter;
use Lcobucci\ContentNegotiation\ContentFormatter;
use function is_object;
use function method_exists;

final class StringCast implements Formatter
final class StringCast extends ContentFormatter
{
/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
public function formatContent($content, array $attributes = []): string
{
if (is_object($content) && ! method_exists($content, '__toString')) {
throw new ContentCouldNotBeFormatted('Given data could not be cast to string');
Expand Down
6 changes: 3 additions & 3 deletions src/Formatter/Twig.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
namespace Lcobucci\ContentNegotiation\Formatter;

use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter;
use Lcobucci\ContentNegotiation\ContentFormatter;
use Throwable;
use Twig\Environment;

final class Twig implements Formatter
final class Twig extends ContentFormatter
{
private const DEFAULT_ATTRIBUTE = 'template';

Expand All @@ -26,7 +26,7 @@ public function __construct(
/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
public function formatContent($content, array $attributes = []): string
{
try {
return $this->render($content, $attributes);
Expand Down
18 changes: 18 additions & 0 deletions src/NotAcceptableFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Lcobucci\ContentNegotiation;

use Fig\Http\Message\StatusCodeInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;

class NotAcceptableFormatter implements Formatter
{
public function format(UnformattedResponse $response, StreamFactoryInterface $streamFactory): ResponseInterface
{
return $response->withBody($streamFactory->createStream())
->withStatus(StatusCodeInterface::STATUS_NOT_ACCEPTABLE);
}
}
11 changes: 9 additions & 2 deletions tests/Formatter/JmsSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
namespace Lcobucci\ContentNegotiation\Tests\Formatter;

use JMS\Serializer\SerializerInterface;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\StreamFactory;
use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter\JmsSerializer;
use Lcobucci\ContentNegotiation\UnformattedResponse;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use RuntimeException;
Expand Down Expand Up @@ -37,6 +40,7 @@ public function createSerializer(): void
public function formatShouldSimplyForwardCallToSerializer(): void
{
$content = ['a' => 'test'];
$unformatted = new UnformattedResponse(new Response(), $content);

$this->serializer->expects(self::once())
->method('serialize')
Expand All @@ -45,7 +49,9 @@ public function formatShouldSimplyForwardCallToSerializer(): void

$formatter = new JmsSerializer($this->serializer, 'json');

self::assertSame('{"a":"test"}', $formatter->format($content));
$response = $formatter->format($unformatted, new StreamFactory());

self::assertSame('{"a":"test"}', $response->getBody()->getContents());
}

/**
Expand All @@ -62,6 +68,7 @@ public function formatShouldConvertAnyRaisedException(): void
->willThrowException(new RuntimeException());

$formatter = new JmsSerializer($this->serializer, 'json');
$formatter->format(['a' => 'test']);
$unformatted = new UnformattedResponse(new Response(), ['a' => 'test']);
$formatter->format($unformatted, new StreamFactory());
}
}
6 changes: 3 additions & 3 deletions tests/Formatter/NaiveTemplateEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Lcobucci\ContentNegotiation\Tests\Formatter;

use Lcobucci\ContentNegotiation\Formatter;
use Lcobucci\ContentNegotiation\ContentFormatter;
use SplFileObject;
use function array_keys;
use function array_map;
Expand All @@ -12,15 +12,15 @@
use function str_replace;
use function trim;

final class NaiveTemplateEngine implements Formatter
final class NaiveTemplateEngine extends ContentFormatter
{
private const BASE_DIR = __DIR__ . '/../../templates/naive/';
private const EXTENSION = 'html';

/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
public function formatContent($content, array $attributes = []): string
{
$template = $this->getTemplateContent($attributes);

Expand Down

0 comments on commit dca9c89

Please sign in to comment.