Completed
Push — develop ( d383bc...d9bd45 )
by Adrien
23:59
created

Gnumeric::listWorksheetInfo()   C

Complexity

Conditions 11
Paths 7

Size

Total Lines 40
Code Lines 28

Duplication

Lines 5
Ratio 12.5 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 28
nc 7
nop 1
dl 5
loc 40
ccs 0
cts 24
cp 0
crap 132
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\ReferenceHelper;
9
use PhpOffice\PhpSpreadsheet\RichText\RichText;
10
use PhpOffice\PhpSpreadsheet\Settings;
11
use PhpOffice\PhpSpreadsheet\Shared\Date;
12
use PhpOffice\PhpSpreadsheet\Shared\File;
13
use PhpOffice\PhpSpreadsheet\Spreadsheet;
14
use PhpOffice\PhpSpreadsheet\Style\Alignment;
15
use PhpOffice\PhpSpreadsheet\Style\Border;
16
use PhpOffice\PhpSpreadsheet\Style\Borders;
17
use PhpOffice\PhpSpreadsheet\Style\Fill;
18
use PhpOffice\PhpSpreadsheet\Style\Font;
19
use XMLReader;
20
21
class Gnumeric extends BaseReader
22
{
23
    /**
24
     * Shared Expressions.
25
     *
26
     * @var array
27
     */
28
    private $expressions = [];
29
30
    private $referenceHelper;
31
32
    /**
33
     * Create a new Gnumeric.
34
     */
35 4
    public function __construct()
36
    {
37 4
        $this->readFilter = new DefaultReadFilter();
38 4
        $this->referenceHelper = ReferenceHelper::getInstance();
39 4
    }
40
41
    /**
42
     * Can the current IReader read the file?
43
     *
44
     * @param string $pFilename
45
     *
46
     * @throws Exception
47
     *
48
     * @return bool
49
     */
50 3
    public function canRead($pFilename)
51
    {
52 3
        File::assertFile($pFilename);
53
54
        // Check if gzlib functions are available
55 3
        if (!function_exists('gzread')) {
56
            throw new Exception('gzlib library is not enabled');
57
        }
58
59
        // Read signature data (first 3 bytes)
60 3
        $fh = fopen($pFilename, 'r');
61 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

61
        $data = fread(/** @scrutinizer ignore-type */ $fh, 2);
Loading history...
62 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

62
        fclose(/** @scrutinizer ignore-type */ $fh);
Loading history...
63
64 3
        return $data == chr(0x1F) . chr(0x8B);
65
    }
66
67
    /**
68
     * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object.
69
     *
70
     * @param string $pFilename
71
     *
72
     * @throws Exception
73
     */
74
    public function listWorksheetNames($pFilename)
75
    {
76
        File::assertFile($pFilename);
77
78
        $xml = new XMLReader();
79
        $xml->xml($this->securityScanFile('compress.zlib://' . realpath($pFilename)), null, Settings::getLibXmlLoaderOptions());
80
        $xml->setParserProperty(2, true);
81
82
        $worksheetNames = [];
83
        while ($xml->read()) {
84 View Code Duplication
            if ($xml->name == 'gnm:SheetName' && $xml->nodeType == XMLReader::ELEMENT) {
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...
85
                $xml->read(); //    Move onto the value node
86
                $worksheetNames[] = (string) $xml->value;
87
            } elseif ($xml->name == 'gnm:Sheets') {
88
                //    break out of the loop once we've got our sheet names rather than parse the entire file
89
                break;
90
            }
91
        }
92
93
        return $worksheetNames;
94
    }
95
96
    /**
97
     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
98
     *
99
     * @param string $pFilename
100
     *
101
     * @throws Exception
102
     */
103
    public function listWorksheetInfo($pFilename)
104
    {
105
        File::assertFile($pFilename);
106
107
        $xml = new XMLReader();
108
        $xml->xml($this->securityScanFile('compress.zlib://' . realpath($pFilename)), null, Settings::getLibXmlLoaderOptions());
109
        $xml->setParserProperty(2, true);
110
111
        $worksheetInfo = [];
112
        while ($xml->read()) {
113
            if ($xml->name == 'gnm:Sheet' && $xml->nodeType == XMLReader::ELEMENT) {
114
                $tmpInfo = [
115
                    'worksheetName' => '',
116
                    'lastColumnLetter' => 'A',
117
                    'lastColumnIndex' => 0,
118
                    'totalRows' => 0,
119
                    'totalColumns' => 0,
120
                ];
121
122
                while ($xml->read()) {
123
                    if ($xml->name == 'gnm:Name' && $xml->nodeType == XMLReader::ELEMENT) {
124
                        $xml->read(); //    Move onto the value node
125
                        $tmpInfo['worksheetName'] = (string) $xml->value;
126
                    } elseif ($xml->name == 'gnm:MaxCol' && $xml->nodeType == XMLReader::ELEMENT) {
127
                        $xml->read(); //    Move onto the value node
128
                        $tmpInfo['lastColumnIndex'] = (int) $xml->value;
129
                        $tmpInfo['totalColumns'] = (int) $xml->value + 1;
130 View Code Duplication
                    } elseif ($xml->name == 'gnm:MaxRow' && $xml->nodeType == XMLReader::ELEMENT) {
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...
131
                        $xml->read(); //    Move onto the value node
132
                        $tmpInfo['totalRows'] = (int) $xml->value + 1;
133
134
                        break;
135
                    }
136
                }
137
                $tmpInfo['lastColumnLetter'] = Coordinate::stringFromColumnIndex($tmpInfo['lastColumnIndex'] + 1);
138
                $worksheetInfo[] = $tmpInfo;
139
            }
140
        }
141
142
        return $worksheetInfo;
143
    }
144
145
    /**
146
     * @param string $filename
147
     */
148 1
    private function gzfileGetContents($filename)
149
    {
150 1
        $file = @gzopen($filename, 'rb');
151 1
        if ($file !== false) {
152 1
            $data = '';
153 1
            while (!gzeof($file)) {
154 1
                $data .= gzread($file, 1024);
155
            }
156 1
            gzclose($file);
157
        }
158
159 1
        return $data;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.
Loading history...
160
    }
161
162
    /**
163
     * Loads Spreadsheet from file.
164
     *
165
     * @param string $pFilename
166
     *
167
     * @throws Exception
168
     *
169
     * @return Spreadsheet
170
     */
171 1
    public function load($pFilename)
172
    {
173
        // Create new Spreadsheet
174 1
        $spreadsheet = new Spreadsheet();
175
176
        // Load into this instance
177 1
        return $this->loadIntoExisting($pFilename, $spreadsheet);
178
    }
179
180
    /**
181
     * Loads from file into Spreadsheet instance.
182
     *
183
     * @param string $pFilename
184
     * @param Spreadsheet $spreadsheet
185
     *
186
     * @throws Exception
187
     *
188
     * @return Spreadsheet
189
     */
190 1
    public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
191
    {
192 1
        File::assertFile($pFilename);
193
194 1
        $gFileData = $this->gzfileGetContents($pFilename);
195
196 1
        $xml = simplexml_load_string($this->securityScan($gFileData), 'SimpleXMLElement', Settings::getLibXmlLoaderOptions());
197 1
        $namespacesMeta = $xml->getNamespaces(true);
198
199 1
        $gnmXML = $xml->children($namespacesMeta['gnm']);
200
201 1
        $docProps = $spreadsheet->getProperties();
202
        //    Document Properties are held differently, depending on the version of Gnumeric
203 1
        if (isset($namespacesMeta['office'])) {
204 1
            $officeXML = $xml->children($namespacesMeta['office']);
205 1
            $officeDocXML = $officeXML->{'document-meta'};
206 1
            $officeDocMetaXML = $officeDocXML->meta;
207
208 1
            foreach ($officeDocMetaXML as $officePropertyData) {
209 1
                $officePropertyDC = [];
210 1
                if (isset($namespacesMeta['dc'])) {
211 1
                    $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']);
212
                }
213 1
                foreach ($officePropertyDC as $propertyName => $propertyValue) {
214 1
                    $propertyValue = (string) $propertyValue;
215
                    switch ($propertyName) {
216 1
                        case 'title':
217 1
                            $docProps->setTitle(trim($propertyValue));
218
219 1
                            break;
220 1
                        case 'subject':
221 1
                            $docProps->setSubject(trim($propertyValue));
222
223 1
                            break;
224 1
                        case 'creator':
225 1
                            $docProps->setCreator(trim($propertyValue));
226 1
                            $docProps->setLastModifiedBy(trim($propertyValue));
227
228 1
                            break;
229 1 View Code Duplication
                        case 'date':
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...
230 1
                            $creationDate = strtotime(trim($propertyValue));
231 1
                            $docProps->setCreated($creationDate);
0 ignored issues
show
Bug introduced by
$creationDate of type integer is incompatible with the type PhpOffice\PhpSpreadsheet\Document\datetime expected by parameter $pValue of PhpOffice\PhpSpreadsheet...roperties::setCreated(). ( Ignorable by Annotation )

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

231
                            $docProps->setCreated(/** @scrutinizer ignore-type */ $creationDate);
Loading history...
232 1
                            $docProps->setModified($creationDate);
0 ignored issues
show
Bug introduced by
$creationDate of type integer is incompatible with the type PhpOffice\PhpSpreadsheet\Document\datetime expected by parameter $pValue of PhpOffice\PhpSpreadsheet...operties::setModified(). ( Ignorable by Annotation )

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

232
                            $docProps->setModified(/** @scrutinizer ignore-type */ $creationDate);
Loading history...
233
234 1
                            break;
235 1
                        case 'description':
236 1
                            $docProps->setDescription(trim($propertyValue));
237
238 1
                            break;
239
                    }
240
                }
241 1
                $officePropertyMeta = [];
242 1
                if (isset($namespacesMeta['meta'])) {
243 1
                    $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
244
                }
245 1
                foreach ($officePropertyMeta as $propertyName => $propertyValue) {
246 1
                    $attributes = $propertyValue->attributes($namespacesMeta['meta']);
247 1
                    $propertyValue = (string) $propertyValue;
248
                    switch ($propertyName) {
249 1
                        case 'keyword':
250 1
                            $docProps->setKeywords(trim($propertyValue));
251
252 1
                            break;
253 1
                        case 'initial-creator':
254 1
                            $docProps->setCreator(trim($propertyValue));
255 1
                            $docProps->setLastModifiedBy(trim($propertyValue));
256
257 1
                            break;
258 1 View Code Duplication
                        case 'creation-date':
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...
259 1
                            $creationDate = strtotime(trim($propertyValue));
260 1
                            $docProps->setCreated($creationDate);
261 1
                            $docProps->setModified($creationDate);
262
263 1
                            break;
264 1
                        case 'user-defined':
265 1
                            list(, $attrName) = explode(':', $attributes['name']);
266
                            switch ($attrName) {
267 1
                                case 'publisher':
268 1
                                    $docProps->setCompany(trim($propertyValue));
269
270 1
                                    break;
271 1
                                case 'category':
272 1
                                    $docProps->setCategory(trim($propertyValue));
273
274 1
                                    break;
275 1
                                case 'manager':
276 1
                                    $docProps->setManager(trim($propertyValue));
277
278 1
                                    break;
279
                            }
280
281 1
                            break;
282
                    }
283
                }
284
            }
285
        } elseif (isset($gnmXML->Summary)) {
286
            foreach ($gnmXML->Summary->Item as $summaryItem) {
287
                $propertyName = $summaryItem->name;
288
                $propertyValue = $summaryItem->{'val-string'};
289
                switch ($propertyName) {
290
                    case 'title':
291
                        $docProps->setTitle(trim($propertyValue));
292
293
                        break;
294
                    case 'comments':
295
                        $docProps->setDescription(trim($propertyValue));
296
297
                        break;
298
                    case 'keywords':
299
                        $docProps->setKeywords(trim($propertyValue));
300
301
                        break;
302
                    case 'category':
303
                        $docProps->setCategory(trim($propertyValue));
304
305
                        break;
306
                    case 'manager':
307
                        $docProps->setManager(trim($propertyValue));
308
309
                        break;
310
                    case 'author':
311
                        $docProps->setCreator(trim($propertyValue));
312
                        $docProps->setLastModifiedBy(trim($propertyValue));
313
314
                        break;
315
                    case 'company':
316
                        $docProps->setCompany(trim($propertyValue));
317
318
                        break;
319
                }
320
            }
321
        }
322
323 1
        $worksheetID = 0;
324 1
        foreach ($gnmXML->Sheets->Sheet as $sheet) {
325 1
            $worksheetName = (string) $sheet->Name;
326 1
            if ((isset($this->loadSheetsOnly)) && (!in_array($worksheetName, $this->loadSheetsOnly))) {
327
                continue;
328
            }
329
330 1
            $maxRow = $maxCol = 0;
331
332
            // Create new Worksheet
333 1
            $spreadsheet->createSheet();
334 1
            $spreadsheet->setActiveSheetIndex($worksheetID);
335
            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
336
            //        cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
337
            //        name in line with the formula, not the reverse
338 1
            $spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
339
340 1
            if ((!$this->readDataOnly) && (isset($sheet->PrintInformation))) {
341 1
                if (isset($sheet->PrintInformation->Margins)) {
342 1
                    foreach ($sheet->PrintInformation->Margins->children('gnm', true) as $key => $margin) {
343 1
                        $marginAttributes = $margin->attributes();
344 1
                        $marginSize = 72 / 100; //    Default
345 1
                        switch ($marginAttributes['PrefUnit']) {
346 1
                            case 'mm':
347 1
                                $marginSize = (int) ($marginAttributes['Points']) / 100;
348
349 1
                                break;
350
                        }
351
                        switch ($key) {
352 1
                            case 'top':
353 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setTop($marginSize);
354
355 1
                                break;
356 1
                            case 'bottom':
357 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setBottom($marginSize);
358
359 1
                                break;
360 1
                            case 'left':
361 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setLeft($marginSize);
362
363 1
                                break;
364 1
                            case 'right':
365 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setRight($marginSize);
366
367 1
                                break;
368 1
                            case 'header':
369 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setHeader($marginSize);
370
371 1
                                break;
372 1
                            case 'footer':
373 1
                                $spreadsheet->getActiveSheet()->getPageMargins()->setFooter($marginSize);
374
375 1
                                break;
376
                        }
377
                    }
378
                }
379
            }
380
381 1
            foreach ($sheet->Cells->Cell as $cell) {
382 1
                $cellAttributes = $cell->attributes();
383 1
                $row = (int) $cellAttributes->Row + 1;
384 1
                $column = (int) $cellAttributes->Col;
385
386 1
                if ($row > $maxRow) {
387 1
                    $maxRow = $row;
388
                }
389 1
                if ($column > $maxCol) {
390 1
                    $maxCol = $column;
391
                }
392
393 1
                $column = Coordinate::stringFromColumnIndex($column + 1);
394
395
                // Read cell?
396 1
                if ($this->getReadFilter() !== null) {
397 1
                    if (!$this->getReadFilter()->readCell($column, $row, $worksheetName)) {
398
                        continue;
399
                    }
400
                }
401
402 1
                $ValueType = $cellAttributes->ValueType;
403 1
                $ExprID = (string) $cellAttributes->ExprID;
404 1
                $type = DataType::TYPE_FORMULA;
405 1
                if ($ExprID > '') {
406 1
                    if (((string) $cell) > '') {
407 1
                        $this->expressions[$ExprID] = [
408 1
                            'column' => $cellAttributes->Col,
409 1
                            'row' => $cellAttributes->Row,
410 1
                            'formula' => (string) $cell,
411
                        ];
412
                    } else {
413 1
                        $expression = $this->expressions[$ExprID];
414
415 1
                        $cell = $this->referenceHelper->updateFormulaReferences(
416 1
                            $expression['formula'],
417 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

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