Export::printCsv()   C
last analyzed

Complexity

Conditions 12
Paths 90

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 38
cts 38
cp 1
rs 6.9666
c 0
b 0
f 0
cc 12
nc 90
nop 0
crap 12

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the Grido (https://github.com/o5/grido)
5
 *
6
 * Copyright (c) 2011 Petr Bugyík (http://petr.bugyik.cz)
7
 *
8
 * For the full copyright and license information, please view
9
 * the file LICENSE.md that was distributed with this source code.
10
 */
11
12
namespace Grido\Components;
13
14
use Grido\Grid;
15
use Grido\Components\Columns\Column;
16
use Nette\Utils\Strings;
17
18
/**
19
 * Exporting data to CSV.
20
 *
21
 * @package     Grido
22
 * @subpackage  Components
23
 * @author      Petr Bugyík
24
 *
25
 * @property int $fetchLimit
26
 * @property-write array $header
27
 * @property-write callable $customData
28
 */
29 1
class Export extends Component implements \Nette\Application\IResponse
30
{
31
    const ID = 'export';
32
33
    /** @var int */
34
    protected $fetchLimit = 100000;
35
36
    /** @var array */
37
    protected $header = [];
38
39
    /** @var callable */
40
    protected $customData;
41
42
    /**
43
     * @param Grid $grid
44
     * @param string $label
45
     */
46
    public function __construct(Grid $grid, $label = NULL)
47
    {
48 1
        $this->grid = $grid;
49 1
        $this->label = $label;
50
51 1
        $grid->addComponent($this, self::ID);
52 1
    }
53
54
    /**
55
     * @return void
56
     */
57
    protected function printCsv()
58
    {
59 1
        $escape = function($value) {
60 1
            return preg_match("~[\"\n,;\t]~", $value) || $value === ""
61 1
                ? '"' . str_replace('"', '""', $value) . '"'
62 1
                : $value;
63 1
        };
64
65 1
        $print = function(array $row) {
66 1
            print implode(',', $row) . "\n";
67 1
        };
68
69 1
        $columns = $this->grid[Column::ID]->getComponents();
70
71 1
        $header = [];
72 1
        $headerItems = $this->header ? $this->header : $columns;
73 1
        foreach ($headerItems as $column) {
74 1
            $header[] = $this->header
75 1
                ? $escape($column)
76 1
                : $escape($column->getLabel());
77 1
        }
78
79 1
        $print($header);
80
81 1
        $datasource = $this->grid->getData(FALSE, FALSE, FALSE);
82 1
        $iterations = ceil($datasource->getCount() / $this->fetchLimit);
83 1
        for ($i = 0; $i < $iterations; $i++) {
84 1
            $datasource->limit($i * $this->fetchLimit, $this->fetchLimit);
85 1
            $data = $this->customData
86 1
                ? call_user_func_array($this->customData, [$datasource])
87 1
                : $datasource->getData();
88
89 1
            foreach ($data as $items) {
90 1
                $row = [];
91
92 1
                $columns = $this->customData
93 1
                    ? $items
94 1
                    : $columns;
95
96 1
                foreach ($columns as $column) {
97 1
                    $row[] = $this->customData
98 1
                        ? $escape($column)
99 1
                        : $escape($column->renderExport($items));
100 1
                }
101
102 1
                $print($row);
103 1
            }
104 1
        }
105 1
    }
106
107
    /**
108
     * Sets a limit which will be used in order to retrieve data from datasource.
109
     * @param int $limit
110
     * @return \Grido\Components\Export
111
     */
112
    public function setFetchLimit($limit)
113
    {
114 1
        $this->fetchLimit = (int) $limit;
115 1
        return $this;
116
    }
117
118
    /**
119
     * @return int
120
     */
121
    public function getFetchLimit()
122
    {
123 1
        return $this->fetchLimit;
124
    }
125
126
    /**
127
     * Sets a custom header of result CSV file (list of field names).
128
     * @param array $header
129
     * @return \Grido\Components\Export
130
     */
131
    public function setHeader(array $header)
132
    {
133 1
        $this->header = $header;
134 1
        return $this;
135
    }
136
137
    /**
138
     * Sets a callback to modify output data. This callback must return a list of items. (array) function($datasource)
139
     * DEBUG? You probably need to comment lines started with $httpResponse->setHeader in Grido\Components\Export.php
140
     * @param callable $callback
141
     * @return \Grido\Components\Export
142
     */
143
    public function setCustomData($callback)
144
    {
145 1
        $this->customData = $callback;
146 1
        return $this;
147
    }
148
149
    /**
150
     * @internal
151
     */
152
    public function handleExport()
153
    {
154 1
        !empty($this->grid->onRegistered) && $this->grid->onRegistered($this->grid);
155 1
        $this->grid->presenter->sendResponse($this);
156
    }
157
158
    /*************************** interface \Nette\Application\IResponse ***************************/
159
160
    /**
161
     * Sends response to output.
162
     * @param \Nette\Http\IRequest $httpRequest
163
     * @param \Nette\Http\IResponse $httpResponse
164
     * @return void
165
     */
166
    public function send(\Nette\Http\IRequest $httpRequest, \Nette\Http\IResponse $httpResponse): void
167
    {
168 1
        $encoding = 'utf-8';
169 1
        $label = $this->label
170 1
            ? ucfirst(Strings::webalize($this->label))
171 1
            : ucfirst($this->grid->getName());
172
173 1
        $httpResponse->setHeader('Content-Encoding', $encoding);
174 1
        $httpResponse->setHeader('Content-Type', "text/csv; charset=$encoding");
175 1
        $httpResponse->setHeader('Content-Disposition', "attachment; filename=\"$label.csv\"");
176
177 1
        print chr(0xEF) . chr(0xBB) . chr(0xBF); //UTF-8 BOM
178 1
        $this->printCsv();
179 1
    }
180
}
181