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

Commit 1bd3919

Browse files
committed
Add functionality to create CSV response from array and traversable
In addition to the refactor to create the CSV response from a string, this change adds the ability to create the CSV response from a plain old PHP array as well as a Traversable. I'm not altogether happy with the naming of some of the functions and variables, but will address that, just as soon as I can think of better names.
1 parent 6295730 commit 1bd3919

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

src/Response/CsvResponse.php

+25
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Zend\Diactoros\Response;
1111

1212
use Psr\Http\Message\StreamInterface;
13+
use Traversable;
1314
use Zend\Diactoros\Exception;
1415
use Zend\Diactoros\Response;
1516
use Zend\Diactoros\Stream;
@@ -31,6 +32,7 @@ class CsvResponse extends DownloadResponse
3132
{
3233
use InjectContentTypeTrait;
3334

35+
const DEFAULT_LINE_ENDING = "\n";
3436
const DEFAULT_SEPARATOR = ',';
3537

3638
/**
@@ -83,6 +85,10 @@ private function createBody($text) : StreamInterface
8385
$body = $text;
8486
}
8587

88+
if (is_array($text) | $text instanceof Traversable) {
89+
$body = $this->createBodyFromIterable($text);
90+
}
91+
8692
return $body;
8793
}
8894

@@ -109,6 +115,25 @@ private function createBodyFromString(string $text) : StreamInterface
109115
return $body;
110116
}
111117

118+
/**
119+
* Create the CSV response body from the contents of an array
120+
* @param array|Traversable $text
121+
* @return StreamInterface
122+
*/
123+
public function createBodyFromIterable($text) : StreamInterface
124+
{
125+
$body = new Stream('php://temp', 'wb+');
126+
$last = end($text);
127+
reset($text);
128+
129+
foreach ($text as $row) {
130+
$body->write($this->getRecord($row, $last));
131+
}
132+
$body->rewind();
133+
134+
return $body;
135+
}
136+
112137
/**
113138
* Get a fully rendered CSV record
114139
* @param array $row

test/Response/CsvResponseTest.php

+95
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,101 @@ public function testConstructorAcceptsBodyAsString()
2828
$this->assertSame(200, $response->getStatusCode());
2929
}
3030

31+
/**
32+
* @dataProvider arrayToBodyDataProvider
33+
* @param array $input
34+
* @param string $output
35+
* @param array $options
36+
*/
37+
public function testConstructorAcceptsArrayAsBody($input, string $output, array $options)
38+
{
39+
$response = new CsvResponse($input, $options);
40+
$this->assertSame($output, (string) $response->getBody());
41+
$this->assertSame(200, $response->getStatusCode());
42+
}
43+
44+
public function arrayToBodyDataProvider()
45+
{
46+
$bodyWithCommaAsFieldSeparatorOutput = <<<EOF
47+
first,last,email,dob
48+
john,citizen,[email protected],01/01/1970
49+
EOF;
50+
51+
$bodyWithTabAsFieldSeparatorOutput = <<<EOF
52+
first last email dob
53+
john citizen [email protected] 01/01/1970
54+
EOF;
55+
56+
$bodyWithSemicolonAsFieldSeparatorOutput = <<<EOF
57+
first;last;email;dob
58+
john;citizen;[email protected];01/01/1970
59+
EOF;
60+
61+
$bodyWithSemicolonAsFieldSeparatorAndCarriageReturnNewlineAsLineEndingOutput = <<<EOF
62+
first;last;email;dob\r
63+
john;citizen;[email protected];01/01/1970
64+
EOF;
65+
66+
$iterator = new \ArrayIterator(
67+
[
68+
["first","last","email","dob"],
69+
["john","citizen","[email protected]","01/01/1970"],
70+
]
71+
);
72+
73+
return [
74+
[
75+
[
76+
["first","last","email","dob"],
77+
["john","citizen","[email protected]","01/01/1970"],
78+
],
79+
$bodyWithCommaAsFieldSeparatorOutput,
80+
[
81+
"field_separator" => ',',
82+
],
83+
],
84+
[
85+
[
86+
["first","last","email","dob"],
87+
["john","citizen","[email protected]","01/01/1970"],
88+
],
89+
$bodyWithTabAsFieldSeparatorOutput,
90+
[
91+
"field_separator" => "\t",
92+
],
93+
],
94+
[
95+
[
96+
["first","last","email","dob"],
97+
["john","citizen","[email protected]","01/01/1970"],
98+
],
99+
$bodyWithSemicolonAsFieldSeparatorOutput,
100+
[
101+
"field_separator" => ";",
102+
],
103+
],
104+
[
105+
[
106+
["first","last","email","dob"],
107+
["john","citizen","[email protected]","01/01/1970"],
108+
],
109+
$bodyWithSemicolonAsFieldSeparatorAndCarriageReturnNewlineAsLineEndingOutput,
110+
[
111+
"field_separator" => ";",
112+
"line_ending" => "\r\n",
113+
],
114+
],
115+
[
116+
$iterator,
117+
$bodyWithSemicolonAsFieldSeparatorAndCarriageReturnNewlineAsLineEndingOutput,
118+
[
119+
"field_separator" => ";",
120+
"line_ending" => "\r\n",
121+
],
122+
],
123+
];
124+
}
125+
31126
public function testConstructorAllowsPassingStatus()
32127
{
33128
$status = 404;

0 commit comments

Comments
 (0)