Completed
Push — develop ( 4c42af...77199c )
by Adrien
22:07 queued 07:17
created

Content::writeCellSpan()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 8

Duplication

Lines 7
Ratio 63.64 %

Code Coverage

Tests 5
CRAP Score 3.7898

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 3
dl 7
loc 11
ccs 5
cts 9
cp 0.5556
crap 3.7898
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Ods;
4
5
/*
6
 * PhpSpreadsheet.
7
 *
8
 * Copyright (c) 2006 - 2015 PhpSpreadsheet
9
 *
10
 * This library is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU Lesser General Public
12
 * License as published by the Free Software Foundation; either
13
 * version 2.1 of the License, or (at your option) any later version.
14
 *
15
 * This library is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
 * Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with this library; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
 *
24
 * @category   PhpSpreadsheet
25
 *
26
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
27
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
28
 */
29
30
use PhpOffice\PhpSpreadsheet\Cell;
31
use PhpOffice\PhpSpreadsheet\Cell\DataType;
32
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
33
use PhpOffice\PhpSpreadsheet\Spreadsheet;
34
use PhpOffice\PhpSpreadsheet\Style\Fill;
35
use PhpOffice\PhpSpreadsheet\Style\Font;
36
use PhpOffice\PhpSpreadsheet\Worksheet;
37
use PhpOffice\PhpSpreadsheet\Writer\Exception;
38
use PhpOffice\PhpSpreadsheet\Writer\Ods;
39
use PhpOffice\PhpSpreadsheet\Writer\Ods\Cell\Comment;
40
41
/**
42
 * @category   PhpSpreadsheet
43
 *
44
 * @method Ods getParentWriter
45
 *
46
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
47
 * @author     Alexander Pervakov <[email protected]>
48
 */
