Failed Conditions
Push — master ( 4b6ad7...9fab89 )
by Adrien
06:57
created

Html::applyInlineStyle()   D

Complexity

Conditions 32
Paths 114

Size

Total Lines 144
Code Lines 85

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 82
CRAP Score 32.0138

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 32
eloc 85
c 1
b 0
f 0
nc 114
nop 4
dl 0
loc 144
ccs 82
cts 84
cp 0.9762
crap 32.0138
rs 4.05

How to fix   Long Method    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 DOMDocument;
6
use DOMElement;
7
use DOMNode;
8
use DOMText;
9
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
10
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
11
use PhpOffice\PhpSpreadsheet\Spreadsheet;
12
use PhpOffice\PhpSpreadsheet\Style\Border;
13
use PhpOffice\PhpSpreadsheet\Style\Color;
14
use PhpOffice\PhpSpreadsheet\Style\Fill;
15
use PhpOffice\PhpSpreadsheet\Style\Font;
16
use PhpOffice\PhpSpreadsheet\Style\Style;
17
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
18
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
19
20
/** PhpSpreadsheet root directory */
21
class Html extends BaseReader
22
{
23
    /**
24
     * Sample size to read to determine if it's HTML or not.
25
     */
26
    const TEST_SAMPLE_SIZE = 2048;
27
28
    /**
29
     * Input encoding.
30
     *
31
     * @var string
32
     */
33
    protected $inputEncoding = 'ANSI';
34
35
    /**
36
     * Sheet index to read.
37
     *
38
     * @var int
39
     */
40
    protected $sheetIndex = 0;
41
42
    /**
43
     * Formats.
44
     *
45
     * @var array
46
     */
47
    protected $formats = [
48
        'h1' => [
49
            'font' => [
50
                'bold' => true,
51
                'size' => 24,
52
            ],
53
        ], //    Bold, 24pt
54
        'h2' => [
55
            'font' => [
56
                'bold' => true,
57
                'size' => 18,
58
            ],
59
        ], //    Bold, 18pt
60
        'h3' => [
61
            'font' => [
62
                'bold' => true,
63
                'size' => 13.5,
64
            ],
65
        ], //    Bold, 13.5pt
66
        'h4' => [
67
            'font' => [
68
                'bold' => true,
69
                'size' => 12,
70
            ],
71
        ], //    Bold, 12pt
72
        'h5' => [
73
            'font' => [
74
                'bold' => true,
75
                'size' => 10,
76
            ],
77
        ], //    Bold, 10pt
78
        'h6' => [
79
            'font' => [
80
                'bold' => true,
81
                'size' => 7.5,
82
            ],
83
        ], //    Bold, 7.5pt
84
        'a' => [
85
            'font' => [
86
                'underline' => true,
87
                'color' => [
88
                    'argb' => Color::COLOR_BLUE,
89
                ],
90
            ],
91
        ], //    Blue underlined
92
        'hr' => [
93
            'borders' => [
94
                'bottom' => [
95
                    'borderStyle' => Border::BORDER_THIN,
96
                    'color' => [
97
                        Color::COLOR_BLACK,
98
                    ],
99
                ],
100
            ],
101
        ], //    Bottom border
102
        'strong' => [
103
            'font' => [
104
                'bold' => true,
105
            ],
106
        ], //    Bold
107
        'b' => [
108
            'font' => [
109
                'bold' => true,
110
            ],
111
        ], //    Bold
112
        'i' => [
113
            'font' => [
114
                'italic' => true,
115
            ],
116
        ], //    Italic
117
        'em' => [
118
            'font' => [
119
                'italic' => true,
120
            ],
121
        ], //    Italic
122
    ];
123
124
    protected $rowspan = [];
125
126
    /**
127
     * Create a new HTML Reader instance.
128
     */
129 32
    public function __construct()
130
    {
131 32
        parent::__construct();
132 32
        $this->securityScanner = XmlScanner::getInstance($this);
133 32
    }
134
135
    /**
136
     * Validate that the current file is an HTML file.
137
     *
138
     * @param string $pFilename
139
     *
140
     * @return bool
141
     */
142 28
    public function canRead($pFilename)
143
    {
144
        // Check if file exists
145
        try {
146 28
            $this->openFile($pFilename);
147
        } catch (Exception $e) {
148
            return false;
149
        }
150
151 28
        $beginning = $this->readBeginning();
152 28
        $startWithTag = self::startsWithTag($beginning);
153 28
        $containsTags = self::containsTags($beginning);
154 28
        $endsWithTag = self::endsWithTag($this->readEnding());
155
156 28
        fclose($this->fileHandle);
1 ignored issue
show
Bug introduced by
It seems like $this->fileHandle 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

156
        fclose(/** @scrutinizer ignore-type */ $this->fileHandle);
Loading history...
157
158 28
        return $startWithTag && $containsTags && $endsWithTag;
159
    }
160
161 28
    private function readBeginning()
162
    {
163 28
        fseek($this->fileHandle, 0);
164
165 28
        return fread($this->fileHandle, self::TEST_SAMPLE_SIZE);
166
    }
167
168 28
    private function readEnding()
169
    {
170 28
        $meta = stream_get_meta_data($this->fileHandle);
171 28
        $filename = $meta['uri'];
172
173 28
        $size = filesize($filename);
174 28
        if ($size === 0) {
175 1
            return '';
176
        }
177
178 27
        $blockSize = self::TEST_SAMPLE_SIZE;
179 27
        if ($size < $blockSize) {
180 13
            $blockSize = $size;
181
        }
182
183 27
        fseek($this->fileHandle, $size - $blockSize);
184
185 27
        return fread($this->fileHandle, $blockSize);
186
    }
187
188 28
    private static function startsWithTag($data)
189
    {
190 28
        return '<' === substr(trim($data), 0, 1);
191
    }
192
193 28
    private static function endsWithTag($data)
194
    {
195 28
        return '>' === substr(trim($data), -1, 1);
196
    }
197
198 28
    private static function containsTags($data)
199
    {
200 28
        return strlen($data) !== strlen(strip_tags($data));
201
    }
202
203
    /**
204
     * Loads Spreadsheet from file.
205
     *
206
     * @param string $pFilename
207
     *
208
     * @throws Exception
209
     *
210
     * @return Spreadsheet
211
     */
212 21
    public function load($pFilename)
213
    {
214
        // Create new Spreadsheet
215 21
        $spreadsheet = new Spreadsheet();
216
217
        // Load into this instance
218 21
        return $this->loadIntoExisting($pFilename, $spreadsheet);
219
    }
220
221
    /**
222
     * Set input encoding.
223
     *
224
     * @param string $pValue Input encoding, eg: 'ANSI'
225
     *
226
     * @return Html
227
     */
228 2
    public function setInputEncoding($pValue)
229
    {
230 2
        $this->inputEncoding = $pValue;
231
232 2
        return $this;
233
    }
234
235
    /**
236
     * Get input encoding.
237
     *
238
     * @return string
239
     */
240
    public function getInputEncoding()
241
    {
242
        return $this->inputEncoding;
243
    }
244
245
    //    Data Array used for testing only, should write to Spreadsheet object on completion of tests
246
    protected $dataArray = [];
247
248
    protected $tableLevel = 0;
249
250
    protected $nestedColumn = ['A'];
251
252 23
    protected function setTableStartColumn($column)
253
    {
254 23
        if ($this->tableLevel == 0) {
255 23
            $column = 'A';
256
        }
257 23
        ++$this->tableLevel;
258 23
        $this->nestedColumn[$this->tableLevel] = $column;
259
260 23
        return $this->nestedColumn[$this->tableLevel];
261
    }
262
263 23
    protected function getTableStartColumn()
264
    {
265 23
        return $this->nestedColumn[$this->tableLevel];
266
    }
267
268 23
    protected function releaseTableStartColumn()
269
    {
270 23
        --$this->tableLevel;
271
272 23
        return array_pop($this->nestedColumn);
273
    }
274
275 23
    protected function flushCell(Worksheet $sheet, $column, $row, &$cellContent)
276
    {
277 23
        if (is_string($cellContent)) {
278
            //    Simple String content
279 23
            if (trim($cellContent) > '') {
280
                //    Only actually write it if there's content in the string
281
                //    Write to worksheet to be done here...
282
                //    ... we return the cell so we can mess about with styles more easily
283 22
                $sheet->setCellValue($column . $row, $cellContent);
284 23
                $this->dataArray[$row][$column] = $cellContent;
285
            }
286
        } else {
287
            //    We have a Rich Text run
288
            //    TODO
289
            $this->dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
290
        }
291 23
        $cellContent = (string) '';
292 23
    }
293
294
    /**
295
     * @param DOMNode $element
296
     * @param Worksheet $sheet
297
     * @param int $row
298
     * @param string $column
299
     * @param string $cellContent
300
     */
301 23
    protected function processDomElement(DOMNode $element, Worksheet $sheet, &$row, &$column, &$cellContent)
302
    {
303 23
        foreach ($element->childNodes as $child) {
304 23
            if ($child instanceof DOMText) {
305 23
                $domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
306 23
                if (is_string($cellContent)) {
307
                    //    simply append the text if the cell content is a plain text string
308 23
                    $cellContent .= $domText;
309
                }
310
                //    but if we have a rich text run instead, we need to append it correctly
311
                    //    TODO
312 23
            } elseif ($child instanceof DOMElement) {
313 23
                $attributeArray = [];
314 23
                foreach ($child->attributes as $attribute) {
315 20
                    $attributeArray[$attribute->name] = $attribute->value;
316
                }
317
318 23
                switch ($child->nodeName) {
319 23
                    case 'meta':
320 10
                        foreach ($attributeArray as $attributeName => $attributeValue) {
321
                            // Extract character set, so we can convert to UTF-8 if required
322 10
                            if ($attributeName === 'charset') {
323 2
                                $this->setInputEncoding($attributeValue);
324
                            }
325
                        }
326 10
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
327
328 10
                        break;
329 23
                    case 'title':
330 10
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
331 10
                        $sheet->setTitle($cellContent, true, false);
332 10
                        $cellContent = '';
333
334 10
                        break;
335 23
                    case 'span':
336 23
                    case 'div':
337 23
                    case 'font':
338 23
                    case 'i':
339 23
                    case 'em':
340 23
                    case 'strong':
341 23
                    case 'b':
342 6
                        if (isset($attributeArray['class']) && $attributeArray['class'] === 'comment') {
343 6
                            $sheet->getComment($column . $row)
344 6
                                ->getText()
345 6
                                ->createTextRun($child->textContent);
346
347 6
                            break;
348
                        }
349
350
                        if ($cellContent > '') {
351
                            $cellContent .= ' ';
352
                        }
353
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
354
                        if ($cellContent > '') {
355
                            $cellContent .= ' ';
356
                        }
357
358
                        if (isset($this->formats[$child->nodeName])) {
359
                            $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
360
                        }
361
362
                        break;
363 23
                    case 'hr':
364
                        $this->flushCell($sheet, $column, $row, $cellContent);
365
                        ++$row;
366
                        if (isset($this->formats[$child->nodeName])) {
367
                            $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
368
                        } else {
369
                            $cellContent = '----------';
370
                            $this->flushCell($sheet, $column, $row, $cellContent);
371
                        }
372
                        ++$row;
373
                        // Add a break after a horizontal rule, simply by allowing the code to dropthru
374
                        // no break
375 23
                    case 'br':
376 3
                        if ($this->tableLevel > 0) {
377
                            //    If we're inside a table, replace with a \n and set the cell to wrap
378 3
                            $cellContent .= "\n";
379 3
                            $sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
380
                        } else {
381
                            //    Otherwise flush our existing content and move the row cursor on
382
                            $this->flushCell($sheet, $column, $row, $cellContent);
383
                            ++$row;
384
                        }
385
386 3
                        break;
387 23
                    case 'a':
388 6
                        foreach ($attributeArray as $attributeName => $attributeValue) {
389
                            switch ($attributeName) {
390 6
                                case 'href':
391
                                    $sheet->getCell($column . $row)->getHyperlink()->setUrl($attributeValue);
392
                                    if (isset($this->formats[$child->nodeName])) {
393
                                        $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
394
                                    }
395
396
                                    break;
397 6
                                case 'class':
398 6
                                    if ($attributeValue === 'comment-indicator') {
399 6
                                        break; // Ignore - it's just a red square.
400
                                    }
401
                            }
402
                        }
403 6
                        $cellContent .= ' ';
404 6
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
405
406 6
                        break;
407 23
                    case 'h1':
408 23
                    case 'h2':
409 23
                    case 'h3':
410 23
                    case 'h4':
411 23
                    case 'h5':
412 23
                    case 'h6':
413 23
                    case 'ol':
414 23
                    case 'ul':
415 23
                    case 'p':
416
                        if ($this->tableLevel > 0) {
417
                            //    If we're inside a table, replace with a \n
418
                            $cellContent .= "\n";
419
                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
420
                        } else {
421
                            if ($cellContent > '') {
422
                                $this->flushCell($sheet, $column, $row, $cellContent);
423
                                ++$row;
424
                            }
425
                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
426
                            $this->flushCell($sheet, $column, $row, $cellContent);
427
428
                            if (isset($this->formats[$child->nodeName])) {
429
                                $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
430
                            }
431
432
                            ++$row;
433
                            $column = 'A';
434
                        }
435
436
                        break;
437 23
                    case 'li':
438
                        if ($this->tableLevel > 0) {
439
                            //    If we're inside a table, replace with a \n
440
                            $cellContent .= "\n";
441
                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
442
                        } else {
443
                            if ($cellContent > '') {
444
                                $this->flushCell($sheet, $column, $row, $cellContent);
445
                            }
446
                            ++$row;
447
                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
448
                            $this->flushCell($sheet, $column, $row, $cellContent);
449
                            $column = 'A';
450
                        }
451
452
                        break;
453 23
                    case 'img':
454 1
                        $this->insertImage($sheet, $column, $row, $attributeArray);
455
456 1
                        break;
457 23
                    case 'table':
458 23
                        $this->flushCell($sheet, $column, $row, $cellContent);
459 23
                        $column = $this->setTableStartColumn($column);
460 23
                        if ($this->tableLevel > 1) {
461
                            --$row;
462
                        }
463 23
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
464 23
                        $column = $this->releaseTableStartColumn();
465 23
                        if ($this->tableLevel > 1) {
466
                            ++$column;
467
                        } else {
468 23
                            ++$row;
469
                        }
470
471 23
                        break;
472 23
                    case 'thead':
473 23
                    case 'tbody':
474 9
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
475
476 9
                        break;
477 23
                    case 'tr':
478 23
                        $column = $this->getTableStartColumn();
479 23
                        $cellContent = '';
480 23
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
481
482 23
                        if (isset($attributeArray['height'])) {
483
                            $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
484
                        }
485
486 23
                        ++$row;
487
488 23
                        break;
489 23
                    case 'th':
490 23
                    case 'td':
491 23
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
492
493 23
                        while (isset($this->rowspan[$column . $row])) {
494 1
                            ++$column;
495
                        }
496
497
                        // apply inline style
498 23
                        $this->applyInlineStyle($sheet, $row, $column, $attributeArray);
499
500 23
                        $this->flushCell($sheet, $column, $row, $cellContent);
501
502 23
                        if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
503
                            //create merging rowspan and colspan
504
                            $columnTo = $column;
505
                            for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
506
                                ++$columnTo;
507
                            }
508
                            $range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1);
509
                            foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
510
                                $this->rowspan[$value] = true;
511
                            }
512
                            $sheet->mergeCells($range);
513
                            $column = $columnTo;
514 23
                        } elseif (isset($attributeArray['rowspan'])) {
515
                            //create merging rowspan
516 1
                            $range = $column . $row . ':' . $column . ($row + (int) $attributeArray['rowspan'] - 1);
517 1
                            foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
518 1
                                $this->rowspan[$value] = true;
519
                            }
520 1
                            $sheet->mergeCells($range);
521 23
                        } elseif (isset($attributeArray['colspan'])) {
522
                            //create merging colspan
523 2
                            $columnTo = $column;
524 2
                            for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
525 2
                                ++$columnTo;
526
                            }
