Skip to content

Commit a1b1d59

Browse files
committed
Refactor: drop contributte/application (copy CsvResponse to datagrid)
1 parent b422d37 commit a1b1d59

File tree

3 files changed

+141
-3
lines changed

3 files changed

+141
-3
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
],
2626
"require": {
2727
"php": ">=8.1",
28-
"contributte/application": "^0.5.0",
28+
"nette/application": "^3.2.0",
2929
"nette/di": "^3.0.0",
3030
"nette/forms": "^3.2.0",
3131
"nette/utils": "^4.0.0",

src/Export/ExportCsv.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
namespace Contributte\Datagrid\Export;
44

5-
use Contributte\Application\Response\CSVResponse;
65
use Contributte\Datagrid\CsvDataModel;
76
use Contributte\Datagrid\Datagrid;
7+
use Contributte\Datagrid\Response\CsvResponse;
88

99
class ExportCsv extends Export
1010
{
@@ -55,7 +55,7 @@ private function getExportCallback(
5555

5656
$csvDataModel = new CsvDataModel($data, $columns, $this->grid->getTranslator());
5757

58-
$this->grid->getPresenter()->sendResponse(new CSVResponse(
58+
$this->grid->getPresenter()->sendResponse(new CsvResponse(
5959
$csvDataModel->getSimpleData(),
6060
$name,
6161
$outputEncoding,

src/Response/CsvResponse.php

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Contributte\Datagrid\Response;
4+
5+
use Nette\Application\Response;
6+
use Nette\Http\IRequest as HttpRequest;
7+
use Nette\Http\IResponse as HttpResponse;
8+
use Nette\InvalidStateException;
9+
use Tracy\Debugger;
10+
11+
/**
12+
* CSV file download response
13+
*/
14+
class CsvResponse implements Response
15+
{
16+
17+
protected string $contentType = 'application/octet-stream';
18+
19+
protected string $delimiter;
20+
21+
/** @var array<int|string, array<scalar>> */
22+
protected array $data;
23+
24+
protected string $outputEncoding;
25+
26+
protected bool $includeBom;
27+
28+
protected string $name;
29+
30+
/** @var string[] */
31+
protected array $headers = [
32+
'Expires' => '0',
33+
'Cache-Control' => 'no-cache',
34+
'Pragma' => 'Public',
35+
];
36+
37+
/**
38+
* @param array<int|string, array<scalar>> $data Input data
39+
*/
40+
public function __construct(
41+
array $data,
42+
string $name = 'export.csv',
43+
string $outputEncoding = 'utf-8',
44+
string $delimiter = ';',
45+
bool $includeBom = false
46+
)
47+
{
48+
if (strpos($name, '.csv') === false) {
49+
$name = sprintf('%s.csv', $name);
50+
}
51+
52+
$this->name = $name;
53+
$this->delimiter = $delimiter;
54+
$this->data = $data;
55+
$this->outputEncoding = $outputEncoding;
56+
$this->includeBom = $includeBom;
57+
}
58+
59+
public function send(HttpRequest $httpRequest, HttpResponse $httpResponse): void
60+
{
61+
// Disable tracy bar
62+
if (class_exists(Debugger::class)) {
63+
Debugger::$productionMode = true;
64+
}
65+
66+
// Set Content-Type header
67+
$httpResponse->setContentType($this->contentType, $this->outputEncoding);
68+
69+
// Set Content-Disposition header
70+
$httpResponse->setHeader('Content-Disposition', sprintf('attachment; filename="%s"', $this->name));
71+
72+
// Set other headers
73+
foreach ($this->headers as $key => $value) {
74+
$httpResponse->setHeader($key, $value);
75+
}
76+
77+
if (function_exists('ob_start')) {
78+
ob_start();
79+
}
80+
81+
// Output data
82+
if ($this->includeBom) {
83+
echo $this->getBom();
84+
}
85+
86+
foreach ($this->data as $row) {
87+
$csvRow = $this->printCsv((array) $row); // @phpstan-ignore-line
88+
89+
if (strtolower($this->outputEncoding) === 'utf-8') {
90+
echo $csvRow;
91+
} elseif (strtolower($this->outputEncoding) === 'windows-1250') {
92+
echo iconv('utf-8', $this->outputEncoding, $csvRow);
93+
} else {
94+
echo mb_convert_encoding($csvRow, $this->outputEncoding);
95+
}
96+
}
97+
98+
if (function_exists('ob_end_flush')) {
99+
ob_end_flush();
100+
}
101+
}
102+
103+
private function getBom(): string
104+
{
105+
switch (strtolower($this->outputEncoding)) {
106+
case 'utf-8':
107+
return b"\xEF\xBB\xBF";
108+
case 'utf-16':
109+
return b"\xFF\xFE";
110+
default:
111+
return '';
112+
}
113+
}
114+
115+
/**
116+
* @param array<scalar> $row
117+
*/
118+
private function printCsv(array $row): string
119+
{
120+
$out = fopen('php://memory', 'wb+');
121+
122+
if ($out === false) {
123+
throw new InvalidStateException('Unable to open memory stream');
124+
}
125+
126+
fputcsv($out, $row, $this->delimiter, escape: '\\');
127+
rewind($out);
128+
$c = stream_get_contents($out);
129+
fclose($out);
130+
131+
if ($c === false) {
132+
throw new InvalidStateException('Unable to read from memory stream');
133+
}
134+
135+
return $c;
136+
}
137+
138+
}

0 commit comments

Comments
 (0)