Skip to content

Commit 09e13af

Browse files
authored
Replace HasContentTypeTrait with an ResponseContentTrait, improve formatters (#49)
1 parent 7fe432a commit 09e13af

10 files changed

+115
-89
lines changed

src/Formatter/HtmlDataResponseFormatter.php

+18-19
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,41 @@
88
use RuntimeException;
99
use Yiisoft\DataResponse\DataResponse;
1010
use Yiisoft\DataResponse\DataResponseFormatterInterface;
11-
use Yiisoft\DataResponse\HasContentTypeTrait;
12-
use Yiisoft\Http\Header;
11+
use Yiisoft\DataResponse\ResponseContentTrait;
12+
13+
use function get_class;
14+
use function gettype;
15+
use function is_object;
16+
use function is_scalar;
17+
use function method_exists;
18+
use function sprintf;
1319

1420
final class HtmlDataResponseFormatter implements DataResponseFormatterInterface
1521
{
16-
use HasContentTypeTrait;
22+
use ResponseContentTrait;
1723

1824
/**
19-
* @var string the Content-Type header for the response
25+
* @var string The Content-Type header for the response.
2026
*/
2127
private string $contentType = 'text/html';
2228

2329
/**
24-
* @var string the XML encoding.
30+
* @var string The encoding to the Content-Type header.
2531
*/
2632
private string $encoding = 'UTF-8';
2733

2834
public function format(DataResponse $dataResponse): ResponseInterface
2935
{
3036
$data = $dataResponse->getData();
31-
if (!is_scalar($data) && null !== $data && !$this->isStringableObject($data)) {
32-
$type = is_object($data) ? get_class($data) : gettype($data);
33-
throw new RuntimeException(sprintf('Data must be a scalar value or null or a stringable object, %s given.', $type));
34-
}
35-
36-
$response = $dataResponse->getResponse();
37-
$response->getBody()->write((string)$data);
3837

39-
return $response->withHeader(Header::CONTENT_TYPE, $this->contentType . '; charset=' . $this->encoding);
40-
}
38+
if (!is_scalar($data) && $data !== null && !$this->isStringableObject($data)) {
39+
throw new RuntimeException(sprintf(
40+
'Data must be a scalar value or null or a stringable object, %s given.',
41+
is_object($data) ? get_class($data) : gettype($data),
42+
));
43+
}
4144

42-
public function withEncoding(string $encoding): self
43-
{
44-
$new = clone $this;
45-
$new->encoding = $encoding;
46-
return $new;
45+
return $this->addToResponse($dataResponse->getResponse(), empty($data) ? null : (string) $data);
4746
}
4847

4948
private function isStringableObject($value): bool

src/Formatter/JsonDataResponseFormatter.php

+12-8
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,26 @@
77
use Psr\Http\Message\ResponseInterface;
88
use Yiisoft\DataResponse\DataResponse;
99
use Yiisoft\DataResponse\DataResponseFormatterInterface;
10-
use Yiisoft\DataResponse\HasContentTypeTrait;
11-
use Yiisoft\Http\Header;
10+
use Yiisoft\DataResponse\ResponseContentTrait;
1211
use Yiisoft\Json\Json;
1312

1413
final class JsonDataResponseFormatter implements DataResponseFormatterInterface
1514
{
16-
use HasContentTypeTrait;
15+
use ResponseContentTrait;
1716

1817
/**
19-
* @var string the Content-Type header for the response
18+
* @var string The Content-Type header for the response.
2019
*/
2120
private string $contentType = 'application/json';
2221

22+
/**
23+
* @var string The encoding to the Content-Type header.
24+
*/
25+
private string $encoding = 'UTF-8';
26+
27+
/**
28+
* @var int The encoding options.
29+
*/
2330
private int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
2431

2532
public function format(DataResponse $dataResponse): ResponseInterface
@@ -28,10 +35,7 @@ public function format(DataResponse $dataResponse): ResponseInterface
2835
$content = Json::encode($dataResponse->getData(), $this->options);
2936
}
3037

31-
$response = $dataResponse->getResponse();
32-
$response->getBody()->write($content ?? '');
33-
34-
return $response->withHeader(Header::CONTENT_TYPE, $this->contentType);
38+
return $this->addToResponse($dataResponse->getResponse(), $content ?? null);
3539
}
3640

3741
/**

src/Formatter/XmlDataResponseFormatter.php

+8-26
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
use DOMText;
1111
use Psr\Http\Message\ResponseInterface;
1212
use Traversable;
13-
use Yiisoft\DataResponse\HasContentTypeTrait;
14-
use Yiisoft\Http\Header;
13+
use Yiisoft\DataResponse\ResponseContentTrait;
1514
use Yiisoft\Strings\NumericHelper;
1615
use Yiisoft\Strings\StringHelper;
1716
use Yiisoft\DataResponse\DataResponse;
@@ -27,7 +26,7 @@
2726

2827
final class XmlDataResponseFormatter implements DataResponseFormatterInterface
2928
{
30-
use HasContentTypeTrait;
29+
use ResponseContentTrait;
3130

3231
private const DEFAULT_ITEM_TAG_NAME = 'item';
3332
private const KEY_ATTRIBUTE_NAME = 'key';
@@ -38,14 +37,14 @@ final class XmlDataResponseFormatter implements DataResponseFormatterInterface
3837
private string $contentType = 'application/xml';
3938

4039
/**
41-
* @var string The XML version.
40+
* @var string The encoding to the Content-Type header.
4241
*/
43-
private string $version = '1.0';
42+
private string $encoding = 'UTF-8';
4443

4544
/**
46-
* @var string The XML encoding.
45+
* @var string The XML version.
4746
*/
48-
private string $encoding = 'UTF-8';
47+
private string $version = '1.0';
4948

5049
/**
5150
* @var string The name of the root element. If an empty value is set, the root tag should not be added.
@@ -72,13 +71,10 @@ public function format(DataResponse $dataResponse): ResponseInterface
7271
$this->buildXml($dom, $dom, $data);
7372
}
7473

75-
$content = $dom->saveXML();
74+
$content = (string) $dom->saveXML();
7675
}
7776

78-
$response = $dataResponse->getResponse();
79-
$response->getBody()->write($content ?? '');
80-
81-
return $response->withHeader(Header::CONTENT_TYPE, $this->contentType . '; ' . $this->encoding);
77+
return $this->addToResponse($dataResponse->getResponse(), $content ?? null);
8278
}
8379

8480
/**
@@ -95,20 +91,6 @@ public function withVersion(string $version): self
9591
return $new;
9692
}
9793

98-
/**
99-
* Returns a new instance with the specified encoding.
100-
*
101-
* @param string $encoding The XML encoding. Default is "UTF-8".
102-
*
103-
* @return self
104-
*/
105-
public function withEncoding(string $encoding): self
106-
{
107-
$new = clone $this;
108-
$new->encoding = $encoding;
109-
return $new;
110-
}
111-
11294
/**
11395
* Returns a new instance with the specified root tag.
11496
*

src/HasContentTypeTrait.php

-15
This file was deleted.

src/ResponseContentTrait.php

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\DataResponse;
6+
7+
use Psr\Http\Message\ResponseInterface;
8+
use Yiisoft\Http\Header;
9+
10+
trait ResponseContentTrait
11+
{
12+
/**
13+
* Returns a new instance with the specified content type.
14+
*
15+
* @param string $contentType The content type. For example, "text/html".
16+
*
17+
* @return self
18+
*/
19+
public function withContentType(string $contentType): self
20+
{
21+
$new = clone $this;
22+
$new->contentType = $contentType;
23+
return $new;
24+
}
25+
26+
/**
27+
* Returns a new instance with the specified encoding.
28+
*
29+
* @param string $encoding The encoding. For example, "UTF-8".
30+
*
31+
* @return self
32+
*/
33+
public function withEncoding(string $encoding): self
34+
{
35+
$new = clone $this;
36+
$new->encoding = $encoding;
37+
return $new;
38+
}
39+
40+
/**
41+
* Adds the content and the content type header to the response and returns it.
42+
*
43+
* @param ResponseInterface $response The response instance.
44+
* @param string|null $content The content to add to the response.
45+
*
46+
* @return ResponseInterface A response with added content and a content type header.
47+
*/
48+
private function addToResponse(ResponseInterface $response, string $content = null): ResponseInterface
49+
{
50+
if ($content !== null) {
51+
$response->getBody()->write($content);
52+
}
53+
54+
return $response->withHeader(Header::CONTENT_TYPE, "$this->contentType; charset=$this->encoding");
55+
}
56+
}