527 2
                            $sheet->mergeCells($column . $row . ':' . $columnTo . $row);
528 2
                            $column = $columnTo;
529 23
                        } elseif (isset($attributeArray['bgcolor'])) {
530
                            $sheet->getStyle($column . $row)->applyFromArray(
531
                                [
532
                                    'fill' => [
533
                                        'fillType' => Fill::FILL_SOLID,
534
                                        'color' => ['rgb' => $attributeArray['bgcolor']],
535
                                    ],
536
                                ]
537
                            );
538
                        }
539
540 23
                        if (isset($attributeArray['width'])) {
541 1
                            $sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
542
                        }
543
544 23
                        if (isset($attributeArray['height'])) {
545 1
                            $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
546
                        }
547
548 23
                        if (isset($attributeArray['align'])) {
549 1
                            $sheet->getStyle($column . $row)->getAlignment()->setHorizontal($attributeArray['align']);
550
                        }
551
552 23
                        if (isset($attributeArray['valign'])) {
553 1
                            $sheet->getStyle($column . $row)->getAlignment()->setVertical($attributeArray['valign']);
554
                        }
555
556 23
                        if (isset($attributeArray['data-format'])) {
557 1
                            $sheet->getStyle($column . $row)->getNumberFormat()->setFormatCode($attributeArray['data-format']);
558
                        }
