1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; |
4
|
|
|
|
5
|
|
|
use PhpOffice\PhpSpreadsheet\Cell\Cell; |
6
|
|
|
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; |
7
|
|
|
use PhpOffice\PhpSpreadsheet\RichText\RichText; |
8
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\StringHelper; |
9
|
|
|
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; |
10
|
|
|
use PhpOffice\PhpSpreadsheet\Style\Conditional; |
11
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; |
12
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; |
13
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView; |
14
|
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet; |
15
|
|
|
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @category PhpSpreadsheet |
19
|
|
|
* |
20
|
|
|
* @copyright Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet) |
21
|
|
|
*/ |
22
|
|
|
class Worksheet extends WriterPart |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* Write worksheet to XML format. |
26
|
|
|
* |
27
|
|
|
* @param PhpspreadsheetWorksheet $pSheet |
28
|
|
|
* @param string[] $pStringTable |
29
|
|
|
* @param bool $includeCharts Flag indicating if we should write charts |
30
|
|
|
* |
31
|
|
|
* @throws WriterException |
32
|
|
|
* |
33
|
|
|
* @return string XML Output |
34
|
|
|
*/ |
35
|
60 |
|
public function writeWorksheet(PhpspreadsheetWorksheet $pSheet, $pStringTable = null, $includeCharts = false) |
36
|
|
|
{ |
37
|
|
|
// Create XML writer |
38
|
60 |
|
$objWriter = null; |
39
|
60 |
|
if ($this->getParentWriter()->getUseDiskCaching()) { |
40
|
|
|
$objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); |
41
|
|
|
} else { |
42
|
60 |
|
$objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
// XML header |
46
|
60 |
|
$objWriter->startDocument('1.0', 'UTF-8', 'yes'); |
47
|
|
|
|
48
|
|
|
// Worksheet |
49
|
60 |
|
$objWriter->startElement('worksheet'); |
50
|
60 |
|
$objWriter->writeAttribute('xml:space', 'preserve'); |
51
|
60 |
|
$objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'); |
52
|
60 |
|
$objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); |
53
|
|
|
|
54
|
|
|
// sheetPr |
55
|
60 |
|
$this->writeSheetPr($objWriter, $pSheet); |
56
|
|
|
|
57
|
|
|
// Dimension |
58
|
60 |
|
$this->writeDimension($objWriter, $pSheet); |
59
|
|
|
|
60
|
|
|
// sheetViews |
61
|
60 |
|
$this->writeSheetViews($objWriter, $pSheet); |
62
|
|
|
|
63
|
|
|
// sheetFormatPr |
64
|
60 |
|
$this->writeSheetFormatPr($objWriter, $pSheet); |
65
|
|
|
|
66
|
|
|
// cols |
67
|
60 |
|
$this->writeCols($objWriter, $pSheet); |
68
|
|
|
|
69
|
|
|
// sheetData |
70
|
60 |
|
$this->writeSheetData($objWriter, $pSheet, $pStringTable); |
71
|
|
|
|
72
|
|
|
// sheetProtection |
73
|
60 |
|
$this->writeSheetProtection($objWriter, $pSheet); |
74
|
|
|
|
75
|
|
|
// protectedRanges |
76
|
60 |
|
$this->writeProtectedRanges($objWriter, $pSheet); |
77
|
|
|
|
78
|
|
|
// autoFilter |
79
|
60 |
|
$this->writeAutoFilter($objWriter, $pSheet); |
80
|
|
|
|
81
|
|
|
// mergeCells |
82
|
60 |
|
$this->writeMergeCells($objWriter, $pSheet); |
83
|
|
|
|
84
|
|
|
// conditionalFormatting |
85
|
60 |
|
$this->writeConditionalFormatting($objWriter, $pSheet); |
86
|
|
|
|
87
|
|
|
// dataValidations |
88
|
60 |
|
$this->writeDataValidations($objWriter, $pSheet); |
89
|
|
|
|
90
|
|
|
// hyperlinks |
91
|
60 |
|
$this->writeHyperlinks($objWriter, $pSheet); |
92
|
|
|
|
93
|
|
|
// Print options |
94
|
60 |
|
$this->writePrintOptions($objWriter, $pSheet); |
95
|
|
|
|
96
|
|
|
// Page margins |
97
|
60 |
|
$this->writePageMargins($objWriter, $pSheet); |
98
|
|
|
|
99
|
|
|
// Page setup |
100
|
60 |
|
$this->writePageSetup($objWriter, $pSheet); |
101
|
|
|
|
102
|
|
|
// Header / footer |
103
|
60 |
|
$this->writeHeaderFooter($objWriter, $pSheet); |
104
|
|
|
|
105
|
|
|
// Breaks |
106
|
60 |
|
$this->writeBreaks($objWriter, $pSheet); |
107
|
|
|
|
108
|
|
|
// Drawings and/or Charts |
109
|
60 |
|
$this->writeDrawings($objWriter, $pSheet, $includeCharts); |
110
|
|
|
|
111
|
|
|
// LegacyDrawing |
112
|
60 |
|
$this->writeLegacyDrawing($objWriter, $pSheet); |
113
|
|
|
|
114
|
|
|
// LegacyDrawingHF |
115
|
60 |
|
$this->writeLegacyDrawingHF($objWriter, $pSheet); |
116
|
|
|
|
117
|
60 |
|
$objWriter->endElement(); |
118
|
|
|
|
119
|
|
|
// Return |
120
|
60 |
|
return $objWriter->getData(); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Write SheetPr. |
125
|
|
|
* |
126
|
|
|
* @param XMLWriter $objWriter XML Writer |
127
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
128
|
|
|
*/ |
129
|
60 |
|
private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
130
|
|
|
{ |
131
|
|
|
// sheetPr |
132
|
60 |
|
$objWriter->startElement('sheetPr'); |
133
|
60 |
|
if ($pSheet->getParent()->hasMacros()) { |
134
|
|
|
//if the workbook have macros, we need to have codeName for the sheet |
135
|
|
|
if ($pSheet->hasCodeName() == false) { |
136
|
|
|
$pSheet->setCodeName($pSheet->getTitle()); |
137
|
|
|
} |
138
|
|
|
$objWriter->writeAttribute('codeName', $pSheet->getCodeName()); |
139
|
|
|
} |
140
|
60 |
|
$autoFilterRange = $pSheet->getAutoFilter()->getRange(); |
141
|
60 |
|
if (!empty($autoFilterRange)) { |
142
|
3 |
|
$objWriter->writeAttribute('filterMode', 1); |
143
|
3 |
|
$pSheet->getAutoFilter()->showHideRows(); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
// tabColor |
147
|
60 |
|
if ($pSheet->isTabColorSet()) { |
148
|
6 |
|
$objWriter->startElement('tabColor'); |
149
|
6 |
|
$objWriter->writeAttribute('rgb', $pSheet->getTabColor()->getARGB()); |
150
|
6 |
|
$objWriter->endElement(); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// outlinePr |
154
|
60 |
|
$objWriter->startElement('outlinePr'); |
155
|
60 |
|
$objWriter->writeAttribute('summaryBelow', ($pSheet->getShowSummaryBelow() ? '1' : '0')); |
156
|
60 |
|
$objWriter->writeAttribute('summaryRight', ($pSheet->getShowSummaryRight() ? '1' : '0')); |
157
|
60 |
|
$objWriter->endElement(); |
158
|
|
|
|
159
|
|
|
// pageSetUpPr |
160
|
60 |
|
if ($pSheet->getPageSetup()->getFitToPage()) { |
161
|
|
|
$objWriter->startElement('pageSetUpPr'); |
162
|
|
|
$objWriter->writeAttribute('fitToPage', '1'); |
163
|
|
|
$objWriter->endElement(); |
164
|
|
|
} |
165
|
|
|
|
166
|
60 |
|
$objWriter->endElement(); |
167
|
60 |
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Write Dimension. |
171
|
|
|
* |
172
|
|
|
* @param XMLWriter $objWriter XML Writer |
173
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
174
|
|
|
*/ |
175
|
60 |
|
private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
176
|
|
|
{ |
177
|
|
|
// dimension |
178
|
60 |
|
$objWriter->startElement('dimension'); |
179
|
60 |
|
$objWriter->writeAttribute('ref', $pSheet->calculateWorksheetDimension()); |
180
|
60 |
|
$objWriter->endElement(); |
181
|
60 |
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Write SheetViews. |
185
|
|
|
* |
186
|
|
|
* @param XMLWriter $objWriter XML Writer |
187
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
188
|
|
|
* |
189
|
|
|
* @throws WriterException |
190
|
|
|
*/ |
191
|
60 |
|
private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
192
|
|
|
{ |
193
|
|
|
// sheetViews |
194
|
60 |
|
$objWriter->startElement('sheetViews'); |
195
|
|
|
|
196
|
|
|
// Sheet selected? |
197
|
60 |
|
$sheetSelected = false; |
198
|
60 |
|
if ($this->getParentWriter()->getSpreadsheet()->getIndex($pSheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) { |
199
|
60 |
|
$sheetSelected = true; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
// sheetView |
203
|
60 |
|
$objWriter->startElement('sheetView'); |
204
|
60 |
|
$objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0'); |
205
|
60 |
|
$objWriter->writeAttribute('workbookViewId', '0'); |
206
|
|
|
|
207
|
|
|
// Zoom scales |
208
|
60 |
|
if ($pSheet->getSheetView()->getZoomScale() != 100) { |
209
|
|
|
$objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale()); |
210
|
|
|
} |
211
|
60 |
|
if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) { |
212
|
|
|
$objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal()); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
// View Layout Type |
216
|
60 |
|
if ($pSheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) { |
217
|
1 |
|
$objWriter->writeAttribute('view', $pSheet->getSheetView()->getView()); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
// Gridlines |
221
|
60 |
|
if ($pSheet->getShowGridlines()) { |
222
|
60 |
|
$objWriter->writeAttribute('showGridLines', 'true'); |
223
|
|
|
} else { |
224
|
|
|
$objWriter->writeAttribute('showGridLines', 'false'); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
// Row and column headers |
228
|
60 |
|
if ($pSheet->getShowRowColHeaders()) { |
229
|
60 |
|
$objWriter->writeAttribute('showRowColHeaders', '1'); |
230
|
|
|
} else { |
231
|
|
|
$objWriter->writeAttribute('showRowColHeaders', '0'); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
// Right-to-left |
235
|
60 |
|
if ($pSheet->getRightToLeft()) { |
236
|
|
|
$objWriter->writeAttribute('rightToLeft', 'true'); |
237
|
|
|
} |
238
|
|
|
|
239
|
60 |
|
$activeCell = $pSheet->getActiveCell(); |
240
|
|
|
|
241
|
|
|
// Pane |
242
|
60 |
|
$pane = ''; |
243
|
60 |
|
if ($pSheet->getFreezePane()) { |
244
|
4 |
|
list($xSplit, $ySplit) = Coordinate::coordinateFromString($pSheet->getFreezePane()); |
245
|
4 |
|
$xSplit = Coordinate::columnIndexFromString($xSplit); |
246
|
4 |
|
--$xSplit; |
247
|
4 |
|
--$ySplit; |
248
|
|
|
|
249
|
4 |
|
$topLeftCell = $pSheet->getTopLeftCell(); |
250
|
4 |
|
$activeCell = $topLeftCell; |
251
|
|
|
|
252
|
|
|
// pane |
253
|
4 |
|
$pane = 'topRight'; |
254
|
4 |
|
$objWriter->startElement('pane'); |
255
|
4 |
|
if ($xSplit > 0) { |
256
|
1 |
|
$objWriter->writeAttribute('xSplit', $xSplit); |
257
|
|
|
} |
258
|
4 |
|
if ($ySplit > 0) { |
259
|
4 |
|
$objWriter->writeAttribute('ySplit', $ySplit); |
260
|
4 |
|
$pane = ($xSplit > 0) ? 'bottomRight' : 'bottomLeft'; |
261
|
|
|
} |
262
|
4 |
|
$objWriter->writeAttribute('topLeftCell', $topLeftCell); |
263
|
4 |
|
$objWriter->writeAttribute('activePane', $pane); |
264
|
4 |
|
$objWriter->writeAttribute('state', 'frozen'); |
265
|
4 |
|
$objWriter->endElement(); |
266
|
|
|
|
267
|
4 |
|
if (($xSplit > 0) && ($ySplit > 0)) { |
268
|
|
|
// Write additional selections if more than two panes (ie both an X and a Y split) |
269
|
1 |
|
$objWriter->startElement('selection'); |
270
|
1 |
|
$objWriter->writeAttribute('pane', 'topRight'); |
271
|
1 |
|
$objWriter->endElement(); |
272
|
1 |
|
$objWriter->startElement('selection'); |
273
|
1 |
|
$objWriter->writeAttribute('pane', 'bottomLeft'); |
274
|
1 |
|
$objWriter->endElement(); |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
// Selection |
279
|
|
|
// Only need to write selection element if we have a split pane |
280
|
|
|
// We cheat a little by over-riding the active cell selection, setting it to the split cell |
281
|
60 |
|
$objWriter->startElement('selection'); |
282
|
60 |
|
if ($pane != '') { |
283
|
4 |
|
$objWriter->writeAttribute('pane', $pane); |
284
|
|
|
} |
285
|
60 |
|
$objWriter->writeAttribute('activeCell', $activeCell); |
286
|
60 |
|
$objWriter->writeAttribute('sqref', $activeCell); |
287
|
60 |
|
$objWriter->endElement(); |
288
|
|
|
|
289
|
60 |
|
$objWriter->endElement(); |
290
|
|
|
|
291
|
60 |
|
$objWriter->endElement(); |
292
|
60 |
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Write SheetFormatPr. |
296
|
|
|
* |
297
|
|
|
* @param XMLWriter $objWriter XML Writer |
298
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
299
|
|
|
*/ |
300
|
60 |
|
private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
301
|
|
|
{ |
302
|
|
|
// sheetFormatPr |
303
|
60 |
|
$objWriter->startElement('sheetFormatPr'); |
304
|
|
|
|
305
|
|
|
// Default row height |
306
|
60 |
|
if ($pSheet->getDefaultRowDimension()->getRowHeight() >= 0) { |
307
|
2 |
|
$objWriter->writeAttribute('customHeight', 'true'); |
308
|
2 |
|
$objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($pSheet->getDefaultRowDimension()->getRowHeight())); |
309
|
|
|
} else { |
310
|
58 |
|
$objWriter->writeAttribute('defaultRowHeight', '14.4'); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
// Set Zero Height row |
314
|
60 |
|
if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() == '1' || |
315
|
60 |
|
strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') { |
316
|
|
|
$objWriter->writeAttribute('zeroHeight', '1'); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
// Default column width |
320
|
60 |
|
if ($pSheet->getDefaultColumnDimension()->getWidth() >= 0) { |
321
|
1 |
|
$objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($pSheet->getDefaultColumnDimension()->getWidth())); |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
// Outline level - row |
325
|
60 |
|
$outlineLevelRow = 0; |
326
|
60 |
|
foreach ($pSheet->getRowDimensions() as $dimension) { |
327
|
11 |
|
if ($dimension->getOutlineLevel() > $outlineLevelRow) { |
328
|
11 |
|
$outlineLevelRow = $dimension->getOutlineLevel(); |
329
|
|
|
} |
330
|
|
|
} |
331
|
60 |
|
$objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow); |
332
|
|
|
|
333
|
|
|
// Outline level - column |
334
|
60 |
|
$outlineLevelCol = 0; |
335
|
60 |
|
foreach ($pSheet->getColumnDimensions() as $dimension) { |
336
|
21 |
|
if ($dimension->getOutlineLevel() > $outlineLevelCol) { |
337
|
21 |
|
$outlineLevelCol = $dimension->getOutlineLevel(); |
338
|
|
|
} |
339
|
|
|
} |
340
|
60 |
|
$objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol); |
341
|
|
|
|
342
|
60 |
|
$objWriter->endElement(); |
343
|
60 |
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Write Cols. |
347
|
|
|
* |
348
|
|
|
* @param XMLWriter $objWriter XML Writer |
349
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
350
|
|
|
*/ |
351
|
60 |
|
private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
352
|
|
|
{ |
353
|
|
|
// cols |
354
|
60 |
|
if (count($pSheet->getColumnDimensions()) > 0) { |
355
|
21 |
|
$objWriter->startElement('cols'); |
356
|
|
|
|
357
|
21 |
|
$pSheet->calculateColumnWidths(); |
358
|
|
|
|
359
|
|
|
// Loop through column dimensions |
360
|
21 |
|
foreach ($pSheet->getColumnDimensions() as $colDimension) { |
361
|
|
|
// col |
362
|
21 |
|
$objWriter->startElement('col'); |
363
|
21 |
|
$objWriter->writeAttribute('min', Coordinate::columnIndexFromString($colDimension->getColumnIndex())); |
364
|
21 |
|
$objWriter->writeAttribute('max', Coordinate::columnIndexFromString($colDimension->getColumnIndex())); |
365
|
|
|
|
366
|
21 |
|
if ($colDimension->getWidth() < 0) { |
367
|
|
|
// No width set, apply default of 10 |
368
|
2 |
|
$objWriter->writeAttribute('width', '9.10'); |
369
|
|
|
} else { |
370
|
|
|
// Width set |
371
|
21 |
|
$objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth())); |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
// Column visibility |
375
|
21 |
|
if ($colDimension->getVisible() == false) { |
376
|
3 |
|
$objWriter->writeAttribute('hidden', 'true'); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
// Auto size? |
380
|
21 |
|
if ($colDimension->getAutoSize()) { |
381
|
8 |
|
$objWriter->writeAttribute('bestFit', 'true'); |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
// Custom width? |
385
|
21 |
|
if ($colDimension->getWidth() != $pSheet->getDefaultColumnDimension()->getWidth()) { |
386
|
21 |
|
$objWriter->writeAttribute('customWidth', 'true'); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
// Collapsed |
390
|
21 |
|
if ($colDimension->getCollapsed() == true) { |
391
|
1 |
|
$objWriter->writeAttribute('collapsed', 'true'); |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
// Outline level |
395
|
21 |
|
if ($colDimension->getOutlineLevel() > 0) { |
396
|
1 |
|
$objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel()); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
// Style |
400
|
21 |
|
$objWriter->writeAttribute('style', $colDimension->getXfIndex()); |
401
|
|
|
|
402
|
21 |
|
$objWriter->endElement(); |
403
|
|
|
} |
404
|
|
|
|
405
|
21 |
|
$objWriter->endElement(); |
406
|
|
|
} |
407
|
60 |
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* Write SheetProtection. |
411
|
|
|
* |
412
|
|
|
* @param XMLWriter $objWriter XML Writer |
413
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
414
|
|
|
*/ |
415
|
60 |
|
private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
416
|
|
|
{ |
417
|
|
|
// sheetProtection |
418
|
60 |
|
$objWriter->startElement('sheetProtection'); |
419
|
|
|
|
420
|
60 |
|
if ($pSheet->getProtection()->getPassword() != '') { |
421
|
1 |
|
$objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword()); |
422
|
|
|
} |
423
|
|
|
|
424
|
60 |
|
$objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false')); |
425
|
60 |
|
$objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false')); |
426
|
60 |
|
$objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false')); |
427
|
60 |
|
$objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false')); |
428
|
60 |
|
$objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false')); |
429
|
60 |
|
$objWriter->writeAttribute('formatRows', ($pSheet->getProtection()->getFormatRows() ? 'true' : 'false')); |
430
|
60 |
|
$objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false')); |
431
|
60 |
|
$objWriter->writeAttribute('insertRows', ($pSheet->getProtection()->getInsertRows() ? 'true' : 'false')); |
432
|
60 |
|
$objWriter->writeAttribute('insertHyperlinks', ($pSheet->getProtection()->getInsertHyperlinks() ? 'true' : 'false')); |
433
|
60 |
|
$objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false')); |
434
|
60 |
|
$objWriter->writeAttribute('deleteRows', ($pSheet->getProtection()->getDeleteRows() ? 'true' : 'false')); |
435
|
60 |
|
$objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false')); |
436
|
60 |
|
$objWriter->writeAttribute('sort', ($pSheet->getProtection()->getSort() ? 'true' : 'false')); |
437
|
60 |
|
$objWriter->writeAttribute('autoFilter', ($pSheet->getProtection()->getAutoFilter() ? 'true' : 'false')); |
438
|
60 |
|
$objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false')); |
439
|
60 |
|
$objWriter->writeAttribute('selectUnlockedCells', ($pSheet->getProtection()->getSelectUnlockedCells() ? 'true' : 'false')); |
440
|
60 |
|
$objWriter->endElement(); |
441
|
60 |
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* Write ConditionalFormatting. |
445
|
|
|
* |
446
|
|
|
* @param XMLWriter $objWriter XML Writer |
447
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
448
|
|
|
* |
449
|
|
|
* @throws WriterException |
450
|
|
|
*/ |
451
|
60 |
|
private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
452
|
|
|
{ |
453
|
|
|
// Conditional id |
454
|
60 |
|
$id = 1; |
455
|
|
|
|
456
|
|
|
// Loop through styles in the current worksheet |
457
|
60 |
|
foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) { |
458
|
3 |
|
foreach ($conditionalStyles as $conditional) { |
459
|
|
|
// WHY was this again? |
460
|
|
|
// if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) == '') { |
|
|
|
|
461
|
|
|
// continue; |
462
|
|
|
// } |
463
|
3 |
|
if ($conditional->getConditionType() != Conditional::CONDITION_NONE) { |
464
|
|
|
// conditionalFormatting |
465
|
3 |
|
$objWriter->startElement('conditionalFormatting'); |
466
|
3 |
|
$objWriter->writeAttribute('sqref', $cellCoordinate); |
467
|
|
|
|
468
|
|
|
// cfRule |
469
|
3 |
|
$objWriter->startElement('cfRule'); |
470
|
3 |
|
$objWriter->writeAttribute('type', $conditional->getConditionType()); |
471
|
3 |
|
$objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode())); |
472
|
3 |
|
$objWriter->writeAttribute('priority', $id++); |
473
|
|
|
|
474
|
3 |
|
if (($conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT) |
475
|
3 |
|
&& $conditional->getOperatorType() != Conditional::OPERATOR_NONE) { |
476
|
3 |
|
$objWriter->writeAttribute('operator', $conditional->getOperatorType()); |
477
|
|
|
} |
478
|
|
|
|
479
|
3 |
|
if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT |
480
|
3 |
|
&& $conditional->getText() !== null) { |
481
|
|
|
$objWriter->writeAttribute('text', $conditional->getText()); |
482
|
|
|
} |
483
|
|
|
|
484
|
3 |
|
if ($conditional->getStopIfTrue()) { |
485
|
1 |
|
$objWriter->writeAttribute('stopIfTrue', '1'); |
486
|
|
|
} |
487
|
|
|
|
488
|
3 |
|
if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT |
489
|
3 |
|
&& $conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT |
490
|
3 |
|
&& $conditional->getText() !== null) { |
491
|
|
|
$objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))'); |
492
|
3 |
|
} elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT |
493
|
3 |
|
&& $conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH |
494
|
3 |
|
&& $conditional->getText() !== null) { |
495
|
|
|
$objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); |
496
|
3 |
|
} elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT |
497
|
3 |
|
&& $conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH |
498
|
3 |
|
&& $conditional->getText() !== null) { |
499
|
|
|
$objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); |
500
|
3 |
|
} elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT |
501
|
3 |
|
&& $conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS |
502
|
3 |
|
&& $conditional->getText() !== null) { |
503
|
|
|
$objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))'); |
504
|
3 |
|
} elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS |
505
|
1 |
|
|| $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT |
506
|
3 |
|
|| $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) { |
507
|
3 |
|
foreach ($conditional->getConditions() as $formula) { |
508
|
|
|
// Formula |
509
|
3 |
|
$objWriter->writeElement('formula', $formula); |
510
|
|
|
} |
511
|
|
|
} |
512
|
|
|
|
513
|
3 |
|
$objWriter->endElement(); |
514
|
|
|
|
515
|
3 |
|
$objWriter->endElement(); |
516
|
|
|
} |
517
|
|
|
} |
518
|
|
|
} |
519
|
60 |
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Write DataValidations. |
523
|
|
|
* |
524
|
|
|
* @param XMLWriter $objWriter XML Writer |
525
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
526
|
|
|
*/ |
527
|
60 |
|
private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
528
|
|
|
{ |
529
|
|
|
// Datavalidation collection |
530
|
60 |
|
$dataValidationCollection = $pSheet->getDataValidationCollection(); |
531
|
|
|
|
532
|
|
|
// Write data validations? |
533
|
60 |
|
if (!empty($dataValidationCollection)) { |
534
|
2 |
|
$dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection); |
535
|
2 |
|
$objWriter->startElement('dataValidations'); |
536
|
2 |
|
$objWriter->writeAttribute('count', count($dataValidationCollection)); |
537
|
|
|
|
538
|
2 |
|
foreach ($dataValidationCollection as $coordinate => $dv) { |
539
|
2 |
|
$objWriter->startElement('dataValidation'); |
540
|
|
|
|
541
|
2 |
|
if ($dv->getType() != '') { |
542
|
2 |
|
$objWriter->writeAttribute('type', $dv->getType()); |
543
|
|
|
} |
544
|
|
|
|
545
|
2 |
|
if ($dv->getErrorStyle() != '') { |
546
|
2 |
|
$objWriter->writeAttribute('errorStyle', $dv->getErrorStyle()); |
547
|
|
|
} |
548
|
|
|
|
549
|
2 |
|
if ($dv->getOperator() != '') { |
550
|
2 |
|
$objWriter->writeAttribute('operator', $dv->getOperator()); |
551
|
|
|
} |
552
|
|
|
|
553
|
2 |
|
$objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0')); |
554
|
2 |
|
$objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0')); |
555
|
2 |
|
$objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0')); |
556
|
2 |
|
$objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0')); |
557
|
|
|
|
558
|
2 |
|
if ($dv->getErrorTitle() !== '') { |
559
|
2 |
|
$objWriter->writeAttribute('errorTitle', $dv->getErrorTitle()); |
560
|
|
|
} |
561
|
2 |
|
if ($dv->getError() !== '') { |
562
|
2 |
|
$objWriter->writeAttribute('error', $dv->getError()); |
563
|
|
|
} |
564
|
2 |
|
if ($dv->getPromptTitle() !== '') { |
565
|
2 |
|
$objWriter->writeAttribute('promptTitle', $dv->getPromptTitle()); |
566
|
|
|
} |
567
|
2 |
|
if ($dv->getPrompt() !== '') { |
568
|
2 |
|
$objWriter->writeAttribute('prompt', $dv->getPrompt()); |
569
|
|
|
} |
570
|
|
|
|
571
|
2 |
|
$objWriter->writeAttribute('sqref', $coordinate); |
572
|
|
|
|
573
|
2 |
|
if ($dv->getFormula1() !== '') { |
574
|
2 |
|
$objWriter->writeElement('formula1', $dv->getFormula1()); |
575
|
|
|
} |
576
|
2 |
|
if ($dv->getFormula2() !== '') { |
577
|
1 |
|
$objWriter->writeElement('formula2', $dv->getFormula2()); |
578
|
|
|
} |
579
|
|
|
|
580
|
2 |
|
$objWriter->endElement(); |
581
|
|
|
} |
582
|
|
|
|
583
|
2 |
|
$objWriter->endElement(); |
584
|
|
|
} |
585
|
60 |
|
} |
586
|
|
|
|
587
|
|
|
/** |
588
|
|
|
* Write Hyperlinks. |
589
|
|
|
* |
590
|
|
|
* @param XMLWriter $objWriter XML Writer |
591
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
592
|
|
|
*/ |
593
|
60 |
|
private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
594
|
|
|
{ |
595
|
|
|
// Hyperlink collection |
596
|
60 |
|
$hyperlinkCollection = $pSheet->getHyperlinkCollection(); |
597
|
|
|
|
598
|
|
|
// Relation ID |
599
|
60 |
|
$relationId = 1; |
600
|
|
|
|
601
|
|
|
// Write hyperlinks? |
602
|
60 |
|
if (!empty($hyperlinkCollection)) { |
603
|
10 |
|
$objWriter->startElement('hyperlinks'); |
604
|
|
|
|
605
|
10 |
|
foreach ($hyperlinkCollection as $coordinate => $hyperlink) { |
606
|
10 |
|
$objWriter->startElement('hyperlink'); |
607
|
|
|
|
608
|
10 |
|
$objWriter->writeAttribute('ref', $coordinate); |
609
|
10 |
|
if (!$hyperlink->isInternal()) { |
610
|
10 |
|
$objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId); |
611
|
10 |
|
++$relationId; |
612
|
|
|
} else { |
613
|
7 |
|
$objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl())); |
614
|
|
|
} |
615
|
|
|
|
616
|
10 |
|
if ($hyperlink->getTooltip() != '') { |
617
|
6 |
|
$objWriter->writeAttribute('tooltip', $hyperlink->getTooltip()); |
618
|
|
|
} |
619
|
|
|
|
620
|
10 |
|
$objWriter->endElement(); |
621
|
|
|
} |
622
|
|
|
|
623
|
10 |
|
$objWriter->endElement(); |
624
|
|
|
} |
625
|
60 |
|
} |
626
|
|
|
|
627
|
|
|
/** |
628
|
|
|
* Write ProtectedRanges. |
629
|
|
|
* |
630
|
|
|
* @param XMLWriter $objWriter XML Writer |
631
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
632
|
|
|
*/ |
633
|
60 |
|
private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
634
|
|
|
{ |
635
|
60 |
|
if (count($pSheet->getProtectedCells()) > 0) { |
636
|
|
|
// protectedRanges |
637
|
6 |
|
$objWriter->startElement('protectedRanges'); |
638
|
|
|
|
639
|
|
|
// Loop protectedRanges |
640
|
6 |
|
foreach ($pSheet->getProtectedCells() as $protectedCell => $passwordHash) { |
641
|
|
|
// protectedRange |
642
|
6 |
|
$objWriter->startElement('protectedRange'); |
643
|
6 |
|
$objWriter->writeAttribute('name', 'p' . md5($protectedCell)); |
644
|
6 |
|
$objWriter->writeAttribute('sqref', $protectedCell); |
645
|
6 |
|
if (!empty($passwordHash)) { |
646
|
6 |
|
$objWriter->writeAttribute('password', $passwordHash); |
647
|
|
|
} |
648
|
6 |
|
$objWriter->endElement(); |
649
|
|
|
} |
650
|
|
|
|
651
|
6 |
|
$objWriter->endElement(); |
652
|
|
|
} |
653
|
60 |
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* Write MergeCells. |
657
|
|
|
* |
658
|
|
|
* @param XMLWriter $objWriter XML Writer |
659
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
660
|
|
|
*/ |
661
|
60 |
|
private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
662
|
|
|
{ |
663
|
60 |
|
if (count($pSheet->getMergeCells()) > 0) { |
664
|
|
|
// mergeCells |
665
|
13 |
|
$objWriter->startElement('mergeCells'); |
666
|
|
|
|
667
|
|
|
// Loop mergeCells |
668
|
13 |
|
foreach ($pSheet->getMergeCells() as $mergeCell) { |
669
|
|
|
// mergeCell |
670
|
13 |
|
$objWriter->startElement('mergeCell'); |
671
|
13 |
|
$objWriter->writeAttribute('ref', $mergeCell); |
672
|
13 |
|
$objWriter->endElement(); |
673
|
|
|
} |
674
|
|
|
|
675
|
13 |
|
$objWriter->endElement(); |
676
|
|
|
} |
677
|
60 |
|
} |
678
|
|
|
|
679
|
|
|
/** |
680
|
|
|
* Write PrintOptions. |
681
|
|
|
* |
682
|
|
|
* @param XMLWriter $objWriter XML Writer |
683
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
684
|
|
|
*/ |
685
|
60 |
|
private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
686
|
|
|
{ |
687
|
|
|
// printOptions |
688
|
60 |
|
$objWriter->startElement('printOptions'); |
689
|
|
|
|
690
|
60 |
|
$objWriter->writeAttribute('gridLines', ($pSheet->getPrintGridlines() ? 'true' : 'false')); |
691
|
60 |
|
$objWriter->writeAttribute('gridLinesSet', 'true'); |
692
|
|
|
|
693
|
60 |
|
if ($pSheet->getPageSetup()->getHorizontalCentered()) { |
694
|
|
|
$objWriter->writeAttribute('horizontalCentered', 'true'); |
695
|
|
|
} |
696
|
|
|
|
697
|
60 |
|
if ($pSheet->getPageSetup()->getVerticalCentered()) { |
698
|
|
|
$objWriter->writeAttribute('verticalCentered', 'true'); |
699
|
|
|
} |
700
|
|
|
|
701
|
60 |
|
$objWriter->endElement(); |
702
|
60 |
|
} |
703
|
|
|
|
704
|
|
|
/** |
705
|
|
|
* Write PageMargins. |
706
|
|
|
* |
707
|
|
|
* @param XMLWriter $objWriter XML Writer |
708
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
709
|
|
|
*/ |
710
|
60 |
|
private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
711
|
|
|
{ |
712
|
|
|
// pageMargins |
713
|
60 |
|
$objWriter->startElement('pageMargins'); |
714
|
60 |
|
$objWriter->writeAttribute('left', StringHelper::formatNumber($pSheet->getPageMargins()->getLeft())); |
715
|
60 |
|
$objWriter->writeAttribute('right', StringHelper::formatNumber($pSheet->getPageMargins()->getRight())); |
716
|
60 |
|
$objWriter->writeAttribute('top', StringHelper::formatNumber($pSheet->getPageMargins()->getTop())); |
717
|
60 |
|
$objWriter->writeAttribute('bottom', StringHelper::formatNumber($pSheet->getPageMargins()->getBottom())); |
718
|
60 |
|
$objWriter->writeAttribute('header', StringHelper::formatNumber($pSheet->getPageMargins()->getHeader())); |
719
|
60 |
|
$objWriter->writeAttribute('footer', StringHelper::formatNumber($pSheet->getPageMargins()->getFooter())); |
720
|
60 |
|
$objWriter->endElement(); |
721
|
60 |
|
} |
722
|
|
|
|
723
|
|
|
/** |
724
|
|
|
* Write AutoFilter. |
725
|
|
|
* |
726
|
|
|
* @param XMLWriter $objWriter XML Writer |
727
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
728
|
|
|
*/ |
729
|
60 |
|
private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
730
|
|
|
{ |
731
|
60 |
|
$autoFilterRange = $pSheet->getAutoFilter()->getRange(); |
732
|
60 |
|
if (!empty($autoFilterRange)) { |
733
|
|
|
// autoFilter |
734
|
3 |
|
$objWriter->startElement('autoFilter'); |
735
|
|
|
|
736
|
|
|
// Strip any worksheet reference from the filter coordinates |
737
|
3 |
|
$range = Coordinate::splitRange($autoFilterRange); |
738
|
3 |
|
$range = $range[0]; |
739
|
|
|
// Strip any worksheet ref |
740
|
3 |
|
if (strpos($range[0], '!') !== false) { |
741
|
|
|
list($ws, $range[0]) = explode('!', $range[0]); |
742
|
|
|
} |
743
|
3 |
|
$range = implode(':', $range); |
744
|
|
|
|
745
|
3 |
|
$objWriter->writeAttribute('ref', str_replace('$', '', $range)); |
746
|
|
|
|
747
|
3 |
|
$columns = $pSheet->getAutoFilter()->getColumns(); |
748
|
3 |
|
if (count($columns) > 0) { |
749
|
2 |
|
foreach ($columns as $columnID => $column) { |
750
|
2 |
|
$rules = $column->getRules(); |
751
|
2 |
|
if (count($rules) > 0) { |
752
|
2 |
|
$objWriter->startElement('filterColumn'); |
753
|
2 |
|
$objWriter->writeAttribute('colId', $pSheet->getAutoFilter()->getColumnOffset($columnID)); |
754
|
|
|
|
755
|
2 |
|
$objWriter->startElement($column->getFilterType()); |
756
|
2 |
|
if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) { |
757
|
1 |
|
$objWriter->writeAttribute('and', 1); |
758
|
|
|
} |
759
|
|
|
|
760
|
2 |
|
foreach ($rules as $rule) { |
761
|
2 |
|
if (($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) && |
762
|
2 |
|
($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) && |
763
|
2 |
|
($rule->getValue() === '')) { |
764
|
|
|
// Filter rule for Blanks |
765
|
1 |
|
$objWriter->writeAttribute('blank', 1); |
766
|
2 |
|
} elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) { |
767
|
|
|
// Dynamic Filter Rule |
768
|
1 |
|
$objWriter->writeAttribute('type', $rule->getGrouping()); |
769
|
1 |
|
$val = $column->getAttribute('val'); |
770
|
1 |
|
if ($val !== null) { |
771
|
1 |
|
$objWriter->writeAttribute('val', $val); |
772
|
|
|
} |
773
|
1 |
|
$maxVal = $column->getAttribute('maxVal'); |
774
|
1 |
|
if ($maxVal !== null) { |
775
|
1 |
|
$objWriter->writeAttribute('maxVal', $maxVal); |
776
|
|
|
} |
777
|
2 |
|
} elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) { |
778
|
|
|
// Top 10 Filter Rule |
779
|
|
|
$objWriter->writeAttribute('val', $rule->getValue()); |
780
|
|
|
$objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0')); |
781
|
|
|
$objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0')); |
782
|
|
|
} else { |
783
|
|
|
// Filter, DateGroupItem or CustomFilter |
784
|
2 |
|
$objWriter->startElement($rule->getRuleType()); |
785
|
|
|
|
786
|
2 |
|
if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) { |
787
|
1 |
|
$objWriter->writeAttribute('operator', $rule->getOperator()); |
788
|
|
|
} |
789
|
2 |
|
if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) { |
790
|
|
|
// Date Group filters |
791
|
1 |
|
foreach ($rule->getValue() as $key => $value) { |
792
|
1 |
|
if ($value > '') { |
793
|
1 |
|
$objWriter->writeAttribute($key, $value); |
794
|
|
|
} |
795
|
|
|
} |
796
|
1 |
|
$objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping()); |
797
|
|
|
} else { |
798
|
2 |
|
$objWriter->writeAttribute('val', $rule->getValue()); |
799
|
|
|
} |
800
|
|
|
|
801
|
2 |
|
$objWriter->endElement(); |
802
|
|
|
} |
803
|
|
|
} |
804
|
|
|
|
805
|
2 |
|
$objWriter->endElement(); |
806
|
|
|
|
807
|
2 |
|
$objWriter->endElement(); |
808
|
|
|
} |
809
|
|
|
} |
810
|
|
|
} |
811
|
3 |
|
$objWriter->endElement(); |
812
|
|
|
} |
813
|
60 |
|
} |
814
|
|
|
|
815
|
|
|
/** |
816
|
|
|
* Write PageSetup. |
817
|
|
|
* |
818
|
|
|
* @param XMLWriter $objWriter XML Writer |
819
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
820
|
|
|
*/ |
821
|
60 |
|
private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
822
|
|
|
{ |
823
|
|
|
// pageSetup |
824
|
60 |
|
$objWriter->startElement('pageSetup'); |
825
|
60 |
|
$objWriter->writeAttribute('paperSize', $pSheet->getPageSetup()->getPaperSize()); |
826
|
60 |
|
$objWriter->writeAttribute('orientation', $pSheet->getPageSetup()->getOrientation()); |
827
|
|
|
|
828
|
60 |
|
if ($pSheet->getPageSetup()->getScale() !== null) { |
829
|
60 |
|
$objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale()); |
830
|
|
|
} |
831
|
60 |
|
if ($pSheet->getPageSetup()->getFitToHeight() !== null) { |
832
|
60 |
|
$objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight()); |
833
|
|
|
} else { |
834
|
|
|
$objWriter->writeAttribute('fitToHeight', '0'); |
835
|
|
|
} |
836
|
60 |
|
if ($pSheet->getPageSetup()->getFitToWidth() !== null) { |
837
|
60 |
|
$objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth()); |
838
|
|
|
} else { |
839
|
|
|
$objWriter->writeAttribute('fitToWidth', '0'); |
840
|
|
|
} |
841
|
60 |
|
if ($pSheet->getPageSetup()->getFirstPageNumber() !== null) { |
842
|
|
|
$objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber()); |
843
|
|
|
$objWriter->writeAttribute('useFirstPageNumber', '1'); |
844
|
|
|
} |
845
|
|
|
|
846
|
60 |
|
$objWriter->endElement(); |
847
|
60 |
|
} |
848
|
|
|
|
849
|
|
|
/** |
850
|
|
|
* Write Header / Footer. |
851
|
|
|
* |
852
|
|
|
* @param XMLWriter $objWriter XML Writer |
853
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
854
|
|
|
*/ |
855
|
60 |
|
private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
856
|
|
|
{ |
857
|
|
|
// headerFooter |
858
|
60 |
|
$objWriter->startElement('headerFooter'); |
859
|
60 |
|
$objWriter->writeAttribute('differentOddEven', ($pSheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false')); |
860
|
60 |
|
$objWriter->writeAttribute('differentFirst', ($pSheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false')); |
861
|
60 |
|
$objWriter->writeAttribute('scaleWithDoc', ($pSheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false')); |
862
|
60 |
|
$objWriter->writeAttribute('alignWithMargins', ($pSheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false')); |
863
|
|
|
|
864
|
60 |
|
$objWriter->writeElement('oddHeader', $pSheet->getHeaderFooter()->getOddHeader()); |
865
|
60 |
|
$objWriter->writeElement('oddFooter', $pSheet->getHeaderFooter()->getOddFooter()); |
866
|
60 |
|
$objWriter->writeElement('evenHeader', $pSheet->getHeaderFooter()->getEvenHeader()); |
867
|
60 |
|
$objWriter->writeElement('evenFooter', $pSheet->getHeaderFooter()->getEvenFooter()); |
868
|
60 |
|
$objWriter->writeElement('firstHeader', $pSheet->getHeaderFooter()->getFirstHeader()); |
869
|
60 |
|
$objWriter->writeElement('firstFooter', $pSheet->getHeaderFooter()->getFirstFooter()); |
870
|
60 |
|
$objWriter->endElement(); |
871
|
60 |
|
} |
872
|
|
|
|
873
|
|
|
/** |
874
|
|
|
* Write Breaks. |
875
|
|
|
* |
876
|
|
|
* @param XMLWriter $objWriter XML Writer |
877
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
878
|
|
|
*/ |
879
|
60 |
|
private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
880
|
|
|
{ |
881
|
|
|
// Get row and column breaks |
882
|
60 |
|
$aRowBreaks = []; |
883
|
60 |
|
$aColumnBreaks = []; |
884
|
60 |
|
foreach ($pSheet->getBreaks() as $cell => $breakType) { |
885
|
1 |
|
if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) { |
886
|
1 |
|
$aRowBreaks[] = $cell; |
887
|
|
|
} elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) { |
888
|
1 |
|
$aColumnBreaks[] = $cell; |
889
|
|
|
} |
890
|
|
|
} |
891
|
|
|
|
892
|
|
|
// rowBreaks |
893
|
60 |
|
if (!empty($aRowBreaks)) { |
894
|
1 |
|
$objWriter->startElement('rowBreaks'); |
895
|
1 |
|
$objWriter->writeAttribute('count', count($aRowBreaks)); |
896
|
1 |
|
$objWriter->writeAttribute('manualBreakCount', count($aRowBreaks)); |
897
|
|
|
|
898
|
1 |
|
foreach ($aRowBreaks as $cell) { |
899
|
1 |
|
$coords = Coordinate::coordinateFromString($cell); |
900
|
|
|
|
901
|
1 |
|
$objWriter->startElement('brk'); |
902
|
1 |
|
$objWriter->writeAttribute('id', $coords[1]); |
903
|
1 |
|
$objWriter->writeAttribute('man', '1'); |
904
|
1 |
|
$objWriter->endElement(); |
905
|
|
|
} |
906
|
|
|
|
907
|
1 |
|
$objWriter->endElement(); |
908
|
|
|
} |
909
|
|
|
|
910
|
|
|
// Second, write column breaks |
911
|
60 |
|
if (!empty($aColumnBreaks)) { |
912
|
|
|
$objWriter->startElement('colBreaks'); |
913
|
|
|
$objWriter->writeAttribute('count', count($aColumnBreaks)); |
914
|
|
|
$objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks)); |
915
|
|
|
|
916
|
|
|
foreach ($aColumnBreaks as $cell) { |
917
|
|
|
$coords = Coordinate::coordinateFromString($cell); |
918
|
|
|
|
919
|
|
|
$objWriter->startElement('brk'); |
920
|
|
|
$objWriter->writeAttribute('id', Coordinate::columnIndexFromString($coords[0]) - 1); |
921
|
|
|
$objWriter->writeAttribute('man', '1'); |
922
|
|
|
$objWriter->endElement(); |
923
|
|
|
} |
924
|
|
|
|
925
|
|
|
$objWriter->endElement(); |
926
|
|
|
} |
927
|
60 |
|
} |
928
|
|
|
|
929
|
|
|
/** |
930
|
|
|
* Write SheetData. |
931
|
|
|
* |
932
|
|
|
* @param XMLWriter $objWriter XML Writer |
933
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
934
|
|
|
* @param string[] $pStringTable String table |
935
|
|
|
* |
936
|
|
|
* @throws WriterException |
937
|
|
|
*/ |
938
|
60 |
|
private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, array $pStringTable) |
939
|
|
|
{ |
940
|
|
|
// Flipped stringtable, for faster index searching |
941
|
60 |
|
$aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->flipStringTable($pStringTable); |
942
|
|
|
|
943
|
|
|
// sheetData |
944
|
60 |
|
$objWriter->startElement('sheetData'); |
945
|
|
|
|
946
|
|
|
// Get column count |
947
|
60 |
|
$colCount = Coordinate::columnIndexFromString($pSheet->getHighestColumn()); |
948
|
|
|
|
949
|
|
|
// Highest row number |
950
|
60 |
|
$highestRow = $pSheet->getHighestRow(); |
951
|
|
|
|
952
|
|
|
// Loop through cells |
953
|
60 |
|
$cellsByRow = []; |
954
|
60 |
|
foreach ($pSheet->getCoordinates() as $coordinate) { |
955
|
59 |
|
$cellAddress = Coordinate::coordinateFromString($coordinate); |
956
|
59 |
|
$cellsByRow[$cellAddress[1]][] = $coordinate; |
957
|
|
|
} |
958
|
|
|
|
959
|
60 |
|
$currentRow = 0; |
960
|
60 |
|
while ($currentRow++ < $highestRow) { |
961
|
|
|
// Get row dimension |
962
|
60 |
|
$rowDimension = $pSheet->getRowDimension($currentRow); |
963
|
|
|
|
964
|
|
|
// Write current row? |
965
|
60 |
|
$writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || $rowDimension->getOutlineLevel() > 0 || $rowDimension->getXfIndex() !== null; |
966
|
|
|
|
967
|
60 |
|
if ($writeCurrentRow) { |
968
|
|
|
// Start a new row |
969
|
59 |
|
$objWriter->startElement('row'); |
970
|
59 |
|
$objWriter->writeAttribute('r', $currentRow); |
971
|
59 |
|
$objWriter->writeAttribute('spans', '1:' . $colCount); |
972
|
|
|
|
973
|
|
|
// Row dimensions |
974
|
59 |
|
if ($rowDimension->getRowHeight() >= 0) { |
975
|
5 |
|
$objWriter->writeAttribute('customHeight', '1'); |
976
|
5 |
|
$objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight())); |
977
|
|
|
} |
978
|
|
|
|
979
|
|
|
// Row visibility |
980
|
59 |
|
if ($rowDimension->getVisible() == false) { |
981
|
2 |
|
$objWriter->writeAttribute('hidden', 'true'); |
982
|
|
|
} |
983
|
|
|
|
984
|
|
|
// Collapsed |
985
|
59 |
|
if ($rowDimension->getCollapsed() == true) { |
986
|
|
|
$objWriter->writeAttribute('collapsed', 'true'); |
987
|
|
|
} |
988
|
|
|
|
989
|
|
|
// Outline level |
990
|
59 |
|
if ($rowDimension->getOutlineLevel() > 0) { |
991
|
|
|
$objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel()); |
992
|
|
|
} |
993
|
|
|
|
994
|
|
|
// Style |
995
|
59 |
|
if ($rowDimension->getXfIndex() !== null) { |
996
|
|
|
$objWriter->writeAttribute('s', $rowDimension->getXfIndex()); |
997
|
|
|
$objWriter->writeAttribute('customFormat', '1'); |
998
|
|
|
} |
999
|
|
|
|
1000
|
|
|
// Write cells |
1001
|
59 |
|
if (isset($cellsByRow[$currentRow])) { |
1002
|
59 |
|
foreach ($cellsByRow[$currentRow] as $cellAddress) { |
1003
|
|
|
// Write cell |
1004
|
59 |
|
$this->writeCell($objWriter, $pSheet, $cellAddress, $aFlippedStringTable); |
1005
|
|
|
} |
1006
|
|
|
} |
1007
|
|
|
|
1008
|
|
|
// End row |
1009
|
59 |
|
$objWriter->endElement(); |
1010
|
|
|
} |
1011
|
|
|
} |
1012
|
|
|
|
1013
|
60 |
|
$objWriter->endElement(); |
1014
|
60 |
|
} |
1015
|
|
|
|
1016
|
|
|
/** |
1017
|
|
|
* Write Cell. |
1018
|
|
|
* |
1019
|
|
|
* @param XMLWriter $objWriter XML Writer |
1020
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
1021
|
|
|
* @param Cell $pCellAddress Cell Address |
1022
|
|
|
* @param string[] $pFlippedStringTable String table (flipped), for faster index searching |
1023
|
|
|
* |
1024
|
|
|
* @throws WriterException |
1025
|
|
|
*/ |
1026
|
59 |
|
private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $pCellAddress, array $pFlippedStringTable) |
1027
|
|
|
{ |
1028
|
|
|
// Cell |
1029
|
59 |
|
$pCell = $pSheet->getCell($pCellAddress); |
1030
|
59 |
|
$objWriter->startElement('c'); |
1031
|
59 |
|
$objWriter->writeAttribute('r', $pCellAddress); |
1032
|
|
|
|
1033
|
|
|
// Sheet styles |
1034
|
59 |
|
if ($pCell->getXfIndex() != '') { |
1035
|
32 |
|
$objWriter->writeAttribute('s', $pCell->getXfIndex()); |
1036
|
|
|
} |
1037
|
|
|
|
1038
|
|
|
// If cell value is supplied, write cell value |
1039
|
59 |
|
$cellValue = $pCell->getValue(); |
1040
|
59 |
|
if (is_object($cellValue) || $cellValue !== '') { |
1041
|
|
|
// Map type |
1042
|
59 |
|
$mappedType = $pCell->getDataType(); |
1043
|
|
|
|
1044
|
|
|
// Write data type depending on its type |
1045
|
59 |
|
switch (strtolower($mappedType)) { |
1046
|
59 |
|
case 'inlinestr': // Inline string |
1047
|
58 |
|
case 's': // String |
1048
|
50 |
|
case 'b': // Boolean |
1049
|
52 |
|
$objWriter->writeAttribute('t', $mappedType); |
1050
|
|
|
|
1051
|
52 |
|
break; |
1052
|
48 |
|
case 'f': // Formula |
1053
|
18 |
|
$calculatedValue = ($this->getParentWriter()->getPreCalculateFormulas()) ? |
1054
|
18 |
|
$pCell->getCalculatedValue() : $cellValue; |
1055
|
18 |
|
if (is_string($calculatedValue)) { |
1056
|
13 |
|
$objWriter->writeAttribute('t', 'str'); |
1057
|
|
|
} |
1058
|
|
|
|
1059
|
18 |
|
break; |
1060
|
47 |
|
case 'e': // Error |
1061
|
|
|
$objWriter->writeAttribute('t', $mappedType); |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
// Write data depending on its type |
1065
|
59 |
|
switch (strtolower($mappedType)) { |
1066
|
59 |
|
case 'inlinestr': // Inline string |
1067
|
8 |
|
if (!$cellValue instanceof RichText) { |
1068
|
|
|
$objWriter->writeElement('t', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue))); |
1069
|
8 |
|
} elseif ($cellValue instanceof RichText) { |
1070
|
8 |
|
$objWriter->startElement('is'); |
1071
|
8 |
|
$this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $cellValue); |
1072
|
8 |
|
$objWriter->endElement(); |
1073
|
|
|
} |
1074
|
|
|
|
1075
|
8 |
|
break; |
1076
|
58 |
|
case 's': // String |
1077
|
51 |
|
if (!$cellValue instanceof RichText) { |
1078
|
51 |
|
if (isset($pFlippedStringTable[$cellValue])) { |
1079
|
51 |
|
$objWriter->writeElement('v', $pFlippedStringTable[$cellValue]); |
1080
|
|
|
} |
1081
|
2 |
|
} elseif ($cellValue instanceof RichText) { |
1082
|
2 |
|
$objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]); |
1083
|
|
|
} |
1084
|
|
|
|
1085
|
51 |
|
break; |
1086
|
50 |
|
case 'f': // Formula |
1087
|
18 |
|
$attributes = $pCell->getFormulaAttributes(); |
1088
|
18 |
|
if ($attributes['t'] == 'array') { |
1089
|
|
|
$objWriter->startElement('f'); |
1090
|
|
|
$objWriter->writeAttribute('t', 'array'); |
1091
|
|
|
$objWriter->writeAttribute('ref', $pCellAddress); |
1092
|
|
|
$objWriter->writeAttribute('aca', '1'); |
1093
|
|
|
$objWriter->writeAttribute('ca', '1'); |
1094
|
|
|
$objWriter->text(substr($cellValue, 1)); |
1095
|
|
|
$objWriter->endElement(); |
1096
|
|
|
} else { |
1097
|
18 |
|
$objWriter->writeElement('f', substr($cellValue, 1)); |
1098
|
|
|
} |
1099
|
18 |
|
if ($this->getParentWriter()->getOffice2003Compatibility() === false) { |
1100
|
18 |
|
if ($this->getParentWriter()->getPreCalculateFormulas()) { |
1101
|
18 |
|
if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') { |
1102
|
18 |
|
$objWriter->writeElement('v', StringHelper::formatNumber($calculatedValue)); |
1103
|
|
|
} else { |
1104
|
18 |
|
$objWriter->writeElement('v', '0'); |
1105
|
|
|
} |
1106
|
|
|
} else { |
1107
|
|
|
$objWriter->writeElement('v', '0'); |
1108
|
|
|
} |
1109
|
|
|
} |
1110
|
|
|
|
1111
|
18 |
|
break; |
1112
|
49 |
|
case 'n': // Numeric |
1113
|
|
|
// force point as decimal separator in case current locale uses comma |
1114
|
41 |
|
$objWriter->writeElement('v', str_replace(',', '.', $cellValue)); |
1115
|
|
|
|
1116
|
41 |
|
break; |
1117
|
26 |
|
case 'b': // Boolean |
1118
|
8 |
|
$objWriter->writeElement('v', ($cellValue ? '1' : '0')); |
1119
|
|
|
|
1120
|
8 |
|
break; |
1121
|
22 |
|
case 'e': // Error |
1122
|
|
|
if (substr($cellValue, 0, 1) == '=') { |
1123
|
|
|
$objWriter->writeElement('f', substr($cellValue, 1)); |
1124
|
|
|
$objWriter->writeElement('v', substr($cellValue, 1)); |
1125
|
|
|
} else { |
1126
|
|
|
$objWriter->writeElement('v', $cellValue); |
1127
|
|
|
} |
1128
|
|
|
|
1129
|
|
|
break; |
1130
|
|
|
} |
1131
|
|
|
} |
1132
|
|
|
|
1133
|
59 |
|
$objWriter->endElement(); |
1134
|
59 |
|
} |
1135
|
|
|
|
1136
|
|
|
/** |
1137
|
|
|
* Write Drawings. |
1138
|
|
|
* |
1139
|
|
|
* @param XMLWriter $objWriter XML Writer |
1140
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
1141
|
|
|
* @param bool $includeCharts Flag indicating if we should include drawing details for charts |
1142
|
|
|
*/ |
1143
|
60 |
|
private function writeDrawings(XMLWriter $objWriter = null, PhpspreadsheetWorksheet $pSheet = null, $includeCharts = false) |
1144
|
|
|
{ |
1145
|
60 |
|
$chartCount = ($includeCharts) ? $pSheet->getChartCollection()->count() : 0; |
1146
|
|
|
// If sheet contains drawings, add the relationships |
1147
|
60 |
|
if (($pSheet->getDrawingCollection()->count() > 0) || |
1148
|
60 |
|
($chartCount > 0)) { |
1149
|
22 |
|
$objWriter->startElement('drawing'); |
1150
|
22 |
|
$objWriter->writeAttribute('r:id', 'rId1'); |
1151
|
22 |
|
$objWriter->endElement(); |
1152
|
|
|
} |
1153
|
60 |
|
} |
1154
|
|
|
|
1155
|
|
|
/** |
1156
|
|
|
* Write LegacyDrawing. |
1157
|
|
|
* |
1158
|
|
|
* @param XMLWriter $objWriter XML Writer |
1159
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
1160
|
|
|
*/ |
1161
|
60 |
|
private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
1162
|
|
|
{ |
1163
|
|
|
// If sheet contains comments, add the relationships |
1164
|
60 |
|
if (count($pSheet->getComments()) > 0) { |
1165
|
9 |
|
$objWriter->startElement('legacyDrawing'); |
1166
|
9 |
|
$objWriter->writeAttribute('r:id', 'rId_comments_vml1'); |
1167
|
9 |
|
$objWriter->endElement(); |
1168
|
|
|
} |
1169
|
60 |
|
} |
1170
|
|
|
|
1171
|
|
|
/** |
1172
|
|
|
* Write LegacyDrawingHF. |
1173
|
|
|
* |
1174
|
|
|
* @param XMLWriter $objWriter XML Writer |
1175
|
|
|
* @param PhpspreadsheetWorksheet $pSheet Worksheet |
1176
|
|
|
*/ |
1177
|
60 |
|
private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet) |
1178
|
|
|
{ |
1179
|
|
|
// If sheet contains images, add the relationships |
1180
|
60 |
|
if (count($pSheet->getHeaderFooter()->getImages()) > 0) { |
1181
|
1 |
|
$objWriter->startElement('legacyDrawingHF'); |
1182
|
1 |
|
$objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1'); |
1183
|
1 |
|
$objWriter->endElement(); |
1184
|
|
|
} |
1185
|
60 |
|
} |
1186
|
|
|
} |
1187
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.