tests/DataResponseTest.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function testSetResponseFormatter(): void
6161

6262
$this->assertTrue($dataResponse->hasResponseFormatter());
6363
$this->assertSame('"test"', $dataResponse->getBody()->getContents());
64-
$this->assertSame(['application/json'], $dataResponse->getHeader('Content-Type'));
64+
$this->assertSame(['application/json; charset=UTF-8'], $dataResponse->getHeader('Content-Type'));
6565
}
6666

6767
public function testSetEmptyResponseFormatter(): void
@@ -72,7 +72,7 @@ public function testSetEmptyResponseFormatter(): void
7272

7373
$this->assertTrue($dataResponse->hasResponseFormatter());
7474
$this->assertSame('', $dataResponse->getBody()->getContents());
75-
$this->assertSame(['application/json'], $dataResponse->getHeader('Content-Type'));
75+
$this->assertSame(['application/json; charset=UTF-8'], $dataResponse->getHeader('Content-Type'));
7676
}
7777

7878
public function testSetResponseLoopFormatter(): void
@@ -108,23 +108,23 @@ public function testGetHeader(): void
108108
$dataResponse = $this->createFactory()->createResponse();
109109
$dataResponse = $dataResponse->withResponseFormatter(new JsonDataResponseFormatter());
110110

