Passed
Push — develop ( 3bea6f...0f8f07 )
by Mark
36:13
created

Gnumeric   F

Complexity

Total Complexity 187

Size/Duplication

Total Lines 870
Duplicated Lines 0 %

Test Coverage

Coverage 76.45%

Importance

Changes 0
Metric Value
eloc 538
dl 0
loc 870
ccs 409
cts 535
cp 0.7645
rs 2
c 0
b 0
f 0
wmc 187

10 Methods

Rating   Name   Duplication   Size   Complexity  
F loadIntoExisting() 0 606 146
A parseRichText() 0 6 1
C parseBorderAttributes() 0 67 16
A listWorksheetNames() 0 20 5
A __construct() 0 5 1
A parseGnumericColour() 0 8 1
A gzfileGetContents() 0 12 3
B listWorksheetInfo() 0 40 11
A canRead() 0 15 2
A load() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like Gnumeric often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Gnumeric, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Reader;
4
5
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
6
use PhpOffice\PhpSpreadsheet\Cell\DataType;
7
use PhpOffice\PhpSpreadsheet\NamedRange;
8
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
9
use PhpOffice\PhpSpreadsheet\ReferenceHelper;
10
use PhpOffice\PhpSpreadsheet\RichText\RichText;
11
use PhpOffice\PhpSpreadsheet\Settings;
12
use PhpOffice\PhpSpreadsheet\Shared\Date;
13
use PhpOffice\PhpSpreadsheet\Shared\File;
14
use PhpOffice\PhpSpreadsheet\Spreadsheet;
15
use PhpOffice\PhpSpreadsheet\Style\Alignment;
16
use PhpOffice\PhpSpreadsheet\Style\Border;
17
use PhpOffice\PhpSpreadsheet\Style\Borders;
18
use PhpOffice\PhpSpreadsheet\Style\Fill;
19
use PhpOffice\PhpSpreadsheet\Style\Font;
20
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
21
use XMLReader;
22
23
class Gnumeric extends BaseReader
24
{
25
    /**
26
     * Shared Expressions.
27
     *
28
     * @var array
29
     */
30
    private $expressions = [];
31
32
    private $referenceHelper;
33
34
    /**
35
     * @var XmlScanner
36
     */
37
    private $securityScanner;
38
39
    /**
40
     * Create a new Gnumeric.
41
     */
42 4
    public function __construct()
43
    {
44 4
        $this->readFilter = new DefaultReadFilter();
45 4
        $this->referenceHelper = ReferenceHelper::getInstance();
46 4
        $this->securityScanner = new XmlScanner();
47 4
    }
48
49
    /**
50
     * Can the current IReader read the file?
51
     *
52
     * @param string $pFilename
53
     *
54
     * @throws Exception
55
     *
56
     * @return bool
57
     */
58 3
    public function canRead($pFilename)
59
    {
60 3
        File::assertFile($pFilename);
61
62
        // Check if gzlib functions are available
63 3
        if (!function_exists('gzread')) {
64
            throw new Exception('gzlib library is not enabled');
65
        }
66
67
        // Read signature data (first 3 bytes)
68 3
        $fh = fopen($pFilename, 'r');
69 3
        $data = fread($fh, 2);
1 ignored issue
show
Bug introduced by
It seems like $fh can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

69
        $data = fread(/** @scrutinizer ignore-type */ $fh, 2);
Loading history...
70 3
        fclose($fh);
1 ignored issue
show
Bug introduced by
It seems like $fh can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
        fclose(/** @scrutinizer ignore-type */ $fh);
Loading history...
71
72 3
        return $data == chr(0x1F) . chr(0x8B);
73
    }
74
75
    /**
76
     * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object.
77
     *
78
     * @param string $pFilename
79
     *
80
     * @return array
81
     */
82
    public function listWorksheetNames($pFilename)
83
    {
84
        File::assertFile($pFilename);
85
86
        $xml = new XMLReader();
87
        $xml->xml($this->securityScanner->scanFile('compress.zlib://' . realpath($pFilename)), null, Settings::getLibXmlLoaderOptions());
88
        $xml->setParserProperty(2, true);
89
90
        $worksheetNames = [];
91
        while ($xml->read()) {
92
            if ($xml->name == 'gnm:SheetName' && $xml->nodeType == XMLReader::ELEMENT) {
93
                $xml->read(); //    Move onto the value node
94
                $worksheetNames[] = (string) $xml->value;
95
            } elseif ($xml->name == 'gnm:Sheets') {
96
                //    break out of the loop once we've got our sheet names rather than parse the entire file
97
                break;
98
            }
99
        }
100
101
        return $worksheetNames;
102
    }
103
104
    /**
105
     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
106
     *
107
     * @param string $pFilename
108
     *
109
     * @return array
110
     */
111
    public function listWorksheetInfo($pFilename)
112
    {
113
        File::assertFile($pFilename);
114
115
        $xml = new XMLReader();
116
        $xml->xml($this->securityScanner->scanFile('compress.zlib://' . realpath($pFilename)), null, Settings::getLibXmlLoaderOptions());
117
        $xml->setParserProperty(2, true);
118
119
        $worksheetInfo = [];
120
        while ($xml->read()) {
121
            if ($xml->name == 'gnm:Sheet' && $xml->nodeType == XMLReader::ELEMENT) {
122
                $tmpInfo = [
123
                    'worksheetName' => '',
124
                    'lastColumnLetter' => 'A',
125
                    'lastColumnIndex' => 0,
126
                    'totalRows' => 0,
127
                    'totalColumns' => 0,
128
                ];
129
130
                while ($xml->read()) {
131
                    if ($xml->name == 'gnm:Name' && $xml->nodeType == XMLReader::ELEMENT) {
132
                        $xml->read(); //    Move onto the value node
133
                        $tmpInfo['worksheetName'] = (string) $xml->value;
134
                    } elseif ($xml->name == 'gnm:MaxCol' && $xml->nodeType == XMLReader::ELEMENT) {
135
                        $xml->read(); //    Move onto the value node
136
                        $tmpInfo['lastColumnIndex'] = (int) $xml->value;
137
                        $tmpInfo['totalColumns'] = (int) $xml->value + 1;
138
                    } elseif ($xml->name == 'gnm:MaxRow' && $xml->nodeType == XMLReader::ELEMENT) {
139
                        $xml->read(); //    Move onto the value node
140
                        $tmpInfo['totalRows'] = (int) $xml->value + 1;
141
142
                        break;
143
                    }
144
                }
145
                $tmpInfo['lastColumnLetter'] = Coordinate::stringFromColumnIndex($tmpInfo['lastColumnIndex'] + 1);
146
                $worksheetInfo[] = $tmpInfo;
147
            }
148
        }
149
150
        return $worksheetInfo;
151
    }
152
153
    /**
154
     * @param string $filename
155
     *
156
     * @return string
157
     */
158 1
    private function gzfileGetContents($filename)
159
    {
160 1
        $file = @gzopen($filename, 'rb');
161 1
        $data = '';
162 1
        if ($file !== false) {
163 1
            while (!gzeof($file)) {
164 1
                $data .= gzread($file, 1024);
165
            }
166 1
            gzclose($file);
167
        }
168
169 1
        return $data;
170
    }
171
172
    /**
173
     * Loads Spreadsheet from file.
174
     *
175
     * @param string $pFilename
176
     *
177
     * @throws Exception
178
     *
179
     * @return Spreadsheet
180
     */
181 1
    public function load($pFilename)
182
    {
183
        // Create new Spreadsheet
184 1
        $spreadsheet = new Spreadsheet();
185
186
        // Load into this instance
187 1
        return $this->loadIntoExisting($pFilename, $spreadsheet);
188
    }
189
190
    /**
191
     * Loads from file into Spreadsheet instance.
192
     *
193
     * @param string $pFilename
194
     * @param Spreadsheet $spreadsheet
195
     *
196
     * @throws Exception
197
     *
198
     * @return Spreadsheet
199
     */
200 1
    public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
201
    {
202 1
        File::assertFile($pFilename);
203
204 1
        $gFileData = $this->gzfileGetContents($pFilename);
205
206 1
        $xml = simplexml_load_string($this->securityScanner->scan($gFileData), 'SimpleXMLElement', Settings::getLibXmlLoaderOptions());
207 1
        $namespacesMeta = $xml->getNamespaces(true);
208
209 1
        $gnmXML = $xml->children($namespacesMeta['gnm']);
210
211 1
        $docProps = $spreadsheet->getProperties();
212
        //    Document Properties are held differently, depending on the version of Gnumeric
213 1
        if (isset($namespacesMeta['office'])) {
214 1
            $officeXML = $xml->children($namespacesMeta['office']);
215 1
            $officeDocXML = $officeXML->{'document-meta'};
216 1
            $officeDocMetaXML = $officeDocXML->meta;
217
218 1
            foreach ($officeDocMetaXML as $officePropertyData) {
219 1
                $officePropertyDC = [];
220 1
                if (isset($namespacesMeta['dc'])) {
221 1
                    $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']);
222
                }
223 1
                foreach ($officePropertyDC as $propertyName => $propertyValue) {
224 1
                    $propertyValue = (string) $propertyValue;
225 1
                    switch ($propertyName) {
226 1
                        case 'title':
227 1
                            $docProps->setTitle(trim($propertyValue));
228
229 1
                            break;
230 1
                        case 'subject':
231 1
                            $docProps->setSubject(trim($propertyValue));
232
233 1
                            break;
234 1
                        case 'creator':
235 1
                            $docProps->setCreator(trim($propertyValue));
236 1
                            $docProps->setLastModifiedBy(trim($propertyValue));
237
238 1
                            break;
239 1
                        case 'date':
240 1
                            $creationDate = strtotime(trim($propertyValue));
241 1
                            $docProps->setCreated($creationDate);
242 1
                            $docProps->setModified($creationDate);
243
244 1
                            break;
245 1
                        case 'description':
246 1
                            $docProps->setDescription(trim($propertyValue));
247
248 1
                            break;
249
                    }
250
                }
251 1
                $officePropertyMeta = [];
252 1
                if (isset($namespacesMeta['meta'])) {
253 1
                    $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
254
                }
255 1
                foreach ($officePropertyMeta as $propertyName => $propertyValue) {
256 1
                    $attributes = $propertyValue->attributes($namespacesMeta['meta']);
257 1
                    $propertyValue = (string) $propertyValue;
258 1
                    switch ($propertyName) {
259 1
                        case 'keyword':
260 1
                            $docProps->setKeywords(trim($propertyValue));
261
262 1
                            break;
263 1
                        case 'initial-creator':
264 1
                            $docProps->setCreator(trim($propertyValue));
265 1
                            $docProps->setLastModifiedBy(trim($propertyValue));
266
267 1
                            break;
268 1
                        case 'creation-date':
269 1
                            $creationDate = strtotime(trim($propertyValue));
270 1
                            $docProps->setCreated($creationDate);
271 1
                            $docProps->setModified($creationDate);
272
273 1
                            break;
274 1
                        case 'user-defined':
275 1
                            list(, $attrName) = explode(':', $attributes['name']);
276 1
                            switch ($attrName) {
277 1
                                case 'publisher':
278 1
                                    $docProps->setCompany(trim($propertyValue));
279
280 1
                                    break;
281 1
                                case 'category':
282 1
                                    $docProps->setCategory(trim($propertyValue));
283
284 1
                                    break;
285 1
                                case 'manager':
286 1
                                    $docProps->setManager(trim($propertyValue));
287
288 1
                                    break;
289
                            }
290
291 1
                            break;
292
                    }
293
                }
294
            }
295
        } elseif (isset($gnmXML->Summary)) {
296
            foreach ($gnmXML->Summary->Item as $summaryItem) {
297
                $propertyName = $summaryItem->name;
298
                $propertyValue = $summaryItem->{'val-string'};
299
                switch ($propertyName) {
300
                    case 'title':
301
                        $docProps->setTitle(trim($propertyValue));
302
303
                        break;
304
                    case 'comments':
305
                        $docProps->setDescription(trim($propertyValue));
306
307
                        break;
308
                    case 'keywords':
309
                        $docProps->setKeywords(trim($propertyValue));
310
311
                        break;
312
                    case 'category':
313
                        $docProps->setCategory(trim($propertyValue));
314
315
                        break;
316
                    case 'manager':
317
                        $docProps->setManager(trim($propertyValue));
318
319
                        break;
320
                    case 'author':
321
                        $docProps->setCreator(trim($propertyValue));
322
                        $docProps->setLastModifiedBy(trim($propertyValue));
323
324
                        break;
325
                    case 'company':
326
                        $docProps->setCompany(trim($propertyValue));
327
328
                        break;
329
                }
330
            }
331
        }
332
333 1
        $worksheetID = 0;
334 1
        foreach ($gnmXML->Sheets->Sheet as $sheet) {
335 1
            $worksheetName = (string) $sheet->Name;
336 1
            if ((isset($this->loadSheetsOnly)) && (!in_array($worksheetName, $this->loadSheetsOnly))) {
337
                continue;
338
            }
339
340 1
            $maxRow = $maxCol = 0;
341
342
            // Create new Worksheet
343 1
            $spreadsheet->createSheet();
344 1
            $spreadsheet->setActiveSheetIndex($worksheetID);
345
            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
346
            //        cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
347
            //        name in line with the formula, not the reverse
348 1
            $spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
349
350 1
            if ((!$this->readDataOnly) && (isset($sheet->PrintInformation))) {
351 1
                if (isset($sheet->PrintInformation->Margins)) {
352 1
                    foreach ($sheet->PrintInformation->Margins->children('gnm', true) as $key => $margin) {
353 1
                        $marginAttributes = $margin->attributes();
354 1
                        $marginSize = 72 / 100; //    Default
355 1
                        switch ($marginAttributes['PrefUnit']) {
356 1
                            case 'mm':
357 1
                                $marginSize = (int) ($marginAttributes['Points']) / 100;
358
359 1
                                break;
360
                        }
361 1
                        switch ($key) {
362 1
                            case 'top':
363 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setTop($marginSize);
364
365 1
                                break;
366 1
                            case 'bottom':
367 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setBottom($marginSize);
368
369 1
                                break;
370 1
                            case 'left':
371 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setLeft($marginSize);
372
373 1
                                break;
374 1
                            case 'right':
375 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setRight($marginSize);
376
377 1
                                break;
378 1
                            case 'header':
379 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setHeader($marginSize);
380
381 1
                                break;
382 1
                            case 'footer':
383 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setFooter($marginSize);
384
385 1
                                break;
386
                        }
387
                    }
388
                }
389
            }
390
391 1
            foreach ($sheet->Cells->Cell as $cell) {
392 1
                $cellAttributes = $cell->attributes();
393 1
                $row = (int) $cellAttributes->Row + 1;
394 1
                $column = (int) $cellAttributes->Col;
395
396 1
                if ($row > $maxRow) {
397 1
                    $maxRow = $row;
398
                }
399 1
                if ($column > $maxCol) {
400 1
                    $maxCol = $column;
401
                }
402
403 1
                $column = Coordinate::stringFromColumnIndex($column + 1);
404
405
                // Read cell?
406 1
                if ($this->getReadFilter() !== null) {
407 1
                    if (!$this->getReadFilter()->readCell($column, $row, $worksheetName)) {
408
                        continue;
409
                    }
410
                }
411
412 1
                $ValueType = $cellAttributes->ValueType;
413 1
                $ExprID = (string) $cellAttributes->ExprID;
414 1
                $type = DataType::TYPE_FORMULA;
415 1
                if ($ExprID > '') {
416 1
                    if (((string) $cell) > '') {
417 1
                        $this->expressions[$ExprID] = [
418 1
                            'column' => $cellAttributes->Col,
419 1
                            'row' => $cellAttributes->Row,
420 1
                            'formula' => (string) $cell,
421
                        ];
422
                    } else {
423 1
                        $expression = $this->expressions[$ExprID];
424
425 1
                        $cell = $this->referenceHelper->updateFormulaReferences(
426 1
                            $expression['formula'],
427 1
                            'A1',
0 ignored issues
show
Bug introduced by
'A1' of type string is incompatible with the type integer expected by parameter $pBefore of PhpOffice\PhpSpreadsheet...dateFormulaReferences(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

427
                            /** @scrutinizer ignore-type */ 'A1',
Loading history...
428 1
                            $cellAttributes->Col - $expression['column'],
429 1
                            $cellAttributes->Row - $expression['row'],
430 1
                            $worksheetName
431
                        );
432
                    }
433 1
                    $type = DataType::TYPE_FORMULA;
434
                } else {
435
                    switch ($ValueType) {
436 1
                        case '10':        //    NULL
437
                            $type = DataType::TYPE_NULL;
438
439
                            break;
440 1
                        case '20':        //    Boolean
441 1
                            $type = DataType::TYPE_BOOL;
442 1
                            $cell = $cell == 'TRUE';
443
444 1
                            break;
445 1
                        case '30':        //    Integer
446
                            $cell = (int) $cell;
447
                            // Excel 2007+ doesn't differentiate between integer and float, so set the value and dropthru to the next (numeric) case
448
                            // no break
449 1
                        case '40':        //    Float
450 1
                            $type = DataType::TYPE_NUMERIC;
451
452 1
                            break;
453 1
                        case '50':        //    Error
454
                            $type = DataType::TYPE_ERROR;
455
456
                            break;
457 1
                        case '60':        //    String
458 1
                            $type = DataType::TYPE_STRING;
459
460 1
                            break;
461 1
                        case '70':        //    Cell Range
462 1
                        case '80':        //    Array
463
                    }
464
                }
465 1
                $spreadsheet->getActiveSheet()->getCell($column . $row)->setValueExplicit($cell, $type);
466
            }
467
468 1
            if ((!$this->readDataOnly) && (isset($sheet->Objects))) {
469 1
                foreach ($sheet->Objects->children('gnm', true) as $key => $comment) {
470 1
                    $commentAttributes = $comment->attributes();
471
                    //    Only comment objects are handled at the moment
472 1
                    if ($commentAttributes->Text) {
473 1
                        $spreadsheet->getActiveSheet()->getComment((string) $commentAttributes->ObjectBound)->setAuthor((string) $commentAttributes->Author)->setText($this->parseRichText((string) $commentAttributes->Text));
474
                    }
475
                }
476
            }
477 1
            foreach ($sheet->Styles->StyleRegion as $styleRegion) {
478 1
                $styleAttributes = $styleRegion->attributes();
479 1
                if (($styleAttributes['startRow'] <= $maxRow) &&
480 1
                    ($styleAttributes['startCol'] <= $maxCol)) {
481 1
                    $startColumn = Coordinate::stringFromColumnIndex((int) $styleAttributes['startCol'] + 1);
482 1
                    $startRow = $styleAttributes['startRow'] + 1;
483
484 1
                    $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol'];
485 1
                    $endColumn = Coordinate::stringFromColumnIndex($endColumn + 1);
486 1
                    $endRow = ($styleAttributes['endRow'] > $maxRow) ? $maxRow : $styleAttributes['endRow'];
487 1
                    $endRow += 1;
488 1
                    $cellRange = $startColumn . $startRow . ':' . $endColumn . $endRow;
489
490 1
                    $styleAttributes = $styleRegion->Style->attributes();
491
492
                    //    We still set the number format mask for date/time values, even if readDataOnly is true
493 1
                    if ((!$this->readDataOnly) ||
494 1
                        (Date::isDateTimeFormatCode((string) $styleAttributes['Format']))) {
495 1
                        $styleArray = [];
496 1
                        $styleArray['numberFormat']['formatCode'] = (string) $styleAttributes['Format'];
497
                        //    If readDataOnly is false, we set all formatting information
498 1
                        if (!$this->readDataOnly) {
499 1
                            switch ($styleAttributes['HAlign']) {
500 1
                                case '1':
501 1
                                    $styleArray['alignment']['horizontal'] = Alignment::HORIZONTAL_GENERAL;
502
503 1
                                    break;
504 1
                                case '2':
505 1
                                    $styleArray['alignment']['horizontal'] = Alignment::HORIZONTAL_LEFT;
506
507 1
                                    break;
508 1
                                case '4':
509 1
                                    $styleArray['alignment']['horizontal'] = Alignment::HORIZONTAL_RIGHT;
510
511 1
                                    break;
512 1
                                case '8':
513 1
                                    $styleArray['alignment']['horizontal'] = Alignment::HORIZONTAL_CENTER;
514
515 1
                                    break;
516
                                case '16':
517
                                case '64':
518
                                    $styleArray['alignment']['horizontal'] = Alignment::HORIZONTAL_CENTER_CONTINUOUS;
519
520
                                    break;
521
                                case '32':
522
                                    $styleArray['alignment']['horizontal'] = Alignment::HORIZONTAL_JUSTIFY;
523
524
                                    break;
525
                            }
526
527 1
                            switch ($styleAttributes['VAlign']) {
528 1
                                case '1':
529 1
                                    $styleArray['alignment']['vertical'] = Alignment::VERTICAL_TOP;
530
531 1
                                    break;
532 1
                                case '2':
533 1
                                    $styleArray['alignment']['vertical'] = Alignment::VERTICAL_BOTTOM;
534
535 1
                                    break;
536 1
                                case '4':
537 1
                                    $styleArray['alignment']['vertical'] = Alignment::VERTICAL_CENTER;
538
539 1
                                    break;
540
                                case '8':
541
                                    $styleArray['alignment']['vertical'] = Alignment::VERTICAL_JUSTIFY;
542
543
                                    break;
544
                            }
545
546 1
                            $styleArray['alignment']['wrapText'] = $styleAttributes['WrapText'] == '1';
547 1
                            $styleArray['alignment']['shrinkToFit'] = $styleAttributes['ShrinkToFit'] == '1';
548 1
                            $styleArray['alignment']['indent'] = ((int) ($styleAttributes['Indent']) > 0) ? $styleAttributes['indent'] : 0;
549
550 1
                            $RGB = self::parseGnumericColour($styleAttributes['Fore']);
551 1
                            $styleArray['font']['color']['rgb'] = $RGB;
552 1
                            $RGB = self::parseGnumericColour($styleAttributes['Back']);
553 1
                            $shade = $styleAttributes['Shade'];
554 1
                            if (($RGB != '000000') || ($shade != '0')) {
555 1
                                $styleArray['fill']['color']['rgb'] = $styleArray['fill']['startColor']['rgb'] = $RGB;
556 1
                                $RGB2 = self::parseGnumericColour($styleAttributes['PatternColor']);
557 1
                                $styleArray['fill']['endColor']['rgb'] = $RGB2;
558
                                switch ($shade) {
559 1
                                    case '1':
560 1
                                        $styleArray['fill']['fillType'] = Fill::FILL_SOLID;
561
562 1
                                        break;
563 1
                                    case '2':
564
                                        $styleArray['fill']['fillType'] = Fill::FILL_GRADIENT_LINEAR;
565
566
                                        break;
567 1
                                    case '3':
568
                                        $styleArray['fill']['fillType'] = Fill::FILL_GRADIENT_PATH;
569
570
                                        break;
571 1
                                    case '4':
572
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKDOWN;
573
574
                                        break;
575 1
                                    case '5':
576
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKGRAY;
577
578
                                        break;
579 1
                                    case '6':
580 1
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKGRID;
581
582 1
                                        break;
583 1
                                    case '7':
584 1
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKHORIZONTAL;
585
586 1
                                        break;
587 1
                                    case '8':
588
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKTRELLIS;
589
590
                                        break;
591 1
                                    case '9':
592
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKUP;
593
594
                                        break;
595 1
                                    case '10':
596
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_DARKVERTICAL;
597
598
                                        break;
599 1
                                    case '11':
600
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_GRAY0625;
601
602
                                        break;
603 1
                                    case '12':
604
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_GRAY125;
605
606
                                        break;
607 1
                                    case '13':
608
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTDOWN;
609
610
                                        break;
611 1
                                    case '14':
612
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTGRAY;
613
614
                                        break;
615 1
                                    case '15':
616
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTGRID;
617
618
                                        break;
619 1
                                    case '16':
620
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTHORIZONTAL;
621
622
                                        break;
623 1
                                    case '17':
624
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTTRELLIS;
625
626
                                        break;
627 1
                                    case '18':
628
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTUP;
629
630
                                        break;
631 1
                                    case '19':
632
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_LIGHTVERTICAL;
633
634
                                        break;
635 1
                                    case '20':
636
                                        $styleArray['fill']['fillType'] = Fill::FILL_PATTERN_MEDIUMGRAY;
637
638
                                        break;
639
                                }
640
                            }
641
642 1
                            $fontAttributes = $styleRegion->Style->Font->attributes();
643 1
                            $styleArray['font']['name'] = (string) $styleRegion->Style->Font;
644 1
                            $styleArray['font']['size'] = (int) ($fontAttributes['Unit']);
645 1
                            $styleArray['font']['bold'] = $fontAttributes['Bold'] == '1';
646 1
                            $styleArray['font']['italic'] = $fontAttributes['Italic'] == '1';
647 1
                            $styleArray['font']['strikethrough'] = $fontAttributes['StrikeThrough'] == '1';
648 1
                            switch ($fontAttributes['Underline']) {
649 1
                                case '1':
650 1
                                    $styleArray['font']['underline'] = Font::UNDERLINE_SINGLE;
651
652 1
                                    break;
653 1
                                case '2':
654 1
                                    $styleArray['font']['underline'] = Font::UNDERLINE_DOUBLE;
655
656 1
                                    break;
657 1
                                case '3':
658 1
                                    $styleArray['font']['underline'] = Font::UNDERLINE_SINGLEACCOUNTING;
659
660 1
                                    break;
661 1
                                case '4':
662 1
                                    $styleArray['font']['underline'] = Font::UNDERLINE_DOUBLEACCOUNTING;
663
664 1
                                    break;
665
                                default:
666 1
                                    $styleArray['font']['underline'] = Font::UNDERLINE_NONE;
667
668 1
                                    break;
669
                            }
670 1
                            switch ($fontAttributes['Script']) {
671 1
                                case '1':
672 1
                                    $styleArray['font']['superscript'] = true;
673
674 1
                                    break;
675 1
                                case '-1':
676 1
                                    $styleArray['font']['subscript'] = true;
677
678 1
                                    break;
679
                            }
680
681 1
                            if (isset($styleRegion->Style->StyleBorder)) {
682 1
                                if (isset($styleRegion->Style->StyleBorder->Top)) {
683 1
                                    $styleArray['borders']['top'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Top->attributes());
684
                                }
685 1
                                if (isset($styleRegion->Style->StyleBorder->Bottom)) {
686 1
                                    $styleArray['borders']['bottom'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Bottom->attributes());
687
                                }
688 1
                                if (isset($styleRegion->Style->StyleBorder->Left)) {
689 1
                                    $styleArray['borders']['left'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Left->attributes());
690
                                }
691 1
                                if (isset($styleRegion->Style->StyleBorder->Right)) {
692 1
                                    $styleArray['borders']['right'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Right->attributes());
693
                                }
694 1
                                if ((isset($styleRegion->Style->StyleBorder->Diagonal)) && (isset($styleRegion->Style->StyleBorder->{'Rev-Diagonal'}))) {
695 1
                                    $styleArray['borders']['diagonal'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Diagonal->attributes());
696 1
                                    $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_BOTH;
697 1
                                } elseif (isset($styleRegion->Style->StyleBorder->Diagonal)) {
698 1
                                    $styleArray['borders']['diagonal'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Diagonal->attributes());
699 1
                                    $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_UP;
700 1
                                } elseif (isset($styleRegion->Style->StyleBorder->{'Rev-Diagonal'})) {
701 1
                                    $styleArray['borders']['diagonal'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->{'Rev-Diagonal'}->attributes());
702 1
                                    $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_DOWN;
703
                                }
704
                            }
705 1
                            if (isset($styleRegion->Style->HyperLink)) {
706
                                //    TO DO
707 1
                                $hyperlink = $styleRegion->Style->HyperLink->attributes();
0 ignored issues
show
Unused Code introduced by
The assignment to $hyperlink is dead and can be removed.
Loading history...
708
                            }
709
                        }
710 1
                        $spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray);
711
                    }
712
                }
713
            }
714
715 1
            if ((!$this->readDataOnly) && (isset($sheet->Cols))) {
716
                //    Column Widths
717 1
                $columnAttributes = $sheet->Cols->attributes();
718 1
                $defaultWidth = $columnAttributes['DefaultSizePts'] / 5.4;
719 1
                $c = 0;
720 1
                foreach ($sheet->Cols->ColInfo as $columnOverride) {
721 1
                    $columnAttributes = $columnOverride->attributes();
722 1
                    $column = $columnAttributes['No'];
723 1
                    $columnWidth = $columnAttributes['Unit'] / 5.4;
724 1
                    $hidden = (isset($columnAttributes['Hidden'])) && ($columnAttributes['Hidden'] == '1');
725 1
                    $columnCount = (isset($columnAttributes['Count'])) ? $columnAttributes['Count'] : 1;
726 1
                    while ($c < $column) {
727 1
                        $spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($defaultWidth);
728 1
                        ++$c;
729
                    }
730 1
                    while (($c < ($column + $columnCount)) && ($c <= $maxCol)) {
731 1
                        $spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($columnWidth);
732 1
                        if ($hidden) {
733 1
                            $spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setVisible(false);
734
                        }
735 1
                        ++$c;
736
                    }
737
                }
738 1
                while ($c <= $maxCol) {
739
                    $spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($defaultWidth);
740
                    ++$c;
741
                }
742
            }
743
744 1
            if ((!$this->readDataOnly) && (isset($sheet->Rows))) {
745
                //    Row Heights
746 1
                $rowAttributes = $sheet->Rows->attributes();
747 1
                $defaultHeight = $rowAttributes['DefaultSizePts'];
748 1
                $r = 0;
749
750 1
                foreach ($sheet->Rows->RowInfo as $rowOverride) {
751 1
                    $rowAttributes = $rowOverride->attributes();
752 1
                    $row = $rowAttributes['No'];
753 1
                    $rowHeight = $rowAttributes['Unit'];
754 1
                    $hidden = (isset($rowAttributes['Hidden'])) && ($rowAttributes['Hidden'] == '1');
755 1
                    $rowCount = (isset($rowAttributes['Count'])) ? $rowAttributes['Count'] : 1;
756 1
                    while ($r < $row) {
757 1
                        ++$r;
758 1
                        $spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight);
759
                    }
760 1
                    while (($r < ($row + $rowCount)) && ($r < $maxRow)) {
761 1
                        ++$r;
762 1
                        $spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($rowHeight);
763 1
                        if ($hidden) {
764
                            $spreadsheet->getActiveSheet()->getRowDimension($r)->setVisible(false);
765
                        }
766
                    }
767
                }
768 1
                while ($r < $maxRow) {
769
                    ++$r;
770
                    $spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight);
771
                }
772
            }
773
774
            //    Handle Merged Cells in this worksheet
775 1
            if (isset($sheet->MergedRegions)) {
776 1
                foreach ($sheet->MergedRegions->Merge as $mergeCells) {
777 1
                    if (strpos($mergeCells, ':') !== false) {
778 1
                        $spreadsheet->getActiveSheet()->mergeCells($mergeCells);
779
                    }
780
                }
781
            }
782
783 1
            ++$worksheetID;
784
        }