559
560 23
                        ++$column;
561
562 23
                        break;
563 23
                    case 'body':
564 23
                        $row = 1;
565 23
                        $column = 'A';
566 23
                        $cellContent = '';
567 23
                        $this->tableLevel = 0;
568 23
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
569
570 23
                        break;
571
                    default:
572 23
                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
573
                }
574
            }
575
        }
576 23
    }
577
578
    /**
579
     * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
580
     *
581
     * @param string $pFilename
582
     * @param Spreadsheet $spreadsheet
583
     *
584
     * @throws Exception
585
     *
586
     * @return Spreadsheet
587
     */
588 21
    public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
589
    {
590
        // Validate
591 21
        if (!$this->canRead($pFilename)) {
592
            throw new Exception($pFilename . ' is an Invalid HTML file.');
593
        }
594
595
        // Create a new DOM object
596 21
        $dom = new DOMDocument();
597
        // Reload the HTML file into the DOM object
598 21
        $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
599 21
        if ($loaded === false) {
600
            throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document');
601
        }
602
603 21
        return $this->loadDocument($dom, $spreadsheet);
604
    }
605
606
    /**
607
     * Spreadsheet from content.
608
     *
609
     * @param string $content
610
     * @param null|Spreadsheet $spreadsheet
611
     *
612
     * @return Spreadsheet
613
     */
