ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Content.php
Go to the documentation of this file.
1 <?php
2 
4 
16 
20 class Content extends WriterPart
21 {
23  const NUMBER_ROWS_REPEATED_MAX = 1048576;
24 
26 
30  public function __construct(Ods $writer)
31  {
32  parent::__construct($writer);
33 
34  $this->formulaConvertor = new Formula($this->getParentWriter()->getSpreadsheet()->getDefinedNames());
35  }
36 
42  public function write(): string
43  {
44  $objWriter = null;
45  if ($this->getParentWriter()->getUseDiskCaching()) {
46  $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
47  } else {
48  $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
49  }
50 
51  // XML header
52  $objWriter->startDocument('1.0', 'UTF-8');
53 
54  // Content
55  $objWriter->startElement('office:document-content');
56  $objWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0');
57  $objWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0');
58  $objWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0');
59  $objWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0');
60  $objWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0');
61  $objWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');
62  $objWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
63  $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');
64  $objWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0');
65  $objWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0');
66  $objWriter->writeAttribute('xmlns:presentation', 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0');
67  $objWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0');
68  $objWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0');
69  $objWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0');
70  $objWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML');
71  $objWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0');
72  $objWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0');
73  $objWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office');
74  $objWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer');
75  $objWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc');
76  $objWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events');
77  $objWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms');
78  $objWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
79  $objWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
80  $objWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report');
81  $objWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2');
82  $objWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml');
83  $objWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#');
84  $objWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table');
85  $objWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0');
86  $objWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0');
87  $objWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/');
88  $objWriter->writeAttribute('office:version', '1.2');
89 
90  $objWriter->writeElement('office:scripts');
91  $objWriter->writeElement('office:font-face-decls');
92 
93  // Styles XF
94  $objWriter->startElement('office:automatic-styles');
95  $this->writeXfStyles($objWriter, $this->getParentWriter()->getSpreadsheet());
96  $objWriter->endElement();
97 
98  $objWriter->startElement('office:body');
99  $objWriter->startElement('office:spreadsheet');
100  $objWriter->writeElement('table:calculation-settings');
101 
102  $this->writeSheets($objWriter);
103 
104  (new AutoFilters($objWriter, $this->getParentWriter()->getSpreadsheet()))->write();
105  // Defined names (ranges and formulae)
106  (new NamedExpressions($objWriter, $this->getParentWriter()->getSpreadsheet(), $this->formulaConvertor))->write();
107 
108  $objWriter->endElement();
109  $objWriter->endElement();
110  $objWriter->endElement();
111 
112  return $objWriter->getData();
113  }
114 
118  private function writeSheets(XMLWriter $objWriter): void
119  {
120  $spreadsheet = $this->getParentWriter()->getSpreadsheet();
121  $sheetCount = $spreadsheet->getSheetCount();
122  for ($i = 0; $i < $sheetCount; ++$i) {
123  $objWriter->startElement('table:table');
124  $objWriter->writeAttribute('table:name', $spreadsheet->getSheet($i)->getTitle());
125  $objWriter->writeElement('office:forms');
126  $objWriter->startElement('table:table-column');
127  $objWriter->writeAttribute('table:number-columns-repeated', self::NUMBER_COLS_REPEATED_MAX);
128  $objWriter->endElement();
129  $this->writeRows($objWriter, $spreadsheet->getSheet($i));
130  $objWriter->endElement();
131  }
132  }
133 
137  private function writeRows(XMLWriter $objWriter, Worksheet $sheet): void
138  {
139  $numberRowsRepeated = self::NUMBER_ROWS_REPEATED_MAX;
140  $span_row = 0;
141  $rows = $sheet->getRowIterator();
142  while ($rows->valid()) {
143  --$numberRowsRepeated;
144  $row = $rows->current();
145  if ($row->getCellIterator()->valid()) {
146  if ($span_row) {
147  $objWriter->startElement('table:table-row');
148  if ($span_row > 1) {
149  $objWriter->writeAttribute('table:number-rows-repeated', $span_row);
150  }
151  $objWriter->startElement('table:table-cell');
152  $objWriter->writeAttribute('table:number-columns-repeated', self::NUMBER_COLS_REPEATED_MAX);
153  $objWriter->endElement();
154  $objWriter->endElement();
155  $span_row = 0;
156  }
157  $objWriter->startElement('table:table-row');
158  $this->writeCells($objWriter, $row);
159  $objWriter->endElement();
160  } else {
161  ++$span_row;
162  }
163  $rows->next();
164  }
165  }
166 
170  private function writeCells(XMLWriter $objWriter, Row $row): void
171  {
172  $numberColsRepeated = self::NUMBER_COLS_REPEATED_MAX;
173  $prevColumn = -1;
174  $cells = $row->getCellIterator();
175  while ($cells->valid()) {
177  $cell = $cells->current();
178  $column = Coordinate::columnIndexFromString($cell->getColumn()) - 1;
179 
180  $this->writeCellSpan($objWriter, $column, $prevColumn);
181  $objWriter->startElement('table:table-cell');
182  $this->writeCellMerge($objWriter, $cell);
183 
184  // Style XF
185  $style = $cell->getXfIndex();
186  if ($style !== null) {
187  $objWriter->writeAttribute('table:style-name', Style::CELL_STYLE_PREFIX . $style);
188  }
189 
190  switch ($cell->getDataType()) {
191  case DataType::TYPE_BOOL:
192  $objWriter->writeAttribute('office:value-type', 'boolean');
193  $objWriter->writeAttribute('office:value', $cell->getValue());
194  $objWriter->writeElement('text:p', $cell->getValue());
195 
196  break;
198  $objWriter->writeAttribute('table:formula', 'of:=#NULL!');
199  $objWriter->writeAttribute('office:value-type', 'string');
200  $objWriter->writeAttribute('office:string-value', '');
201  $objWriter->writeElement('text:p', '#NULL!');
202 
203  break;
205  $formulaValue = $cell->getValue();
206  if ($this->getParentWriter()->getPreCalculateFormulas()) {
207  try {
208  $formulaValue = $cell->getCalculatedValue();
209  } catch (Exception $e) {
210  // don't do anything
211  }
212  }
213  $objWriter->writeAttribute('table:formula', $this->formulaConvertor->convertFormula($cell->getValue()));
214  if (is_numeric($formulaValue)) {
215  $objWriter->writeAttribute('office:value-type', 'float');
216  } else {
217  $objWriter->writeAttribute('office:value-type', 'string');
218  }
219  $objWriter->writeAttribute('office:value', $formulaValue);
220  $objWriter->writeElement('text:p', $formulaValue);
221 
222  break;
224  $objWriter->writeAttribute('office:value-type', 'float');
225  $objWriter->writeAttribute('office:value', $cell->getValue());
226  $objWriter->writeElement('text:p', $cell->getValue());
227 
228  break;
230  // break intentionally omitted
232  $objWriter->writeAttribute('office:value-type', 'string');
233  $objWriter->writeElement('text:p', $cell->getValue());
234 
235  break;
236  }
237  Comment::write($objWriter, $cell);
238  $objWriter->endElement();
239  $prevColumn = $column;
240  $cells->next();
241  }
242  $numberColsRepeated = $numberColsRepeated - $prevColumn - 1;
243  if ($numberColsRepeated > 0) {
244  if ($numberColsRepeated > 1) {
245  $objWriter->startElement('table:table-cell');
246  $objWriter->writeAttribute('table:number-columns-repeated', $numberColsRepeated);
247  $objWriter->endElement();
248  } else {
249  $objWriter->writeElement('table:table-cell');
250  }
251  }
252  }
253 
260  private function writeCellSpan(XMLWriter $objWriter, $curColumn, $prevColumn): void
261  {
262  $diff = $curColumn - $prevColumn - 1;
263  if (1 === $diff) {
264  $objWriter->writeElement('table:table-cell');
265  } elseif ($diff > 1) {
266  $objWriter->startElement('table:table-cell');
267  $objWriter->writeAttribute('table:number-columns-repeated', $diff);
268  $objWriter->endElement();
269  }
270  }
271 
275  private function writeXfStyles(XMLWriter $writer, Spreadsheet $spreadsheet): void
276  {
277  $styleWriter = new Style($writer);
278  foreach ($spreadsheet->getCellXfCollection() as $style) {
279  $styleWriter->write($style);
280  }
281  }
282 
286  private function writeCellMerge(XMLWriter $objWriter, Cell $cell): void
287  {
288  if (!$cell->isMergeRangeValueCell()) {
289  return;
290  }
291 
292  $mergeRange = Coordinate::splitRange($cell->getMergeRange());
293  [$startCell, $endCell] = $mergeRange[0];
297  $rowSpan = ((int) $end[1]) - ((int) $start[1]) + 1;
298 
299  $objWriter->writeAttribute('table:number-columns-spanned', $columnSpan);
300  $objWriter->writeAttribute('table:number-rows-spanned', $rowSpan);
301  }
302 }
static splitRange($pRange)
Split range into coordinate strings.
Definition: Coordinate.php:140
$style
Definition: example_012.php:70
__construct(Ods $writer)
Set parent Ods writer.
Definition: Content.php:30
getSpreadsheet()
Get Spreadsheet object.
Definition: Ods.php:174
writeRows(XMLWriter $objWriter, Worksheet $sheet)
Write rows of the specified sheet.
Definition: Content.php:137
getRowIterator($startRow=1, $endRow=null)
Get row iterator.
Definition: Worksheet.php:2638
getDiskCachingDirectory()
Get disk caching directory.
Definition: BaseWriter.php:92
getCellXfCollection()
Get the workbook collection of cellXfs.
$start
Definition: bench.php:8
getPreCalculateFormulas()
Get Pre-Calculate Formulas flag If this is true (the default), then the writer will recalculate all f...
Definition: BaseWriter.php:60
write()
Write content.xml to XML format.
Definition: Content.php:42
writeCellMerge(XMLWriter $objWriter, Cell $cell)
Write attributes for merged cell.
Definition: Content.php:286
$row
$rows
Definition: xhr_table.php:10
writeXfStyles(XMLWriter $writer, Spreadsheet $spreadsheet)
Write XF cell styles.
Definition: Content.php:275
static coordinateFromString($pCoordinateString)
Coordinate from string.
Definition: Coordinate.php:32
isMergeRangeValueCell()
Is this cell the master (top left cell) in a merge range (that holds the actual data value)...
Definition: Cell.php:499
getMergeRange()
If this cell is in a merge range, then return the range.
Definition: Cell.php:517
writeCellSpan(XMLWriter $objWriter, $curColumn, $prevColumn)
Write span.
Definition: Content.php:260
getCellIterator($startColumn='A', $endColumn=null)
Get cell iterator.
Definition: Row.php:59
$i
Definition: disco.tpl.php:19
getUseDiskCaching()
Get use disk caching where possible?
Definition: BaseWriter.php:72
static columnIndexFromString($pString)
Column index from string.
Definition: Coordinate.php:265