785
786
        //    Loop through definedNames (global named ranges)
787 1
        if (isset($gnmXML->Names)) {
788 1
            foreach ($gnmXML->Names->Name as $namedRange) {
789 1
                $name = (string) $namedRange->name;
790 1
                $range = (string) $namedRange->value;
791 1
                if (stripos($range, '#REF!') !== false) {
792
                    continue;
793
                }
794
795 1
                $range = Worksheet::extractSheetTitle($range, true);
796 1
                $range[0] = trim($range[0], "'");
797 1
                if ($worksheet = $spreadsheet->getSheetByName($range[0])) {
798 1
                    $extractedRange = str_replace('$', '', $range[1]);
799 1
                    $spreadsheet->addNamedRange(new NamedRange($name, $worksheet, $extractedRange));
800
                }
801
            }
802
        }
803
804
        // Return
805 1
        return $spreadsheet;
806
    }
807
808 1
    private static function parseBorderAttributes($borderAttributes)
809
    {
810 1
        $styleArray = [];
811 1
        if (isset($borderAttributes['Color'])) {
812 1
            $styleArray['color']['rgb'] = self::parseGnumericColour($borderAttributes['Color']);
813
        }
814
815 1
        switch ($borderAttributes['Style']) {
816 1
            case '0':
817
                $styleArray['borderStyle'] = Border::BORDER_NONE;
818
819
                break;
820 1
            case '1':
821 1
                $styleArray['borderStyle'] = Border::BORDER_THIN;
822
823 1
                break;
824 1
            case '2':
825 1
                $styleArray['borderStyle'] = Border::BORDER_MEDIUM;
826
827 1
                break;
828 1
            case '3':
829
                $styleArray['borderStyle'] = Border::BORDER_SLANTDASHDOT;
830
831
                break;
832 1
            case '4':
833 1
                $styleArray['borderStyle'] = Border::BORDER_DASHED;
834
835 1
                break;
836 1
            case '5':
837 1
                $styleArray['borderStyle'] = Border::BORDER_THICK;
838
839 1
                break;
840 1
            case '6':
841 1
                $styleArray['borderStyle'] = Border::BORDER_DOUBLE;
842
843 1
                break;
844 1
            case '7':
845 1
                $styleArray['borderStyle'] = Border::BORDER_DOTTED;
846
847 1
                break;
848 1
            case '8':
849 1
                $styleArray['borderStyle'] = Border::BORDER_MEDIUMDASHED;
850
851 1
                break;
852 1
            case '9':
853 1
                $styleArray['borderStyle'] = Border::BORDER_DASHDOT;
854
855 1
                break;
856 1
            case '10':
857 1
                $styleArray['borderStyle'] = Border::BORDER_MEDIUMDASHDOT;
858
859 1
                break;
860 1
            case '11':
861 1
                $styleArray['borderStyle'] = Border::BORDER_DASHDOTDOT;
862
863 1
                break;
864 1
            case '12':
865 1
                $styleArray['borderStyle'] = Border::BORDER_MEDIUMDASHDOTDOT;
866
867 1
                break;
868 1
            case '13':
869 1
                $styleArray['borderStyle'] = Border::BORDER_MEDIUMDASHDOTDOT;
870
871 1
                break;
872
        }
873
874 1
        return $styleArray;
875
    }
876
877 1
    private function parseRichText($is)
878
    {
879 1
        $value = new RichText();
880 1
        $value->createText($is);
881
882 1
        return $value;
883
    }
884
885 1
    private static function parseGnumericColour($gnmColour)
886
    {
887 1
        list($gnmR, $gnmG, $gnmB) = explode(':', $gnmColour);
888 1
        $gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
889 1
        $gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
890 1
        $gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);
891
892 1
        return $gnmR . $gnmG . $gnmB;
893
    }
894
}
895