614 2
    public function loadFromString($content, ?Spreadsheet $spreadsheet = null): Spreadsheet
615
    {
616
        //    Create a new DOM object
617 2
        $dom = new DOMDocument();
618
        //    Reload the HTML file into the DOM object
619 2
        $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scan($content), 'HTML-ENTITIES', 'UTF-8'));
620 2
        if ($loaded === false) {
621
            throw new Exception('Failed to load content as a DOM Document');
622
        }
623
624 2
        return $this->loadDocument($dom, $spreadsheet ?? new Spreadsheet());
625
    }
626
627
    /**
628
     * Loads PhpSpreadsheet from DOMDocument into PhpSpreadsheet instance.
629
     *
630
     * @param DOMDocument $document
631
     * @param Spreadsheet $spreadsheet
632
     *
633
     * @throws \PhpOffice\PhpSpreadsheet\Exception
634
     *
635
     * @return Spreadsheet
636
     */
637 23
    private function loadDocument(DOMDocument $document, Spreadsheet $spreadsheet): Spreadsheet
638
    {
639 23
        while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
640 1
            $spreadsheet->createSheet();
641
        }
642 23
        $spreadsheet->setActiveSheetIndex($this->sheetIndex);
643
644
        // Discard white space
645 23
        $document->preserveWhiteSpace = false;
