Completed
Branch development (b1b115)
by Johannes
10:28
created

Html::_processDomElement()   F

Complexity

Conditions 66
Paths 6406

Size

Total Lines 380

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 380
rs 0
cc 66
nc 6406
nop 6

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 namespace Maatwebsite\Excel\Readers;
2
3
use PHPExcel;
4
use DOMNode;
5
use DOMText;
6
use DOMElement;
7
use DOMDocument;
8
use PHPExcel_Cell;
9
use PHPExcel_Settings;
10
use PHPExcel_Reader_HTML;
11
use PHPExcel_Style_Color;
12
use PHPExcel_Style_Fill;
13
use PHPExcel_Style_Font;
14
use PHPExcel_Style_Border;
15
use PHPExcel_Worksheet_Drawing;
16
use PHPExcel_Style_Alignment;
17
use Maatwebsite\Excel\Parsers\CssParser;
18
use Maatwebsite\Excel\Classes\LaravelExcelWorksheet;
19
20
/**
21
 *
22
 * LaravelExcel HTML reader
23
 *
24
 * @category   Laravel Excel
25
 * @version    2.0.0
26
 * @package    maatwebsite/excel
27
 * @copyright  Copyright (c) 2013 - 2014 Maatwebsite (http://www.maatwebsite.nl)
28
 * @copyright  Original Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
29
 * @author     Maatwebsite <[email protected]>
30
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
31
 */