111-
$this->assertEquals(['application/json'], $dataResponse->getHeader(Header::CONTENT_TYPE));
111+
$this->assertEquals(['application/json; charset=UTF-8'], $dataResponse->getHeader(Header::CONTENT_TYPE));
112112
}
113113

114114
public function testGetHeaderLine(): void
115115
{
116116
$dataResponse = $this->createFactory()->createResponse();
117117
$dataResponse = $dataResponse->withResponseFormatter(new JsonDataResponseFormatter());
118118

119-
$this->assertEquals('application/json', $dataResponse->getHeaderLine(Header::CONTENT_TYPE));
119+
$this->assertEquals('application/json; charset=UTF-8', $dataResponse->getHeaderLine(Header::CONTENT_TYPE));
120120
}
121121

122122
public function testGetHeaders(): void
123123
{
124124
$dataResponse = $this->createFactory()->createResponse();
125125
$dataResponse = $dataResponse->withResponseFormatter(new JsonDataResponseFormatter());
126126

127-
$this->assertEquals([Header::CONTENT_TYPE => ['application/json']], $dataResponse->getHeaders());
127+
$this->assertEquals([Header::CONTENT_TYPE => ['application/json; charset=UTF-8']], $dataResponse->getHeaders());
128128
}
129129

130130
public function testHasHeader(): void

tests/Formatter/JsonDataResponseFormatterTest.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function testCorrectFormat(): void
1919
$result->getBody()->rewind();
2020

2121
$this->assertSame('{"test":"test"}', $result->getBody()->getContents());
22-
$this->assertSame(['application/json'], $result->getHeader(Header::CONTENT_TYPE));
22+
$this->assertSame(['application/json; charset=UTF-8'], $result->getHeader(Header::CONTENT_TYPE));
2323
}
2424

2525
public function testWithContentType(): void
@@ -29,7 +29,7 @@ public function testWithContentType(): void
2929
$result->getBody()->rewind();
3030

3131
$this->assertSame('{"test":"test"}', $result->getBody()->getContents());
32-
$this->assertSame(['application/xml'], $result->getHeader(Header::CONTENT_TYPE));
32+
$this->assertSame(['application/xml; charset=UTF-8'], $result->getHeader(Header::CONTENT_TYPE));
3333
}
3434

3535
public function testWithOptions(): void
@@ -39,7 +39,7 @@ public function testWithOptions(): void
3939
$result->getBody()->rewind();
4040

