Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit d7d0532

Browse files
committed
Merge branch 'feature/285' into develop
Close #285
2 parents 66b9b21 + 930cbe6 commit d7d0532

File tree

4 files changed

+196
-1
lines changed

4 files changed

+196
-1
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ All notable changes to this project will be documented in this file, in reverse
66

77
### Added
88

9-
- Nothing.
9+
- [#285](https://github.com/zendframework/zend-diactoros/pull/285) adds a new
10+
custom response type, `Zend\Diactoros\Response\XmlResponse`, for generating
11+
responses representing XML. Usage is the same as with the `HtmlResponse` or
12+
`TextResponse`; the response generated will have a `Content-Type:
13+
application/xml` header by default.
1014

1115
### Changed
1216

doc/book/custom-responses.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,28 @@ $response = new HtmlResponse($htmlContent, 200, [ 'Content-Type' => ['applicatio
5858
Headers must be in the same format as you would provide to the
5959
[Response constructor](api.md#response-message).
6060

61+
## XML Responses
62+
63+
- Since 1.7.0
64+
65+
`Zend\Diactoros\Response\XmlResponse` allows specifying XML as a payload, and sets the
66+
`Content-Type` header to `application/xml` by default:
67+
68+
```php
69+
$response = new XmlResponse($xml);
70+
```
71+
72+
The constructor allows passing two additional arguments: a status code, and an array of headers.
73+
These allow you to further seed the initial state of the response, as well as to override the
74+
`Content-Type` header if desired:
75+
76+
```php
77+
$response = new XmlResponse($xml, 200, [ 'Content-Type' => ['application/hal+xml']]);
78+
```
79+
80+
Headers must be in the same format as you would provide to the
81+
[Response constructor](api.md#response-message).
82+
6183
## JSON Responses
6284

6385
`Zend\Diactoros\Response\JsonResponse` accepts a data structure to convert to JSON, and sets

src/Response/XmlResponse.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository
4+
* @copyright Copyright (c) 2015-2017 Zend Technologies USA Inc. (http://www.zend.com)
5+
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
namespace Zend\Diactoros\Response;
9+
10+
use InvalidArgumentException;
11+
use Psr\Http\Message\StreamInterface;
12+
use Zend\Diactoros\Response;
13+
use Zend\Diactoros\Stream;
14+
15+
/**
16+
* XML response.
17+
*
18+
* Allows creating a response by passing an XML string to the constructor; by default,
19+
* sets a status code of 200 and sets the Content-Type header to application/xml.
20+
*/
21+
class XmlResponse extends Response
22+
{
23+
use InjectContentTypeTrait;
24+
25+
/**
26+
* Create an XML response.
27+
*
28+
* Produces an XML response with a Content-Type of application/xml and a default
29+
* status of 200.
30+
*
31+
* @param string|StreamInterface $xml String or stream for the message body.
32+
* @param int $status Integer status code for the response; 200 by default.
33+
* @param array $headers Array of headers to use at initialization.
34+
* @throws InvalidArgumentException if $text is neither a string or stream.
35+
*/
36+
public function __construct(
37+
$xml,
38+
$status = 200,
39+
array $headers = []
40+
) {
41+
parent::__construct(
42+
$this->createBody($xml),
43+
$status,
44+
$this->injectContentType('application/xml; charset=utf-8', $headers)
45+
);
46+
}
47+
48+
/**
49+
* Create the message body.
50+
*
51+
* @param string|StreamInterface $xml
52+
* @return StreamInterface
53+
* @throws InvalidArgumentException if $xml is neither a string or stream.
54+
*/
55+
private function createBody($xml)
56+
{
57+
if ($xml instanceof StreamInterface) {
58+
return $xml;
59+
}
60+
61+
if (! is_string($xml)) {
62+
throw new InvalidArgumentException(sprintf(
63+
'Invalid content (%s) provided to %s',
64+
(is_object($xml) ? get_class($xml) : gettype($xml)),
65+
__CLASS__
66+
));
67+
}
68+
69+
$body = new Stream('php://temp', 'wb+');
70+
$body->write($xml);
71+
$body->rewind();
72+
return $body;
73+
}
74+
}

test/Response/XmlResponseTest.php

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-diactoros for the canonical source repository
4+
* @copyright Copyright (c) 2015-2017 Zend Technologies USA Inc. (http://www.zend.com)
5+
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
namespace ZendTest\Diactoros\Response;
9+
10+
use InvalidArgumentException;
11+
use PHPUnit\Framework\TestCase;
12+
use Psr\Http\Message\StreamInterface;
13+
use Zend\Diactoros\Response\XmlResponse;
14+
15+
class XmlResponseTest extends TestCase
16+
{
17+
public function testConstructorAcceptsBodyAsString()
18+
{
19+
$body = 'Super valid XML';
20+
21+
$response = new XmlResponse($body);
22+
$this->assertSame($body, (string) $response->getBody());
23+
$this->assertSame(200, $response->getStatusCode());
24+
}
25+
26+
public function testConstructorAllowsPassingStatus()
27+
{
28+
$body = 'More valid XML';
29+
$status = 404;
30+
31+
$response = new XmlResponse($body, $status);
32+
$this->assertSame(404, $response->getStatusCode());
33+
$this->assertSame($body, (string) $response->getBody());
34+
}
35+
36+
public function testConstructorAllowsPassingHeaders()
37+
{
38+
$body = '<nearly>Valid XML</nearly>';
39+
$status = 404;
40+
$headers = [
41+
'x-custom' => [ 'foo-bar' ],
42+
];
43+
44+
$response = new XmlResponse($body, $status, $headers);
45+
$this->assertSame(['foo-bar'], $response->getHeader('x-custom'));
46+
$this->assertSame('application/xml; charset=utf-8', $response->getHeaderLine('content-type'));
47+
$this->assertSame(404, $response->getStatusCode());
48+
$this->assertSame($body, (string) $response->getBody());
49+
}
50+
51+
public function testAllowsStreamsForResponseBody()
52+
{
53+
$stream = $this->prophesize(StreamInterface::class);
54+
$body = $stream->reveal();
55+
$response = new XmlResponse($body);
56+
$this->assertSame($body, $response->getBody());
57+
}
58+
59+
public function invalidContent()
60+
{
61+
return [
62+
'null' => [null],
63+
'true' => [true],
64+
'false' => [false],
65+
'zero' => [0],
66+
'int' => [1],
67+
'zero-float' => [0.0],
68+
'float' => [1.1],
69+
'array' => [['php://temp']],
70+
'object' => [(object) ['php://temp']],
71+
];
72+
}
73+
74+
/**
75+
* @dataProvider invalidContent
76+
*/
77+
public function testRaisesExceptionforNonStringNonStreamBodyContent($body)
78+
{
79+
$this->expectException(InvalidArgumentException::class);
80+
81+
new XmlResponse($body);
82+
}
83+
84+
/**
85+
* @group 115
86+
*/
87+
public function testConstructorRewindsBodyStream()
88+
{
89+
$body = '<?xml version="1.0"?>' . PHP_EOL . '<something>Valid XML</something>';
90+
$response = new XmlResponse($body);
91+
92+
$actual = $response->getBody()->getContents();
93+
$this->assertSame($body, $actual);
94+
}
95+
}

0 commit comments

Comments
 (0)