646
647 23
        $row = 0;
648 23
        $column = 'A';
649 23
        $content = '';
650 23
        $this->rowspan = [];
651 23
        $this->processDomElement($document, $spreadsheet->getActiveSheet(), $row, $column, $content);
652
653
        // Return
654 23
        return $spreadsheet;
655
    }
656
657
    /**
658
     * Get sheet index.
659
     *
660
     * @return int
661
     */
662
    public function getSheetIndex()
663
    {
664
        return $this->sheetIndex;
665
    }
666
667
    /**
668
     * Set sheet index.
669
     *
670
     * @param int $pValue Sheet index
671
     *
672
     * @return HTML
673
     */
674 1
    public function setSheetIndex($pValue)
675
    {
676 1
        $this->sheetIndex = $pValue;
677
678 1
        return $this;
679
    }
680
681
    /**
682
     * Apply inline css inline style.
683
     *
684
     * NOTES :
685
     * Currently only intended for td & th element,
686
     * and only takes 'background-color' and 'color'; property with HEX color
687
     *
688
     * TODO :
689
     * - Implement to other propertie, such as border
690
     *
691
     * @param Worksheet $sheet
692
     * @param int $row
693
     * @param string $column
694
     * @param array $attributeArray
695
     */
696 23
    private function applyInlineStyle(&$sheet, $row, $column, $attributeArray)
