Passed
Push — feature/53-multi-sheet-writing ( 617449...9e65cf )
by Stefan
02:06
created

Writer::setFreezePaneCellId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace OneSheet;
4
5
use OneSheet\Size\SizeCalculator;
6
use OneSheet\Style\Style;
7
use OneSheet\Style\Styler;
8
9
class Writer
10
{
11
    /**
12
     * @var SheetFile[]
13
     */
14
    private $sheetFiles;
15
16
    /**
17
     * @var Styler
18
     */
19
    private $styler;
20
21
    /**
22
     * @var Sheet[]
23
     */
24
    private $sheets;
25
26
    /**
27
     * @var Workbook
28
     */
29
    private $workbook;
30
31
    /**
32
     * @var resource
33
     */
34
    private $output;
35
36
    /**
37
     * @var string
38
     */
39
    private $currentSheet;
40
41
    /**
42
     * If a $fontsDirectory is supplied it will be scanned for usable ttf/otf fonts
43
     * to be used for cell auto-sizing. Keep in mind though - viewers of an excel
44
     * file have to have that font on their machine. XLSX does not embed fonts!
45
     *
46
     * @param string|null $fontsDirectory
47
     * @param string|int  $sheetName
48
     * @throws \Exception
49
     */
50 14
    public function __construct($fontsDirectory = null, $sheetName = 'sheet1')
51
    {
52 14
        $this->styler = new Styler();
53 14
        $this->switchSheet($sheetName, $fontsDirectory);
54 12
        $this->workbook = new Workbook();
55 12
    }
56
57
    /**
58
     * All cells _above_ this cell (e.g. A2) will be frozen/fixed.
59
     *
60
     * @param string $cellId
61
     */
62 1
    public function setFreezePaneCellId($cellId)
63
    {
64 1
        $this->sheets[$this->currentSheet]->setFreezePaneCellId($cellId);
65 1
    }
66
67
    /**
68
     * Set the range of rows to repeat at the top of each page when printing the
69
     * excel file. $startRow=1 and $endRow=1 will repeat the first row only.
70
     *
71
     * @param int $startRow
72
     * @param int $endRow
73
     */
74 1
    public function setPrintTitleRange($startRow, $endRow)
75
    {
76 1
        $this->workbook->setPrintTitleRange($startRow, $endRow, $this->currentSheet);
77 1
    }
78
79
    /**
80
     * Set fixed column widths per cell (no ranges) and array index
81
     * 0 being the first column.
82
     * If used alongside cell autosizing, these should be set
83
     * after the last row has been added.
84
     *
85
     * @param array $columnWidths
86
     * @throws \InvalidArgumentException
87
     */
88 1
    public function setFixedColumnWidths(array $columnWidths)
89
    {
90 1
        $this->sheets[$this->currentSheet]->setFixedColumnWidths($columnWidths);
91 1
    }
92
93
    /**
94
     * Set lower and/or upper limits for column widths.
95
     *
96
     * @param int|float|null $minWidth
97
     * @param int|float|null $maxWidth
98
     */
99 1
    public function setColumnWidthLimits($minWidth = null, $maxWidth = null)
100
    {
101 1
        $this->sheets[$this->currentSheet]->setColumnWidthLimits($minWidth, $maxWidth);
102 1
    }
103
104
    /**
105
     * Start recording row specs for column auto-sizing.
106
     *
107
     * @return Writer
108
     */
109 3
    public function enableCellAutosizing()
110
    {
111 3
        $this->sheets[$this->currentSheet]->enableCellAutosizing();
112 3
        return $this;
113
    }
114
115
    /**
116
     * Stop recording row specs for column auto-sizing.
117
     *
118
     * @return Writer
119
     */
120 1
    public function disableCellAutosizing()
121
    {
122 1
        $this->sheets[$this->currentSheet]->disableCellAutosizing();
123 1
        return $this;
124
    }
125
126
    /**
127
     * Add multiple rows at once.
128
     *
129
     * @param array|\Traversable $rows
130
     * @param Style              $style
131
     * @throws \InvalidArgumentException
132
     */
133 4
    public function addRows($rows, Style $style = null)
134
    {
135 4
        if (!is_array($rows) && false === $rows instanceof \Traversable) {
136 1
            throw new \InvalidArgumentException('Expected array or traversable object as rows');
137
        }
138
139 3
        foreach ($rows as $row) {
140 3
            $this->addRow($row, $style);
141
        }
142 3
    }
143
144
    /**
145
     * Add a single new row to the sheet and supply an optional style.
146
     *
147
     * @param array $row
148
     * @param Style $style
149
     */
150 4
    public function addRow(array $row, Style $style = null)
151
    {
152 4
        if (!empty($row)) {
153 4
            $style = $style instanceof Style ? $style : $this->styler->getDefaultStyle();
154 4
            $this->styler->addStyle($style);
155 4
            $this->sheetFiles[$this->currentSheet]->fwrite(
156 4
                $this->sheets[$this->currentSheet]->addRow($row, $style)
157
            );
158
        }
159 4
    }
160
161
    /**
162
     * @param string|int  $sheetName
163
     * @param string|null $fontsDirectory
164
     * @throws \Exception
165
     */
166 14
    public function switchSheet($sheetName, $fontsDirectory = null)
167
    {
168 14
        $sheetName = is_int($sheetName) ? sprintf('sheet%s', $sheetName) : $sheetName;
169 14
        isset($this->sheets[$sheetName]) || $this->createNewSheet($fontsDirectory, $sheetName);
170 12
        $this->currentSheet = $sheetName;
171 12
    }
172
173
    /**
174
     * Wrap things up and write xlsx.
175
     *
176
     * @param string $fileName
177
     */
178 3
    public function writeToFile($fileName = 'report.xlsx')
179
    {
180 3
        $this->output = fopen($fileName, 'w');
181 3
        $finalizer = new Finalizer($this->sheets, $this->styler, $this->sheetFiles, $this->workbook);
182 3
        $finalizer->finalize($this->output);
183 3
    }
184
185
    /**
186
     * Wrap things up and send xlsx to browser.
187
     *
188
     * @param string $fileName
189
     */
190 1
    public function writeToBrowser($fileName = 'report.xlsx')
191
    {
192 1
        $this->output = fopen('php://output', 'w');
193 1
        $finalizer = new Finalizer($this->sheets, $this->styler, $this->sheetFiles, $this->workbook);
194 1
        $this->sendHeaders($fileName);
195 1
        $finalizer->finalize($this->output);
196 1
    }
197
198
    /**
199
     * Send headers for browser output.
200
     *
201
     * @param string $fileName
202
     */
203 1
    private function sendHeaders($fileName)
204
    {
205 1
        if (!headers_sent()) {
206
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
207
            header('Content-Disposition: attachment; filename="' . $fileName . '"');
208
            header('Cache-Control: max-age=0');
209
            header('Pragma: public');
210
        }
211 1
    }
212
213
    /**
214
     * @param string $fontsDirectory
215
     * @param string $sheetName
216
     * @throws \Exception|\InvalidArgumentException
217
     */
218 14
    private function createNewSheet($fontsDirectory, $sheetName)
219
    {
220 14
        $pattern = '\/*?:\[\]';
221 14
        if (strlen($sheetName) === 0 || 1 === preg_match('~[' . $pattern . ']~', $sheetName)) {
222 2
            throw new \InvalidArgumentException(
223 2
                sprintf('sheet name must not be empty and not contain %s', $pattern)
224
            );
225
        }
226 12
        $this->sheetFiles[$sheetName] = new SheetFile();
227 12
        $this->sheetFiles[$sheetName]->fwrite(str_repeat(' ', 1024 * 1024) . '<sheetData>');
228 12
        $this->sheets[$sheetName] = new Sheet(new CellBuilder(), new SizeCalculator($fontsDirectory));
229 12
    }
230
231
    /**
232
     * Return array of available fonts & paths as key value pairs.
233
     *
234
     * @return array
235
     */
236 1
    public function getFonts()
237
    {
238 1
        return $this->sheets[$this->currentSheet]->getFonts();
239
    }
240
}
241