PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.7.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.7.1
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Writer / Xlsx / Worksheet.php

Worksheet.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.7.1, at vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php

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