697
    {
698 23
        if (!isset($attributeArray['style'])) {
699 20
            return;
700
        }
701
702 9
        $cellStyle = $sheet->getStyle($column . $row);
703
704
        // add color styles (background & text) from dom element,currently support : td & th, using ONLY inline css style with RGB color
705 9
        $styles = explode(';', $attributeArray['style']);
706 9
        foreach ($styles as $st) {
707 9
            $value = explode(':', $st);
708 9
            $styleName = isset($value[0]) ? trim($value[0]) : null;
709 9
            $styleValue = isset($value[1]) ? trim($value[1]) : null;
710
711 9
            if (!$styleName) {
712 6
                continue;
713
            }
714
715
            switch ($styleName) {
716 9
                case 'background':
717 9
                case 'background-color':
718 3
                    $styleColor = $this->getStyleColor($styleValue);
719
720 3
                    if (!$styleColor) {
721
                        continue 2;
722
                    }
723
724 3
                    $cellStyle->applyFromArray(['fill' => ['fillType' => Fill::FILL_SOLID, 'color' => ['rgb' => $styleColor]]]);
725
726 3
                    break;
727 9
                case 'color':
728 3
                    $styleColor = $this->getStyleColor($styleValue);
729
730 3
                    if (!$styleColor) {
731
                        continue 2;
732
                    }
733
734 3
                    $cellStyle->applyFromArray(['font' => ['color' => ['rgb' => $styleColor]]]);
735
736 3
                    break;
737
738 6
                case 'border':
739 1
                    $this->setBorderStyle($cellStyle, $styleValue, 'allBorders');
740
741 1
                    break;
742
743 6
                case 'border-top':
744 1
                    $this->setBorderStyle($cellStyle, $styleValue, 'top');
745
746 1
                    break;
747
748 6
                case 'border-bottom':
749 1
                    $this->setBorderStyle($cellStyle, $styleValue, 'bottom');
750
751 1
                    break;
752
753 6
                case 'border-left':
754 1
                    $this->setBorderStyle($cellStyle, $styleValue, 'left');
755
756 1
                    break;
757
758 6
                case 'border-right':
759 1
                    $this->setBorderStyle($cellStyle, $styleValue, 'right');
760
761 1
                    break;
762
763 5
                case 'font-size':
764 1
                    $cellStyle->getFont()->setSize(
765 1
                        (float) $styleValue
766
                    );
767
768 1
                    break;
769
770 5
                case 'font-weight':
771 1
                    if ($styleValue === 'bold' || $styleValue >= 500) {
772 1
                        $cellStyle->getFont()->setBold(true);
773
                    }
774
775 1
                    break;
776
777 5
                case 'font-style':
778 1
                    if ($styleValue === 'italic') {
779 1
                        $cellStyle->getFont()->setItalic(true);
780
                    }
781
782 1
                    break;
783
784 5
                case 'font-family':
785 1
                    $cellStyle->getFont()->setName(str_replace('\'', '', $styleValue));
786
787 1
                    break;
788
789 5
                case 'text-decoration':
790
                    switch ($styleValue) {
791 1
                        case 'underline':
792 1
                            $cellStyle->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
793
794 1
                            break;
795 1
                        case 'line-through':
796 1
                            $cellStyle->getFont()->setStrikethrough(true);
797
798 1
                            break;
799
                    }
800
801 1
                    break;
802
803 4
                case 'text-align':
804 1
                    $cellStyle->getAlignment()->setHorizontal($styleValue);
805
806 1
                    break;
807
808 4
                case 'vertical-align':
809 2
                    $cellStyle->getAlignment()->setVertical($styleValue);
810
811 2
                    break;
812
813 4
                case 'width':
814 1
                    $sheet->getColumnDimension($column)->setWidth(
815 1
                        str_replace('px', '', $styleValue)
816
                    );
817
818 1
                    break;
819
820 3
                case 'height':
821 1
                    $sheet->getRowDimension($row)->setRowHeight(
822 1
                        str_replace('px', '', $styleValue)
823
                    );
824
825 1
                    break;
826
827 2
                case 'word-wrap':
828 1
                    $cellStyle->getAlignment()->setWrapText(
829 1
                        $styleValue === 'break-word'
830
                    );
831
832 1
                    break;
833
834 2
                case 'text-indent':
835 2
                    $cellStyle->getAlignment()->setIndent(
836 2
                        (int) str_replace(['px'], '', $styleValue)
837
                    );
838
839 2
                    break;
840
            }
841
        }
842 9
    }