49
class Content extends WriterPart
50
{
51
    const NUMBER_COLS_REPEATED_MAX = 1024;
52
    const NUMBER_ROWS_REPEATED_MAX = 1048576;
53
    const CELL_STYLE_PREFIX = 'ce';
54
55
    /**
56
     * Write content.xml to XML format.
57
     *
58
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
59
     *
60
     * @return string XML Output
61
     */
62 2
    public function write()
63
    {
64 2
        $objWriter = null;
0 ignored issues
show
Unused Code introduced by
$objWriter is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
65 2 View Code Duplication
        if ($this->getParentWriter()->getUseDiskCaching()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
66
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
67
        } else {
68 2
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
69
        }
70
71
        // XML header
72 2
        $objWriter->startDocument('1.0', 'UTF-8');
73
74
        // Content
75 2
        $objWriter->startElement('office:document-content');
76 2
        $objWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0');
77 2
        $objWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0');
78 2
        $objWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0');
79 2
        $objWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0');
80 2
        $objWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0');
81 2
        $objWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');
82 2
        $objWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
83 2
        $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');
84 2
        $objWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0');
85 2
        $objWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0');
86 2
        $objWriter->writeAttribute('xmlns:presentation', 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0');
87 2
        $objWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0');
88 2
        $objWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0');
89 2
        $objWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0');
90 2
        $objWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML');
91 2
        $objWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0');
92 2
        $objWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0');
93 2
        $objWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office');
94 2
        $objWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer');
95 2
        $objWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc');
96 2
        $objWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events');
97 2
        $objWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms');
98 2
        $objWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
99 2
        $objWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
100 2
        $objWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report');
101 2
        $objWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2');
102 2
        $objWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml');
103 2
        $objWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#');
104 2
        $objWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table');
105 2
        $objWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0');
106 2
        $objWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0');
107 2
        $objWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/');
108 2
        $objWriter->writeAttribute('office:version', '1.2');
109
110 2
        $objWriter->writeElement('office:scripts');
111 2
        $objWriter->writeElement('office:font-face-decls');
112
113
        // Styles XF
114 2
        $objWriter->startElement('office:automatic-styles');
115 2
        $this->writeXfStyles($objWriter, $this->getParentWriter()->getSpreadsheet());
116 2
        $objWriter->endElement();
117
118 2
        $objWriter->startElement('office:body');
119 2
        $objWriter->startElement('office:spreadsheet');
120 2
        $objWriter->writeElement('table:calculation-settings');
121
122 2
        $this->writeSheets($objWriter);
123
124 2
        $objWriter->writeElement('table:named-expressions');
125 2
        $objWriter->endElement();
126 2
        $objWriter->endElement();
127 2
        $objWriter->endElement();
128
129 2
        return $objWriter->getData();
130
    }
131
132
    /**
133
     * Write sheets.
134
     *
135
     * @param XMLWriter $objWriter
136
     */
137 2
    private function writeSheets(XMLWriter $objWriter)
138
    {
139 2
        $spreadsheet = $this->getParentWriter()->getSpreadsheet(); /* @var $spreadsheet Spreadsheet */
140
141 2
        $sheetCount = $spreadsheet->getSheetCount();
142 2
        for ($i = 0; $i < $sheetCount; ++$i) {
143 2
            $objWriter->startElement('table:table');
144 2
            $objWriter->writeAttribute('table:name', $spreadsheet->getSheet($i)->getTitle());
145 2
            $objWriter->writeElement('office:forms');
146 2
            $objWriter->startElement('table:table-column');
147 2
            $objWriter->writeAttribute('table:number-columns-repeated', self::NUMBER_COLS_REPEATED_MAX);
148 2
            $objWriter->endElement();
149 2
            $this->writeRows($objWriter, $spreadsheet->getSheet($i));
150 2
            $objWriter->endElement();
151
        }
152 2
    }
153
154
    /**
155
     * Write rows of the specified sheet.
156
     *
157
     * @param XMLWriter $objWriter
158
     * @param Worksheet $sheet
159
     */
160 2
    private function writeRows(XMLWriter $objWriter, Worksheet $sheet)
161
    {
162 2
        $numberRowsRepeated = self::NUMBER_ROWS_REPEATED_MAX;
163 2
        $span_row = 0;
164 2
        $rows = $sheet->getRowIterator();
165 2
        while ($rows->valid()) {
166 2
            --$numberRowsRepeated;
167 2
            $row = $rows->current();
168 2
            if ($row->getCellIterator()->valid()) {
169 2
                if ($span_row) {
170
                    $objWriter->startElement('table:table-row');
171
                    if ($span_row > 1) {
172
                        $objWriter->writeAttribute('table:number-rows-repeated', $span_row);
173
                    }
174
                    $objWriter->startElement('table:table-cell');
175
                    $objWriter->writeAttribute('table:number-columns-repeated', self::NUMBER_COLS_REPEATED_MAX);
176
                    $objWriter->endElement();
177
                    $objWriter->endElement();
178
                    $span_row = 0;
179
                }
180 2
                $objWriter->startElement('table:table-row');
181 2
                $this->writeCells($objWriter, $row);
182 2
                $objWriter->endElement();
183
            } else {
184
                ++$span_row;
185
            }
186 2
            $rows->next();
187
        }
188 2
    }
189
190
    /**
191
     * Write cells of the specified row.
192
     *
193
     * @param XMLWriter $objWriter
194
     * @param Worksheet\Row $row
195
     *
196
     * @throws Exception
197
     */
198 2
    private function writeCells(XMLWriter $objWriter, Worksheet\Row $row)
199
    {
200 2
        $numberColsRepeated = self::NUMBER_COLS_REPEATED_MAX;
201 2
        $prevColumn = -1;
202 2
        $cells = $row->getCellIterator();
203 2
        while ($cells->valid()) {
204
            /** @var Cell $cell */
205 2
            $cell = $cells->current();
206 2
            $column = Cell::columnIndexFromString($cell->getColumn()) - 1;
207
208 2
            $this->writeCellSpan($objWriter, $column, $prevColumn);
209 2
            $objWriter->startElement('table:table-cell');
210
211
            // Style XF
212 2
            $style = $cell->getXfIndex();
213 2
            if ($style !== null) {
214 2
                $objWriter->writeAttribute('table:style-name', self::CELL_STYLE_PREFIX . $style);
215
            }
216
217 2
            switch ($cell->getDataType()) {
218 2 View Code Duplication
                case DataType::TYPE_BOOL:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
219 1
                    $objWriter->writeAttribute('office:value-type', 'boolean');
220 1
                    $objWriter->writeAttribute('office:value', $cell->getValue());
221 1
                    $objWriter->writeElement('text:p', $cell->getValue());
222 1
                    break;
223 2
                case DataType::TYPE_ERROR:
224
                    throw new Exception('Writing of error not implemented yet.');
225
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
226 2
                case DataType::TYPE_FORMULA:
227 1
                    $formulaValue = $cell->getValue();
228 1
                    if ($this->getParentWriter()->getPreCalculateFormulas()) {
229
                        try {
230 1
                            $formulaValue = $cell->getCalculatedValue();
231
                        } catch (Exception $e) {
232
                            // don't do anything
233
                        }
234
                    }
235 1
                    $objWriter->writeAttribute('table:formula', 'of:' . $cell->getValue());
236 1
                    if (is_numeric($formulaValue)) {
237
                        $objWriter->writeAttribute('office:value-type', 'float');
238
                    } else {
239 1
                        $objWriter->writeAttribute('office:value-type', 'string');
240
                    }
241 1
                    $objWriter->writeAttribute('office:value', $formulaValue);
242 1
                    $objWriter->writeElement('text:p', $formulaValue);
243 1
                    break;
244 2
                case DataType::TYPE_INLINE:
245
                    throw new Exception('Writing of inline not implemented yet.');
246
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
247 2 View Code Duplication
                case DataType::TYPE_NUMERIC:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248 1
                    $objWriter->writeAttribute('office:value-type', 'float');
249 1
                    $objWriter->writeAttribute('office:value', $cell->getValue());
250 1
                    $objWriter->writeElement('text:p', $cell->getValue());
251 1
                    break;
252 2
                case DataType::TYPE_STRING:
253 1
                    $objWriter->writeAttribute('office:value-type', 'string');
254 1
                    $objWriter->writeElement('text:p', $cell->getValue());
255 1
                    break;
256
            }
257 2
            Comment::write($objWriter, $cell);
258 2
            $objWriter->endElement();
259 2
            $prevColumn = $column;
260 2
            $cells->next();
261
        }
262 2
        $numberColsRepeated = $numberColsRepeated - $prevColumn - 1;
263 2 View Code Duplication
        if ($numberColsRepeated > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
264 2
            if ($numberColsRepeated > 1) {
265 2
                $objWriter->startElement('table:table-cell');
266 2
                $objWriter->writeAttribute('table:number-columns-repeated', $numberColsRepeated);
267 2
                $objWriter->endElement();
268
            } else {
269
                $objWriter->writeElement('table:table-cell');
270
            }
271
        }
272 2
    }
273
274
    /**
275
     * Write span.
276
     *
277
     * @param XMLWriter $objWriter
278
     * @param int $curColumn
279
     * @param int $prevColumn
280
     */
281 2
    private function writeCellSpan(XMLWriter $objWriter, $curColumn, $prevColumn)
282
    {
283 2
        $diff = $curColumn - $prevColumn - 1;
284 2 View Code Duplication
        if (1 === $diff) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
285
            $objWriter->writeElement('table:table-cell');
286 2
        } elseif ($diff > 1) {
287
            $objWriter->startElement('table:table-cell');
288
            $objWriter->writeAttribute('table:number-columns-repeated', $diff);
289
            $objWriter->endElement();
290
        }
291 2
    }
292
293
    /**
294
     * Write XF cell styles.
295
     *
296
     * @param XMLWriter $writer
297
     * @param Spreadsheet $spreadsheet
298
     */
299 2
    private function writeXfStyles(XMLWriter $writer, Spreadsheet $spreadsheet)
300
    {
301 2
        foreach ($spreadsheet->getCellXfCollection() as $style) {
302 2
            $writer->startElement('style:style');
303 2
            $writer->writeAttribute('style:name', self::CELL_STYLE_PREFIX . $style->getIndex());
304 2
            $writer->writeAttribute('style:family', 'table-cell');
305 2
            $writer->writeAttribute('style:parent-style-name', 'Default');
306
307
            /*
308
             * style:text-properties
309
             */
310
311
            // Font
312 2
            $writer->startElement('style:text-properties');
313
314 2
            $font = $style->getFont();
315
316 2
            if ($font->getBold()) {
317 1
                $writer->writeAttribute('fo:font-weight', 'bold');
318 1
                $writer->writeAttribute('style:font-weight-complex', 'bold');
319 1
                $writer->writeAttribute('style:font-weight-asian', 'bold');
320
            }
321
322 2
            if ($font->getItalic()) {
323 1
                $writer->writeAttribute('fo:font-style', 'italic');
324
            }
325
326 2
            if ($color = $font->getColor()) {
327 2
                $writer->writeAttribute('fo:color', sprintf('#%s', $color->getRGB()));
328
            }
329
330 2
            if ($family = $font->getName()) {
331 2
                $writer->writeAttribute('fo:font-family', $family);
332
            }
333
334 2
            if ($size = $font->getSize()) {
335 2
                $writer->writeAttribute('fo:font-size', sprintf('%.1fpt', $size));
336
            }
337
338 2
            if ($font->getUnderline() && $font->getUnderline() != Font::UNDERLINE_NONE) {
339 1
                $writer->writeAttribute('style:text-underline-style', 'solid');
340 1
                $writer->writeAttribute('style:text-underline-width', 'auto');
341 1
                $writer->writeAttribute('style:text-underline-color', 'font-color');
342
343 1
                switch ($font->getUnderline()) {
344 1
                    case Font::UNDERLINE_DOUBLE:
345 1
                        $writer->writeAttribute('style:text-underline-type', 'double');
346 1
                        break;
347 1
                    case Font::UNDERLINE_SINGLE:
348 1
                        $writer->writeAttribute('style:text-underline-type', 'single');
349 1
                        break;
350
                }
351
            }
352
353 2
            $writer->endElement(); // Close style:text-properties
354
355
            /*
356
             * style:table-cell-properties
357
             */
358
359 2
            $writer->startElement('style:table-cell-properties');
360 2
            $writer->writeAttribute('style:rotation-align', 'none');
361
362
            // Fill
363 2
            if ($fill = $style->getFill()) {
364 2
                switch ($fill->getFillType()) {
365 2
                    case Fill::FILL_SOLID:
366 1
                        $writer->writeAttribute('fo:background-color', sprintf(
367 1
                            '#%s',
368 1
                            strtolower($fill->getStartColor()->getRGB())
369
                        ));
370 1
                        break;
371 2
                    case Fill::FILL_GRADIENT_LINEAR:
372 2
                    case Fill::FILL_GRADIENT_PATH:
373
                        /// TODO :: To be implemented
374
                        break;
375 2
                    case Fill::FILL_NONE:
376
                    default:
377
                }
378
            }
379
380 2
            $writer->endElement(); // Close style:table-cell-properties
381
382
            /*
383
             * End
384
             */
385
386 2
            $writer->endElement(); // Close style:style
387
        }
388 2
    }
389
}
390