32
class Html extends PHPExcel_Reader_HTML {
33
34
    /**
35
     * Style per range
36
     * @var array
37
     */
38
    protected $styles = [];
39
40
    protected $_dataArray = [];
41
42
    protected $_nestedColumn = ['A'];
43
44
    /**
45
     * @var int
46
     */
47
    protected $_tableLevel = 0;
48
49
    /**
50
     * Input encoding
51
     * @var string
52
     */
53
    protected $_inputEncoding = 'ANSI';
54
55
    /**
56
     * Sheet index to read
57
     * @var int
58
     */
59
    protected $_sheetIndex = 0;
60
61
    /**
62
     * HTML tags formatting settings
63
     * @var array
64
     */
65
    protected $_formats = [];
66
67
    /**
68
     * The current colspan
69
     * @var integer
70
     */
71
    protected $spanWidth = 1;
72
73
    /**
74
     * The current rowspan
75
     * @var integer
76
     */
77
    protected $spanHeight = 1;
78
79
    /**
80
     * @var
81
     */
82
    private $cssParser;
83
84
    /**
85
     * @param CssParser $cssParser
86
     */
87
    public function __construct(CssParser $cssParser)
88
    {
89
        $this->cssParser = $cssParser;
90
        parent::__construct();
91
    }
92
93
    /**
94
     * Loads PHPExcel from file
95
     *
96
     * @param   string                                 $pFilename
97
     * @param   boolean                                $isString
98
     * @param bool|LaravelExcelWorksheet|null|PHPExcel $obj
99
     * @throws \PHPExcel_Reader_Exception
100
     * @return  LaravelExcelWorksheet
101
     */
102
    public function load($pFilename, $isString = false, $obj = false)
103
    {
104
        // Set the default style formats
105
        $this->setStyleFormats();
106
107
        if ( $obj instanceof PHPExcel )
108
        {
109
            // Load into this instance
110
            return $this->loadIntoExisting($pFilename, $obj, $isString);
111
        }
112
        elseif ( $obj instanceof LaravelExcelWorksheet )
113
        {
114
            // Load into this instance
115
            return $this->loadIntoExistingSheet($pFilename, $obj, $isString);
116
        }
117
118
        $objPHPExcel = $obj ? $obj : new PHPExcel();
119
120
        return $this->loadIntoExisting($pFilename, $objPHPExcel, $isString);
121
    }
122
123
    /**
124
     * Set the style formats from our config file
125
     * @return  array
126
     */
127
    protected function setStyleFormats()
128
    {
129
        $this->_formats = config('excel.views.styles', []);
130
    }
131
132
    /**
133
     * Loads HTML from file into sheet instance
134
     *
135
     * @param   string                $pFilename
136
     * @param   LaravelExcelWorksheet $sheet
137
     * @param   boolean               $isString
138
     * @return  LaravelExcelWorksheet
139
     * @throws  PHPExcel_Reader_Exception
140
     */
141
    public function loadIntoExistingSheet($pFilename, LaravelExcelWorksheet $sheet, $isString = false)
142
    {
143
        $isHtmlFile = false;
144
145
        // Check if it's a string or file
146
        if ( !$isString )
147
        {
148
            // Double check if it's a file
149
            if ( is_file($pFilename) )
150
            {
151
                $isHtmlFile = true;
152
                $this->_openFile($pFilename);
153
154
                if ( !$this->_isValidFormat() )
155
                {
156
                    fclose($this->_fileHandle);
157
                    throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid HTML file.");
158
                }
159
160
                fclose($this->_fileHandle);
161
            }
162
        }
163
164
        //  Create a new DOM object
165
        $dom = new DOMDocument;
166
167
        // Check if we need to load the file or the HTML
168
        if ( $isHtmlFile )
169
        {
170
            // Load HTML from file
171
            if ( (version_compare(PHP_VERSION, '5.4.0') >= 0) && defined(LIBXML_DTDLOAD) )
172
            {
173
                $loaded = @$dom->loadHTMLFile($pFilename, PHPExcel_Settings::getLibXmlLoaderOptions());
174
            }
175
            else
176
            {
177
                $loaded = @$dom->loadHTMLFile($pFilename);
178
            }
179
        }
180
        else
181
        {
182
            // Load HTML from string
183
            @$dom->loadHTML(mb_convert_encoding($pFilename, 'HTML-ENTITIES', 'UTF-8'));
184
185
            // Let the css parser find all stylesheets
186
            $this->cssParser->findStyleSheets($dom);
187
188
            // Transform the css files to inline css and replace the html
189
            $html = $this->cssParser->transformCssToInlineStyles($pFilename);
190
191
            // Re-init dom doc
192
            $dom = new DOMDocument;
193
194
            // Load again with css included
195
            $loaded = @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
196
        }
197
198
        if ( $loaded === false )
199
        {
200
            throw new PHPExcel_Reader_Exception('Failed to load ' . $pFilename . ' as a DOM Document');
201
        }
202
203
        //  Discard white space
204
        $dom->preserveWhiteSpace = true;
205
206
        $row = 0;
207
        $column = 'A';
208
        $content = '';
209
        $this->_processDomElement($dom, $sheet, $row, $column, $content);
210
211
        if ( !$sheet->hasFixedSizeColumns() )
212
            $this->autosizeColumn($sheet);
213
214
        return $sheet;
215
    }
216
217
    /**
218
     * Autosize column for document
219
     * @param  LaravelExcelWorksheet $sheet
220
     * @return LaravelExcelWorksheet
221
     */
222
    public function autosizeColumn($sheet)
223
    {
224
        if ( $columns = $sheet->getAutosize() )
225
        {
226
            if ( is_array($columns) )
227
            {
228
                $sheet->setAutoSize($columns);
229
            }
230
            else
231
            {
232
                $toCol = $sheet->getHighestColumn();
233
                $toCol++;
234
                for ($i = 'A'; $i !== $toCol; $i++)
235
                {
236
                    $sheet->getColumnDimension($i)->setAutoSize(true);
237
                }
238
239
                $sheet->calculateColumnWidths();
240
            }
241
        }
242
243
        return $sheet;
244
    }
245
246
    /**
247
     * Process the dom element
248
     * @param  DOMNode               $element
249
     * @param  LaravelExcelWorksheet $sheet
250
     * @param  string                $row
251
     * @param  integer               $column
252
     * @param  string                $cellContent
253
     * @return void
254
     */
255
    protected function _processDomElement(DOMNode $element, $sheet, &$row, &$column, &$cellContent, $format = null)
256
    {
257
        foreach ($element->childNodes as $child)
258
        {
259
            // If is text
260
            if ( $child instanceof DOMText )
261
            {
262
                // get the dom text
263
                $domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
264
265
                //  simply append the text if the cell content is a plain text string
266
                if ( is_string($cellContent) )
267
                {
268
                    $cellContent .= $domText;
269
                }
270
            }
271
272
            // If is a dom element
273
            elseif ( $child instanceof DOMElement )
274
            {
275
                $attributeArray = [];
276
277
                // Set row (=parent) styles
278
                if ( isset($this->styles[$row]) )
279
                    $this->parseInlineStyles($sheet, $column, $row, $this->styles[$row]);
280
281
                // Loop through the child's attributes
282
                foreach ($child->attributes as $attribute)
283
                {
284
                    // Add the attribute to the array
285
                    $attributeArray[$attribute->name] = $attribute->value;
286
287
                    // Attribute names
288
                    switch ($attribute->name)
289
                    {
290
                        // Colspan
291
                        case 'width':
292
                            $this->parseWidth($sheet, $column, $row, $attribute->value);
293
                            break;
294
295
                        case 'height':
296
                            $this->parseHeight($sheet, $column, $row, $attribute->value);
297
                            break;
298
299
                        // Colspan
300
                        case 'colspan':
301
                            $this->parseColSpan($sheet, $column, $row, $attribute->value, $child->attributes);
302
                            break;
303
304
                        // Rowspan
305
                        case 'rowspan':
306
                            $this->parseRowSpan($sheet, $column, $row, $attribute->value, $child->attributes);
307
                            break;
308
309
                        // Alignment
310
                        case 'align':
311
                            $this->parseAlign($sheet, $column, $row, $attribute->value);
312
                            break;
313
314
                        // Vertical alignment
315
                        case 'valign':
316
                            $this->parseValign($sheet, $column, $row, $attribute->value);
317
                            break;
318
319
                        // Cell format
320
                        case 'data-format':
321
                            $this->parseDataFormat($sheet, $column, $row, $attribute->value);
322
                            break;
323
324
                        // Inline css styles
325
                        case 'style':
326
                            $this->parseInlineStyles($sheet, $column, $row, $attribute->value);
327
328
                            if ( $child->nodeName == 'tr' )
329
                                $this->styles[$row] = $attribute->value;
330
                            break;
331
                    }
332
                }
333
334
                // nodeName
335
                switch ($child->nodeName)
336
                {
337
338
                    // Meta tags
339
                    case 'meta' :
340
341
                        // Loop through the attributes
342
                        foreach ($attributeArray as $attributeName => $attributeValue)
343
                        {
344
345
                            // Switch the names
346
                            switch ($attributeName)
347
                            {
348
                                // Set input encoding
349
                                case 'charset':
350
                                    $_inputEncoding = $attributeValue;
351
                                    break;
352
                            }
353
                        }
354
355
                        // Continue processing dom element
356
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
357
358
                        break;
359
360
                    // Set sheet title
361
                    case 'title' :
362
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
363
                        $sheet->setTitle($cellContent);
364
                        $cellContent = '';
365
                        break;
366
367
                    // Text
368
                    case 'span'  :
369
                    case 'div'   :
370
                    case 'font'  :
371
                    case 'i'     :
372
                    case 'em'    :
373
                    case 'strong':
374
                    case 'b'     :
375
376
                        // Add space after empty cells
377
                        if ( $cellContent > '' )
378
                            $cellContent .= ' ';
379
380
                        // Continue processing
381
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
382
383
                        // Add space after empty cells
384
                        if ( $cellContent > '' )
385
                            $cellContent .= ' ';
386
387
                        // Set the styling
388
                        if ( isset($this->_formats[$child->nodeName]) )
389
                        {
390
                            $sheet->getStyle($column . $row)
391
                                  ->applyFromArray($this->_formats[$child->nodeName]);
392
                        }
393
394
                        break;
395
396
                    // Horizontal rules
397
                    case 'hr' :
398
399
                        // Flush the cell
400
                        $this->flushCell($sheet, $column, $row, $cellContent);
401
402
                        // count
403
                        ++$row;
404
405
                        // Set the styling
406
                        if ( isset($this->_formats[$child->nodeName]) )
407
                        {
408
                            $sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
409
                        }
410
                        // If not, enter cell content
411
                        else
412
                        {
413
                            $cellContent = '----------';
414
                            $this->flushCell($sheet, $column, $row, $cellContent);
415
                        }
416
417
                        ++$row;
418
419
                    // Linebreaks
420
                    case 'br' :
421
422
                        // Add linebreak
423
                        if ( $this->_tableLevel > 0 )
424
                        {
425
                            $cellContent .= "\n";
426
                        }
427
428
                        //  Otherwise flush our existing content and move the row cursor on
429
                        else
430
                        {
431
                            $this->flushCell($sheet, $column, $row, $cellContent);
432
                            ++$row;
433
                        }
434
435
                        break;
436
437
                    // Hyperlinks
438
                    case 'a'  :
439
440
                        foreach ($attributeArray as $attributeName => $attributeValue)
441
                        {
442
                            switch ($attributeName)
443
                            {
444
                                case 'href':
445
446
                                    // Set the url
447
                                    $sheet->getCell($column . $row)
448
                                          ->getHyperlink()
449
                                          ->setUrl($attributeValue);
450
451
                                    // Set styling
452
                                    if ( isset($this->_formats[$child->nodeName]) )
453
                                    {
454
                                        $sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
455
                                    }
456
457
                                    break;
458
                            }
459
                        }
460
461
                        // Add empty space
462
                        $cellContent .= ' ';
463
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
464
465
                        break;
466
467
                    // Headings/paragraphs and lists
468
                    case 'h1' :
469
                    case 'h2' :
470
                    case 'h3' :
471
                    case 'h4' :
472
                    case 'h5' :
473
                    case 'h6' :
474
                    case 'ol' :
475
                    case 'ul' :
476
                    case 'p'  :
477
478
                        if ( $this->_tableLevel > 0 )
479
                        {
480
                            $cellContent .= "\n";
481
                            $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
482
                            $this->flushCell($sheet, $column, $row, $cellContent);
483
484
                            // Set style
485
                            if ( isset($this->_formats[$child->nodeName]) )
486
                            {
487
                                $sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
488
                            }
489
                        }
490
                        else
491
                        {
492
                            if ( $cellContent > '' )
493
                            {
494
                                $this->flushCell($sheet, $column, $row, $cellContent);
495
                                $row += 2;
496
                            }
497
                            $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
498
                            $this->flushCell($sheet, $column, $row, $cellContent);
499
500
                            // Set style
501
                            if ( isset($this->_formats[$child->nodeName]) )
502
                            {
503
                                $sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
504
                            }
505
506
                            $row += 2;
507
                            $column = 'A';
508
                        }
509
                        break;
510
511
                    // List istem
512
                    case 'li'  :
513
514
                        if ( $this->_tableLevel > 0 )
515
                        {
516
                            //  If we're inside a table, replace with a \n
517
                            $cellContent .= "\n";
518
                            $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
519
                        }
520
                        else
521
                        {
522
                            if ( $cellContent > '' )
523
                            {
524
                                $this->flushCell($sheet, $column, $row, $cellContent);
525
                            }
526
527
                            ++$row;
528
529
                            $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
530
                            $this->flushCell($sheet, $column, $row, $cellContent);
531
                            $column = 'A';
532
                        }
533
                        break;
534
535
                    // Tables
536
                    case 'table' :
537
538
                        // Flush the cells
539
                        $this->flushCell($sheet, $column, $row, $cellContent);
540
541
                        // Set the start column
542
                        $column = $this->_setTableStartColumn($column);
543
544
                        if ( $this->_tableLevel > 1 )
545
                            --$row;
546
547
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
548
549
                        // Release the table start column
550
                        $column = $this->_releaseTableStartColumn();
551
552
                        if ( $this->_tableLevel > 1 )
553
                        {
554
                            ++$column;
555
                        }
556
                        else
557
                        {
558
                            ++$row;
559
                        }
560
561
                        break;
562
563
                    // Heading and body
564
                    case 'thead' :
565
                    case 'tbody' :
566
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
567
                        break;
568
569
                    case 'img':
570
                        $this->insertImageBySrc($sheet, $column, $row, $child);
571
                        break;
572
573
                    // Table rows
574
                    case 'tr' :
575
576
                        // Get start column
577
                        $column = $this->_getTableStartColumn();
578
579
                        // Set empty cell content
580
                        $cellContent = '';
581
582
                        // Continue processing
583
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
584
585
                        ++$row;
586
587
                        // reset the span height
588
                        $this->spanHeight = 1;
589
590
                        break;
591
592
                    // Table heading
593
                    case 'th' :
594
                        // Continue processing
595
                        $this->_processHeadings($child, $sheet, $row, $column, $cellContent);
596
597
                        // If we have a colspan, count the right amount of columns, else just 1
598
                        for ($w = 0; $w < $this->spanWidth; $w++)
599
                        {
600
                            ++$column;
601
                        }
602
603
                        // reset the span width after the process
604
                        $this->spanWidth = 1;
605
606
                        break;
607
608
                    // Table cell
609
                    case 'td' :
610
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
611
                        $this->flushCell($sheet, $column, $row, $cellContent);
612
613
                        // If we have a colspan, count the right amount of columns, else just 1
614
                        for ($w = 0; $w < $this->spanWidth; $w++)
615
                        {
616
                            ++$column;
617
                        }
618
619
                        // reset the span width after the process
620
                        $this->spanWidth = 1;
621
                        break;
622
623
                    // Html Body
624
                    case 'body' :
625
                        $row = 1;
626
                        $column = 'A';
627
                        $content = '';
628
                        $this->_tableLevel = 0;
629
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
630
                        break;
631
632
                    // Default
633
                    default:
634
                        $this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
635
                }
636
            }
637
        }
638
    }
639
640
    /**
641
     * Set the start column
642
     * @param   string $column
643
     * @return  string
644
     */
645
    protected function _setTableStartColumn($column)
646
    {
647
        // Set to a
648
        if ( $this->_tableLevel == 0 )
649
            $column = 'A';
650
651
        ++$this->_tableLevel;
652
653
        // Get nested column
654
        $this->_nestedColumn[$this->_tableLevel] = $column;
655
656
        return $this->_nestedColumn[$this->_tableLevel];
657
    }
658
659
    /**
660
     * Get the table start column
661
     * @return string
662
     */
663
    protected function _getTableStartColumn()
664
    {
665
        return $this->_nestedColumn[$this->_tableLevel];
666
    }
667
668
    /**
669
     * Release the table start column
670
     * @return array
671
     */
672
    protected function _releaseTableStartColumn()
673
    {
674
        --$this->_tableLevel;
675
676
        return array_pop($this->_nestedColumn);
677
    }
678
679
    /**
680
     * Flush the cells
681
     * @param  LaravelExcelWorksheet $sheet
682
     * @param  string                $column
683
     * @param  integer               $row
684
     * @param  string                $cellContent
685
     * @return void
686
     */
687
    protected function flushCell($sheet, $column, $row, &$cellContent)
688
    {
689
        // Process merged cells
690
        list($column, $cellContent) = $this->processMergedCells($sheet, $column, $row, $cellContent);
691
692
        if ( is_string($cellContent) )
693
        {
694
            //  Simple String content
695
            if ( trim($cellContent) > '' )
696
            {
697
                //  Only actually write it if there's content in the string
698
                //  Write to worksheet to be done here...
699
                //  ... we return the cell so we can mess about with styles more easily
700
701
                $cell = $sheet->setCellValue($column . $row, $cellContent, true);
702
                $this->_dataArray[$row][$column] = $cellContent;
703
            }
704
        }
705
        else
706
        {
707
            $this->_dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
708
        }
709
        $cellContent = (string) '';
710
    }
711
712
    /**
713
     * Process table headings
714
     * @param  string                $child
715
     * @param  LaravelExcelWorksheet $sheet
716
     * @param  string                $row
717
     * @param  integer               $column
718
     * @param                        $cellContent
719
     * @throws \PHPExcel_Exception
720
     * @return LaravelExcelWorksheet
721
     */
722
    protected function _processHeadings($child, $sheet, $row, $column, $cellContent)
723
    {
724
        $this->_processDomElement($child, $sheet, $row, $column, $cellContent);
725
        $this->flushCell($sheet, $column, $row, $cellContent);
726
727
        if ( isset($this->_formats[$child->nodeName]) )
728
        {
729
            $sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
730
        }
731
732
        return $sheet;
733
    }
734
735
    /**
736
     * Insert a image inside the sheet
737
     * @param  LaravelExcelWorksheet $sheet
738
     * @param  string                $column
739
     * @param  integer               $row
740
     * @param  string                $attributes
741
     * @return void
742
     */
743
    protected function insertImageBySrc($sheet, $column, $row, $attributes)
744
    {
745
        // Get attributes
746
        $src = urldecode($attributes->getAttribute('src'));
747
        $width = (float) $attributes->getAttribute('width');
748
        $height = (float) $attributes->getAttribute('height');
749
        $alt = $attributes->getAttribute('alt');
750
751
        // init drawing
752
        $drawing = new PHPExcel_Worksheet_Drawing();
753
754
        // Set image
755
        $drawing->setPath($src);
756
        $drawing->setName($alt);
757
        $drawing->setWorksheet($sheet);
758
        $drawing->setCoordinates($column . $row);
759
        $drawing->setResizeProportional();
760
        $drawing->setOffsetX(0);
761
        $drawing->setOffsetY(10);
762
763
        // Set height and width
764
        if ( $width > 0 )
765
            $drawing->setWidth($width);
766
767
        if ( $height > 0 )
768
            $drawing->setHeight($height);
769
770
        // Set cell width based on image
771
        $this->parseWidth($sheet, $column, $row, $drawing->getWidth() / 6);
772
        $this->parseHeight($sheet, $column, $row, $drawing->getHeight() * 0.9);
773
    }
774
775
    /**
776
     * Set cell data format
777
     * @param  LaravelExcelWorksheet $sheet
778
     * @param  string                $column
779
     * @param  integer               $row
780
     * @param  integer               $width
781
     * @return void
782
    */
783
    protected function parseDataFormat($sheet, $column, $row, $format)
784
    {
785
        $sheet->setColumnFormat([$column.$row => $format]);
786
    }
787
788
    /**
789
     * Set column width
790
     * @param  LaravelExcelWorksheet $sheet
791
     * @param  string                $column
792
     * @param  integer               $row
793
     * @param  integer               $width
794
     * @return void
795
     */
796
    protected function parseWidth($sheet, $column, $row, $width)
797
    {
798
        $sheet->setWidth($column, $width);
799
    }
800
801
    /**
802
     * Set row height
803
     * @param  LaravelExcelWorksheet $sheet
804
     * @param  string                $column
805
     * @param  integer               $row
806
     * @param  integer               $height
807
     * @return void
808
     */
809
    protected function parseHeight($sheet, $column, $row, $height)
810
    {
811
        $sheet->setHeight($row, $height);
812
    }
813
814
    /**
815
     * Parse colspans
816
     * @param  LaravelExcelWorksheet $sheet
817
     * @param  string                $column
818
     * @param  integer               $row
819
     * @param  integer               $spanWidth
820
     * @param                        $attributes
821
     * @return void
822
     */
823
    protected function parseColSpan($sheet, $column, $row, $spanWidth, $attributes)
824
    {
825
        $startCell = $column . $row;
826
827
        $this->spanWidth = $spanWidth;
828
829
        // Find end column letter
830
        for ($i = 0; $i < ($spanWidth - 1); $i++)
831
        {
832
            ++$column;
833
        }
834
835
        // Set endcell
836
        $endCell = ($column) . $row;
837
838
        // Set range
839
        $range = $startCell . ':' . $endCell;
840
841
        // Remember css inline styles
842
        foreach ($attributes as $attribute)
843
        {
844
            if ( $attribute->name == 'style' )
845
            {
846
                $this->styles[$range] = $attribute->value;
847
            }
848
        }
849
850
        // Merge the cells
851
        $sheet->mergeCells($range);
852
    }
853
854
    /**
855
     * Parse colspans
856
     * @param  LaravelExcelWorksheet $sheet
857
     * @param  string                $column
858
     * @param  integer               $row
859
     * @param  integer               $spanHeight
860
     * @param                        $attributes
861
     * @return void
862
     */
863
    protected function parseRowSpan($sheet, $column, $row, $spanHeight, $attributes)
864
    {
865
        // Set the span height
866
        $this->spanHeight = --$spanHeight;
867
868
        // Set start cell
869
        $startCell = $column . $row;
870
871
        // Set endcell = current row number + spanheight
872
        $endCell = $column . ($row + $this->spanHeight);
873
        $range = $startCell . ':' . $endCell;
874
875
        // Remember css inline styles
876
        //foreach($attributes as $attribute)
877
        //{
878
        //    if($attribute->name == 'style')
879
        //    {
880
        //        $this->styles[$range] = $attribute->value;
881
        //    }
882
        //}
883
884
        // Merge the cells
885
        $sheet->mergeCells($range);
886
    }
887
888
    /**
889
     * Parse the align
890
     * @param  LaravelExcelWorksheet $sheet
891
     * @param  string                $column
892
     * @param  integer               $row
893
     * @param  string                $value
894
     * @return void
895
     */
896
    protected function parseAlign($sheet, $column, $row, $value)
897
    {
898
899
        $horizontal = false;
900
        $cells = $sheet->getStyle($column . $row);
901
902
        switch ($value)
903
        {
904
            case 'center':
905
                $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_CENTER;
906
                break;
907
908
            case 'left':
909
                $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_LEFT;
910
                break;
911
912
            case 'right':
913
                $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT;
914
                break;
915
916
            case 'justify':
917
                $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY;
918
                break;
919
        }
920
921
        if ( $horizontal )
922
            $cells->getAlignment()->applyFromArray(
923
                ['horizontal' => $horizontal]
924
            );
925
    }
926
927
    /**
928
     * Parse the valign
929
     * @param  LaravelExcelWorksheet $sheet
930
     * @param  string                $column
931
     * @param  integer               $row
932
     * @param  string                $value
933
     * @return void
934
     */
935
    protected function parseValign($sheet, $column, $row, $value)
936
    {
937
938
        $vertical = false;
939
        $cells = $sheet->getStyle($column . $row);
940
941
        switch ($value)
942
        {
943
            case 'top':
944
                $vertical = PHPExcel_Style_Alignment::VERTICAL_TOP;
945
                break;
946
947
            case 'middle':
948
                $vertical = PHPExcel_Style_Alignment::VERTICAL_CENTER;
949
                break;
950
951
            case 'bottom':
952
                $vertical = PHPExcel_Style_Alignment::VERTICAL_BOTTOM;
953
                break;
954
955
            case 'justify':
956
                $vertical = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY;
957
                break;
958
        }
959
960
        if ( $vertical )
961
            $cells->getAlignment()->applyFromArray(
962
                ['vertical' => $vertical]
963
            );
964
    }
965
966
    /**
967
     * Parse the inline styles
968
     * @param  LaravelExcelWorksheet $sheet
969
     * @param  string                $column
970
     * @param  integer               $row
971
     * @param  string                $styleTag
972
     * @return void
973
     */
974
    protected function parseInlineStyles($sheet, $column, $row, $styleTag)
975
    {
976
        // Seperate the different styles
977
        $styles = explode(';', $styleTag);
978
979
        $this->parseCssAttributes($sheet, $column, $row, $styles);
980
    }
981
982
    /**
983
     * Parse the styles
984
     * @param  LaravelExcelWorksheet $sheet
985
     * @param  string                $column
986
     * @param  integer               $row
987
     * @param                        array @styles
988
     * @return void
989
     */
990
    protected function parseCssAttributes($sheet, $column, $row, $styles = [])
991
    {
992
        foreach ($styles as $tag)
993
        {
994
            $style = explode(':', $tag);
995
            $name = trim(reset($style));
996
            $value = trim(end($style));
997
998
            $this->parseCssProperties($sheet, $column, $row, $name, $value);
999
        }
1000
    }
1001
1002
    /**
1003
     * Parse CSS
1004
     * @param  LaravelExcelWorksheet $sheet
1005
     * @param  string                $column
1006
     * @param  integer               $row
1007
     * @param  string                $name
1008
     * @param  string                $value
1009
     * @return void
1010
     */
1011
    protected function parseCssProperties($sheet, $column, $row, $name, $value)
1012
    {
1013
        $cells = $sheet->getStyle($column . $row);
1014
        switch ($name)
1015
        {
1016
            // Cell width
1017
            case 'width':
1018
                $this->parseWidth($sheet, $column, $row, $value);
1019
                break;
1020
1021
            // Row height
1022
            case 'height':
1023
                $this->parseHeight($sheet, $column, $row, $value);
1024
                break;
1025
1026
            // BACKGROUND
1027
            case 'background':
1028
            case 'background-color':
1029
1030
                $original = $value;
1031
1032
                $value = $this->getColor($value);
1033
1034
                $cells->getFill()->applyFromArray(
1035
                    [
1036
                        'type'  => PHPExcel_Style_Fill::FILL_SOLID,
1037
                        'color' => ['rgb' => $value]
1038
                    ]
1039
                );
1040
1041
                break;
1042
1043
            // TEXT COLOR
1044
            case 'color':
1045
                $value = $this->getColor($value);
1046
                $cells->getFont()->getColor()->applyFromArray(
1047
                    ['rgb' => $value]
1048
                );
1049
                break;
1050
1051
            // FONT SIZE
1052
            case 'font-size':
1053
                $cells->getFont()->setSize($value);
1054
                break;
1055
1056
            // FONT WEIGHT
1057
            case 'font-weight':
1058
                if ( $value == 'bold' || $value >= 500 )
1059
                    $cells->getFont()->setBold(true);
1060
                break;
1061
1062
            // FONT STYLE
1063
            case 'font-style':
1064
                if ( $value == 'italic' )
1065
                    $cells->getFont()->setItalic(true);
1066
                break;
1067
1068
            // FONT FACE
1069
            case 'font-family':
1070
                $cells->getFont()->applyFromArray(
1071
                    ['name' => $value]
1072
                );
1073
                break;
1074
1075
            // TEXT DECORATION
1076
            case 'text-decoration':
1077
                switch ($value)
1078
                {
1079
                    case 'underline':
1080
                        $cells->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
1081
                        break;
1082
1083
                    case 'line-through':
1084
                        $cells->getFont()->setStrikethrough(true);
1085
                        break;
1086
                }
1087
                break;
1088
1089
            // Text align
1090
            case 'text-align':
1091
1092
                $horizontal = false;
1093
1094
                switch ($value)
1095
                {
1096
                    case 'center':
1097
                        $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_CENTER;
1098
                        break;
1099
1100
                    case 'left':
1101
                        $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_LEFT;
1102
                        break;
1103
1104
                    case 'right':
1105
                        $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT;
1106
                        break;
1107
1108
                    case 'justify':
1109
                        $horizontal = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY;
1110
                        break;
1111
                }
1112
1113
                if ( $horizontal )
1114
                    $cells->getAlignment()->applyFromArray(
1115
                        ['horizontal' => $horizontal]
1116
                    );
1117
1118
                break;
1119
1120
            // Vertical align
1121
            case 'vertical-align':
1122
1123
                $vertical = false;
1124
1125
                switch ($value)
1126
                {
1127
                    case 'top':
1128
                        $vertical = PHPExcel_Style_Alignment::VERTICAL_TOP;
1129
                        break;
1130
1131
                    case 'middle':
1132
                        $vertical = PHPExcel_Style_Alignment::VERTICAL_CENTER;
1133
                        break;
1134
1135
                    case 'bottom':
1136
                        $vertical = PHPExcel_Style_Alignment::VERTICAL_BOTTOM;
1137
                        break;
1138
1139
                    case 'justify':
1140
                        $vertical = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY;
1141
                        break;
1142
                }
1143
1144
                if ( $vertical )
1145
                    $cells->getAlignment()->applyFromArray(
1146
                        ['vertical' => $vertical]
1147
                    );
1148
                break;
1149
1150
            // Borders
1151
            case 'border':
1152
            case 'borders':
1153
                $borders = explode(' ', $value);
1154
                if (!empty($borders[1])) {
1155
                    $style = $borders[1];
1156
                    $color = end($borders);
1157
                    $color = $this->getColor($color);
1158
                    $borderStyle = $this->borderStyle($style);
1159
1160
                    $cells->getBorders()->applyFromArray(
1161
                        ['allborders' => ['style' => $borderStyle, 'color' => ['rgb' => $color]]]
1162
                    );
1163
                }
1164
                break;
1165
1166
            // Border-top
1167
            case 'border-top':
1168
                $borders = explode(' ', $value);
1169
                if (!empty($borders[1])) {
1170
                    $style = $borders[1];
1171
                    $color = end($borders);
1172
                    $color = $this->getColor($color);
1173
1174
                    $borderStyle = $this->borderStyle($style);
1175
1176
                    $cells->getBorders()->getTop()->applyFromArray(
1177
                        ['style' => $borderStyle, 'color' => ['rgb' => $color]]
1178
                    );
1179
                }
1180
                break;
1181
1182
            // Border-bottom
1183
            case 'border-bottom':
1184
                $borders = explode(' ', $value);
1185
                if (!empty($borders[1])) {
1186
                    $style = $borders[1];
1187
                    $color = end($borders);
1188
                    $color = $this->getColor($color);
1189
                    $borderStyle = $this->borderStyle($style);
1190
1191
                    $cells->getBorders()->getBottom()->applyFromArray(
1192
                        ['style' => $borderStyle, 'color' => ['rgb' => $color]]
1193
                    );
1194
                }
1195
                break;
1196
1197
            // Border-right
1198
            case 'border-right':
1199
                $borders = explode(' ', $value);
1200
                if (!empty($borders[1])) {
1201
                    $style = $borders[1];
1202
                    $color = end($borders);
1203
                    $color = $this->getColor($color);
1204
                    $borderStyle = $this->borderStyle($style);
1205
1206
                    $cells->getBorders()->getRight()->applyFromArray(
1207
                        ['style' => $borderStyle, 'color' => ['rgb' => $color]]
1208
                    );
1209
                }
1210
                break;
1211
1212
            // Border-left
1213
            case 'border-left':
1214
                $borders = explode(' ', $value);
1215
                if (!empty($borders[1])) {
1216
                    $style = $borders[1];
1217
                    $color = end($borders);
1218
                    $color = $this->getColor($color);
1219
                    $borderStyle = $this->borderStyle($style);
1220
1221
                    $cells->getBorders()->getLeft()->applyFromArray(
1222
                        ['style' => $borderStyle, 'color' => ['rgb' => $color]]
1223
                    );
1224
                }
1225
                break;
1226
1227
            // wrap-text
1228
            case 'wrap-text':
1229
1230
                if ( $value == 'true' )
1231
                    $wrap = true;
1232
1233
                if ( !$value || $value == 'false' )
1234
                    $wrap = false;
1235
1236
                $cells->getAlignment()->setWrapText($wrap);
1237
1238
                break;
1239
1240
            case 'text-indent':
1241
                $cells->getAlignment()->setIndent((int)$value);
1242
                break;
1243
        }
1244
    }
1245
1246
    /**
1247
     * Get the color
1248
     * @param  string $color
1249
     * @return string
1250
     */
1251
    public function getColor($color)
1252
    {
1253
        $color = str_replace('#', '', $color);
1254
1255
        // If color is only 3 chars long, mirror it to 6 chars
1256
        if ( strlen($color) == 3 )
1257
            $color = $color . $color;
1258
1259
        return $color;
1260
    }
1261
1262
    /**
1263
     * Get the border style
1264
     * @param  string $style
1265
     * @return string
1266
     */
1267
    public function borderStyle($style)
1268
    {
1269
        switch ($style)
1270
        {
1271
            case 'solid';
1272
                return PHPExcel_Style_Border::BORDER_THIN;
1273
                break;
1274
1275
            case 'dashed':
1276
                return PHPExcel_Style_Border::BORDER_DASHED;
1277
                break;
1278
1279
            case 'dotted':
1280
                return PHPExcel_Style_Border::BORDER_DOTTED;
1281
                break;
1282
1283
            case 'medium':
1284
                return PHPExcel_Style_Border::BORDER_MEDIUM;
1285
                break;
1286
1287
            case 'thick':
1288
                return PHPExcel_Style_Border::BORDER_THICK;
1289
                break;
1290
1291
            case 'none':
1292
                return PHPExcel_Style_Border::BORDER_NONE;
1293
                break;
1294
1295
            case 'dash-dot':
1296
                return PHPExcel_Style_Border::BORDER_DASHDOT;
1297
                break;
1298
1299
            case 'dash-dot-dot':
1300
                return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
1301
                break;
1302
1303
            case 'double':
1304
                return PHPExcel_Style_Border::BORDER_DOUBLE;
1305
                break;
1306
1307
            case 'hair':
1308
                return PHPExcel_Style_Border::BORDER_HAIR;
1309
                break;
1310
1311
            case 'medium-dash-dot':
1312
                return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
1313
                break;
1314
1315
            case 'medium-dash-dot-dot':
1316
                return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
1317
                break;
1318
1319
            case 'medium-dashed':
1320
                return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
1321
                break;
1322
1323
            case 'slant-dash-dot':
1324
                return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
1325
                break;
1326
1327
            default:
1328
                return '';
1329
                break;
1330
        }
1331
    }
1332
1333
    /**
1334
     * @param $sheet
1335
     * @param $column
1336
     * @param $row
1337
     * @param $cellContent
1338
     * @throws \PHPExcel_Exception
1339
     * @return array
1340
     */
1341
    private function processMergedCells($sheet, &$column, $row, $cellContent)
1342
    {
1343
        // Find the cells
1344
        $cell = $sheet->getCell($column . $row);
1345
1346
        // Get the merged cells
1347
        foreach ($sheet->getMergeCells() as $mergedCells)
1348
        {
1349
            // If cells is in the merged cells range
1350
            if ( $cell->isInRange($mergedCells) )
1351
            {
1352
                // Get columns
1353
                preg_match("/(.*):(.*?)/u", $mergedCells, $matches);
1354
1355
                // skip the first item in the merge
1356
                if ( $matches[1] != $column . $row )
1357
                {
1358
                    $newCol = PHPExcel_Cell::stringFromColumnIndex(
1359
                        (PHPExcel_Cell::columnIndexFromString($column) + 1) - 1
1360
                    );
1361
1362
                    $column = $newCol;
1363
1364
                    // Set style for merged cells
1365
                    if ( isset($this->styles[$row]) )
1366
                        $this->parseInlineStyles($sheet, $column, $row, $this->styles[$row]);
1367
1368
                    // Flush cell
1369
                    $this->flushCell($sheet, $column, $row, $cellContent);
1370
                }
1371
            }
1372
        }
1373
1374
        return [$column, $cellContent];
1375
    }
1376
}
1377