843
844
    /**
845
     * Check if has #, so we can get clean hex.
846
     *
847
     * @param $value
848
     *
849
     * @return null|string
850
     */
851 4
    public function getStyleColor($value)
852
    {
853 4
        if (strpos($value, '#') === 0) {
854 4
            return substr($value, 1);
855
        }
856
857
        return null;
858
    }
859
860
    /**
861
     * @param Worksheet $sheet
862
     * @param string    $column
863
     * @param int       $row
864
     * @param array     $attributes
865
     *
866
     * @throws \PhpOffice\PhpSpreadsheet\Exception
867
     */
868 1
    private function insertImage(Worksheet $sheet, $column, $row, array $attributes)
869
    {
870 1
        if (!isset($attributes['src'])) {
871
            return;
872
        }
873
874 1
        $src = urldecode($attributes['src']);
875 1
        $width = isset($attributes['width']) ? (float) $attributes['width'] : null;
876 1
        $height = isset($attributes['height']) ? (float) $attributes['height'] : null;
877 1
        $name = isset($attributes['alt']) ? (float) $attributes['alt'] : null;
878
879 1
        $drawing = new Drawing();
880 1
        $drawing->setPath($src);
881 1
        $drawing->setWorksheet($sheet);
882 1
        $drawing->setCoordinates($column . $row);
883 1
        $drawing->setOffsetX(0);
884 1
        $drawing->setOffsetY(10);
885 1
        $drawing->setResizeProportional(true);
886
887 1
        if ($name) {
888
            $drawing->setName($name);
889
        }
890
891 1
        if ($width) {
892
            $drawing->setWidth((int) $width);
893
        }
894
895 1
        if ($height) {
896
            $drawing->setHeight((int) $height);
897
        }
898
899 1
        $sheet->getColumnDimension($column)->setWidth(
900 1
            $drawing->getWidth() / 6
901
        );
902
903 1
        $sheet->getRowDimension($row)->setRowHeight(
904 1
            $drawing->getHeight() * 0.9
905
        );
906 1
    }
907
908
    /**
909
     * Map html border style to PhpSpreadsheet border style.
910
     *
911
     * @param  string $style
912
     *
913
     * @return null|string
914
     */
915 1
    public function getBorderStyle($style)
916
    {
917
        switch ($style) {
918 1
            case 'solid':
919 1
                return Border::BORDER_THIN;
920
            case 'dashed':
921
                return Border::BORDER_DASHED;
922
            case 'dotted':
923
                return Border::BORDER_DOTTED;
924
            case 'medium':
925
                return Border::BORDER_MEDIUM;
926
            case 'thick':
927
                return Border::BORDER_THICK;
928
            case 'none':
929
                return Border::BORDER_NONE;
930
            case 'dash-dot':
931
                return Border::BORDER_DASHDOT;
932
            case 'dash-dot-dot':
933
                return Border::BORDER_DASHDOTDOT;
934
            case 'double':
935
                return Border::BORDER_DOUBLE;
936
            case 'hair':
937
                return Border::BORDER_HAIR;
938
            case 'medium-dash-dot':
939
                return Border::BORDER_MEDIUMDASHDOT;
940
            case 'medium-dash-dot-dot':
941
                return Border::BORDER_MEDIUMDASHDOTDOT;
942
            case 'medium-dashed':
943
                return Border::BORDER_MEDIUMDASHED;
944
            case 'slant-dash-dot':
945
                return Border::BORDER_SLANTDASHDOT;
946
        }
947
948
        return null;
949
    }
950
951
    /**
952
     * @param Style  $cellStyle
953
     * @param string $styleValue
954
     * @param string $type
955
     */
956 1
    private function setBorderStyle(Style $cellStyle, $styleValue, $type)
957
    {
958 1
        [, $borderStyle, $color] = explode(' ', $styleValue);
959
960 1
        $cellStyle->applyFromArray([
961
            'borders' => [
962
                $type => [
963 1
                    'borderStyle' => $this->getBorderStyle($borderStyle),
964 1
                    'color' => ['rgb' => $this->getStyleColor($color)],
965
                ],
966
            ],
967
        ]);
968 1
    }
969
}
970