4141
$this->assertSame('{"0":"test"}', $result->getBody()->getContents());
42-
$this->assertSame(['application/json'], $result->getHeader(Header::CONTENT_TYPE));
42+
$this->assertSame(['application/json; charset=UTF-8'], $result->getHeader(Header::CONTENT_TYPE));
4343
}
4444

4545
public function testWithEmptyResponse(): void
@@ -49,7 +49,7 @@ public function testWithEmptyResponse(): void
4949
$result->getBody()->rewind();
5050

5151
$this->assertSame('', $result->getBody()->getContents());
52-
$this->assertSame(['application/json'], $result->getHeader(Header::CONTENT_TYPE));
52+
$this->assertSame(['application/json; charset=UTF-8'], $result->getHeader(Header::CONTENT_TYPE));
5353
}
5454

5555
private function createFactory(): DataResponseFactory

tests/Formatter/XmlDataResponseFormatterTest.php

+7-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function testCorrectFormat(): void
2727
$this->xml('<response>test</response>'),
2828
$result->getBody()->getContents()
2929
);
30-
$this->assertSame(['application/xml; UTF-8'], $result->getHeader('Content-Type'));
30+
$this->assertSame(['application/xml; charset=UTF-8'], $result->getHeader('Content-Type'));
3131
}
3232

3333
public function testWithEncoding(): void
@@ -41,7 +41,7 @@ public function testWithEncoding(): void
4141
$this->xml('<response>test</response>', '1.0', $encoding),
4242
$result->getBody()->getContents()
4343
);
44-
$this->assertSame(["application/xml; {$encoding}"], $result->getHeader('Content-Type'));
44+
$this->assertSame(["application/xml; charset={$encoding}"], $result->getHeader('Content-Type'));
4545
}
4646

4747
public function testWithVersion(): void
@@ -55,7 +55,7 @@ public function testWithVersion(): void
5555
$this->xml('<response>test</response>', $version),
5656
$result->getBody()->getContents()
5757
);
58-
$this->assertSame(['application/xml; UTF-8'], $result->getHeader('Content-Type'));
58+
$this->assertSame(['application/xml; charset=UTF-8'], $result->getHeader('Content-Type'));
5959
}
6060

6161
public function testWithRootTag(): void
@@ -68,7 +68,7 @@ public function testWithRootTag(): void
6868
$this->xml('<exampleRootTag>test</exampleRootTag>'),
6969
$result->getBody()->getContents()
7070
);
71-
$this->assertSame(['application/xml; UTF-8'], $result->getHeader('Content-Type'));
71+
$this->assertSame(['application/xml; charset=UTF-8'], $result->getHeader('Content-Type'));
7272
}
7373

7474
public function testWithoutRootTag(): void
@@ -81,7 +81,7 @@ public function testWithoutRootTag(): void
8181
$this->xml('<tag>value</tag>'),
8282
$result->getBody()->getContents()
8383
);
84-
$this->assertSame(['application/xml; UTF-8'], $result->getHeader('Content-Type'));
84+
$this->assertSame(['application/xml; charset=UTF-8'], $result->getHeader('Content-Type'));
8585
}
8686

8787
public function testWithEmptyRootTag(): void
@@ -94,7 +94,7 @@ public function testWithEmptyRootTag(): void
9494
$this->xml('<response/>'),
9595
$result->getBody()->getContents()
9696
);
97-
$this->assertSame(['application/xml; UTF-8'], $result->getHeader('Content-Type'));
97+
$this->assertSame(['application/xml; charset=UTF-8'], $result->getHeader('Content-Type'));
9898
}
9999

100100
public function testWithContentType(): void
@@ -107,7 +107,7 @@ public function testWithContentType(): void
107107
$this->xml('<response>test</response>'),
108108
$result->getBody()->getContents()
109109
);
110-
$this->assertSame(['text/xml; UTF-8'], $result->getHeader('Content-Type'));
110+
$this->assertSame(['text/xml; charset=UTF-8'], $result->getHeader('Content-Type'));
111111
}
112112

113113
public function testScalarValues(): void

0 commit comments

Comments
 (0)