1377 lines
42 KiB
PHP
1377 lines
42 KiB
PHP
<?php namespace Maatwebsite\Excel\Readers;
|
|
|
|
use PHPExcel;
|
|
use DOMNode;
|
|
use DOMText;
|
|
use DOMElement;
|
|
use DOMDocument;
|
|
use PHPExcel_Cell;
|
|
use PHPExcel_Settings;
|
|
use PHPExcel_Reader_HTML;
|
|
use PHPExcel_Style_Color;
|
|
use PHPExcel_Style_Fill;
|
|
use PHPExcel_Style_Font;
|
|
use PHPExcel_Style_Border;
|
|
use PHPExcel_Worksheet_Drawing;
|
|
use PHPExcel_Style_Alignment;
|
|
use Maatwebsite\Excel\Parsers\CssParser;
|
|
use Maatwebsite\Excel\Classes\LaravelExcelWorksheet;
|
|
|
|
/**
|
|
*
|
|
* LaravelExcel HTML reader
|
|
*
|
|
* @category Laravel Excel
|
|
* @version 2.0.0
|
|
* @package maatwebsite/excel
|
|
* @copyright Copyright (c) 2013 - 2014 Maatwebsite (http://www.maatwebsite.nl)
|
|
* @copyright Original Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
|
* @author Maatwebsite <info@maatwebsite.nl>
|
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
|
*/
|
|
class Html extends PHPExcel_Reader_HTML {
|
|
|
|
/**
|
|
* Style per range
|
|
* @var array
|
|
*/
|
|
protected $styles = [];
|
|
|
|
protected $_dataArray = [];
|
|
|
|
protected $_nestedColumn = ['A'];
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
protected $_tableLevel = 0;
|
|
|
|
/**
|
|
* Input encoding
|
|
* @var string
|
|
*/
|
|
protected $_inputEncoding = 'ANSI';
|
|
|
|
/**
|
|
* Sheet index to read
|
|
* @var int
|
|
*/
|
|
protected $_sheetIndex = 0;
|
|
|
|
/**
|
|
* HTML tags formatting settings
|
|
* @var array
|
|
*/
|
|
protected $_formats = [];
|
|
|
|
/**
|
|
* The current colspan
|
|
* @var integer
|
|
*/
|
|
protected $spanWidth = 1;
|
|
|
|
/**
|
|
* The current rowspan
|
|
* @var integer
|
|
*/
|
|
protected $spanHeight = 1;
|
|
|
|
/**
|
|
* @var
|
|
*/
|
|
private $cssParser;
|
|
|
|
/**
|
|
* @param CssParser $cssParser
|
|
*/
|
|
public function __construct(CssParser $cssParser)
|
|
{
|
|
$this->cssParser = $cssParser;
|
|
parent::__construct();
|
|
}
|
|
|
|
/**
|
|
* Loads PHPExcel from file
|
|
*
|
|
* @param string $pFilename
|
|
* @param boolean $isString
|
|
* @param bool|LaravelExcelWorksheet|null|PHPExcel $obj
|
|
* @throws \PHPExcel_Reader_Exception
|
|
* @return LaravelExcelWorksheet
|
|
*/
|
|
public function load($pFilename, $isString = false, $obj = false)
|
|
{
|
|
// Set the default style formats
|
|
$this->setStyleFormats();
|
|
|
|
if ( $obj instanceof PHPExcel )
|
|
{
|
|
// Load into this instance
|
|
return $this->loadIntoExisting($pFilename, $obj, $isString);
|
|
}
|
|
elseif ( $obj instanceof LaravelExcelWorksheet )
|
|
{
|
|
// Load into this instance
|
|
return $this->loadIntoExistingSheet($pFilename, $obj, $isString);
|
|
}
|
|
|
|
$objPHPExcel = $obj ? $obj : new PHPExcel();
|
|
|
|
return $this->loadIntoExisting($pFilename, $objPHPExcel, $isString);
|
|
}
|
|
|
|
/**
|
|
* Set the style formats from our config file
|
|
* @return array
|
|
*/
|
|
protected function setStyleFormats()
|
|
{
|
|
$this->_formats = config('excel.views.styles', []);
|
|
}
|
|
|
|
/**
|
|
* Loads HTML from file into sheet instance
|
|
*
|
|
* @param string $pFilename
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param boolean $isString
|
|
* @return LaravelExcelWorksheet
|
|
* @throws PHPExcel_Reader_Exception
|
|
*/
|
|
public function loadIntoExistingSheet($pFilename, LaravelExcelWorksheet $sheet, $isString = false)
|
|
{
|
|
$isHtmlFile = false;
|
|
|
|
// Check if it's a string or file
|
|
if ( !$isString )
|
|
{
|
|
// Double check if it's a file
|
|
if ( is_file($pFilename) )
|
|
{
|
|
$isHtmlFile = true;
|
|
$this->_openFile($pFilename);
|
|
|
|
if ( !$this->_isValidFormat() )
|
|
{
|
|
fclose($this->_fileHandle);
|
|
throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid HTML file.");
|
|
}
|
|
|
|
fclose($this->_fileHandle);
|
|
}
|
|
}
|
|
|
|
// Create a new DOM object
|
|
$dom = new DOMDocument;
|
|
|
|
// Check if we need to load the file or the HTML
|
|
if ( $isHtmlFile )
|
|
{
|
|
// Load HTML from file
|
|
if ( (version_compare(PHP_VERSION, '5.4.0') >= 0) && defined(LIBXML_DTDLOAD) )
|
|
{
|
|
$loaded = @$dom->loadHTMLFile($pFilename, PHPExcel_Settings::getLibXmlLoaderOptions());
|
|
}
|
|
else
|
|
{
|
|
$loaded = @$dom->loadHTMLFile($pFilename);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Load HTML from string
|
|
@$dom->loadHTML(mb_convert_encoding($pFilename, 'HTML-ENTITIES', 'UTF-8'));
|
|
|
|
// Let the css parser find all stylesheets
|
|
$this->cssParser->findStyleSheets($dom);
|
|
|
|
// Transform the css files to inline css and replace the html
|
|
$html = $this->cssParser->transformCssToInlineStyles($pFilename);
|
|
|
|
// Re-init dom doc
|
|
$dom = new DOMDocument;
|
|
|
|
// Load again with css included
|
|
$loaded = @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
|
|
}
|
|
|
|
if ( $loaded === false )
|
|
{
|
|
throw new PHPExcel_Reader_Exception('Failed to load ' . $pFilename . ' as a DOM Document');
|
|
}
|
|
|
|
// Discard white space
|
|
$dom->preserveWhiteSpace = true;
|
|
|
|
$row = 0;
|
|
$column = 'A';
|
|
$content = '';
|
|
$this->_processDomElement($dom, $sheet, $row, $column, $content);
|
|
|
|
if ( !$sheet->hasFixedSizeColumns() )
|
|
$this->autosizeColumn($sheet);
|
|
|
|
return $sheet;
|
|
}
|
|
|
|
/**
|
|
* Autosize column for document
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @return LaravelExcelWorksheet
|
|
*/
|
|
public function autosizeColumn($sheet)
|
|
{
|
|
if ( $columns = $sheet->getAutosize() )
|
|
{
|
|
if ( is_array($columns) )
|
|
{
|
|
$sheet->setAutoSize($columns);
|
|
}
|
|
else
|
|
{
|
|
$toCol = $sheet->getHighestColumn();
|
|
$toCol++;
|
|
for ($i = 'A'; $i !== $toCol; $i++)
|
|
{
|
|
$sheet->getColumnDimension($i)->setAutoSize(true);
|
|
}
|
|
|
|
$sheet->calculateColumnWidths();
|
|
}
|
|
}
|
|
|
|
return $sheet;
|
|
}
|
|
|
|
/**
|
|
* Process the dom element
|
|
* @param DOMNode $element
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $row
|
|
* @param integer $column
|
|
* @param string $cellContent
|
|
* @return void
|
|
*/
|
|
protected function _processDomElement(DOMNode $element, $sheet, &$row, &$column, &$cellContent, $format = null)
|
|
{
|
|
foreach ($element->childNodes as $child)
|
|
{
|
|
// If is text
|
|
if ( $child instanceof DOMText )
|
|
{
|
|
// get the dom text
|
|
$domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
|
|
|
|
// simply append the text if the cell content is a plain text string
|
|
if ( is_string($cellContent) )
|
|
{
|
|
$cellContent .= $domText;
|
|
}
|
|
}
|
|
|
|
// If is a dom element
|
|
elseif ( $child instanceof DOMElement )
|
|
{
|
|
$attributeArray = [];
|
|
|
|
// Set row (=parent) styles
|
|
if ( isset($this->styles[$row]) )
|
|
$this->parseInlineStyles($sheet, $column, $row, $this->styles[$row]);
|
|
|
|
// Loop through the child's attributes
|
|
foreach ($child->attributes as $attribute)
|
|
{
|
|
// Add the attribute to the array
|
|
$attributeArray[$attribute->name] = $attribute->value;
|
|
|
|
// Attribute names
|
|
switch ($attribute->name)
|
|
{
|
|
// Colspan
|
|
case 'width':
|
|
$this->parseWidth($sheet, $column, $row, $attribute->value);
|
|
break;
|
|
|
|
case 'height':
|
|
$this->parseHeight($sheet, $column, $row, $attribute->value);
|
|
break;
|
|
|
|
// Colspan
|
|
case 'colspan':
|
|
$this->parseColSpan($sheet, $column, $row, $attribute->value, $child->attributes);
|
|
break;
|
|
|
|
// Rowspan
|
|
case 'rowspan':
|
|
$this->parseRowSpan($sheet, $column, $row, $attribute->value, $child->attributes);
|
|
break;
|
|
|
|
// Alignment
|
|
case 'align':
|
|
$this->parseAlign($sheet, $column, $row, $attribute->value);
|
|
break;
|
|
|
|
// Vertical alignment
|
|
case 'valign':
|
|
$this->parseValign($sheet, $column, $row, $attribute->value);
|
|
break;
|
|
|
|
// Cell format
|
|
case 'data-format':
|
|
$this->parseDataFormat($sheet, $column, $row, $attribute->value);
|
|
break;
|
|
|
|
// Inline css styles
|
|
case 'style':
|
|
$this->parseInlineStyles($sheet, $column, $row, $attribute->value);
|
|
|
|
if ( $child->nodeName == 'tr' )
|
|
$this->styles[$row] = $attribute->value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// nodeName
|
|
switch ($child->nodeName)
|
|
{
|
|
|
|
// Meta tags
|
|
case 'meta' :
|
|
|
|
// Loop through the attributes
|
|
foreach ($attributeArray as $attributeName => $attributeValue)
|
|
{
|
|
|
|
// Switch the names
|
|
switch ($attributeName)
|
|
{
|
|
// Set input encoding
|
|
case 'charset':
|
|
$_inputEncoding = $attributeValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Continue processing dom element
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
|
|
break;
|
|
|
|
// Set sheet title
|
|
case 'title' :
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
$sheet->setTitle($cellContent);
|
|
$cellContent = '';
|
|
break;
|
|
|
|
// Text
|
|
case 'span' :
|
|
case 'div' :
|
|
case 'font' :
|
|
case 'i' :
|
|
case 'em' :
|
|
case 'strong':
|
|
case 'b' :
|
|
|
|
// Add space after empty cells
|
|
if ( $cellContent > '' )
|
|
$cellContent .= ' ';
|
|
|
|
// Continue processing
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
|
|
// Add space after empty cells
|
|
if ( $cellContent > '' )
|
|
$cellContent .= ' ';
|
|
|
|
// Set the styling
|
|
if ( isset($this->_formats[$child->nodeName]) )
|
|
{
|
|
$sheet->getStyle($column . $row)
|
|
->applyFromArray($this->_formats[$child->nodeName]);
|
|
}
|
|
|
|
break;
|
|
|
|
// Horizontal rules
|
|
case 'hr' :
|
|
|
|
// Flush the cell
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
|
|
// count
|
|
++$row;
|
|
|
|
// Set the styling
|
|
if ( isset($this->_formats[$child->nodeName]) )
|
|
{
|
|
$sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
|
|
}
|
|
// If not, enter cell content
|
|
else
|
|
{
|
|
$cellContent = '----------';
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
}
|
|
|
|
++$row;
|
|
|
|
// Linebreaks
|
|
case 'br' :
|
|
|
|
// Add linebreak
|
|
if ( $this->_tableLevel > 0 )
|
|
{
|
|
$cellContent .= "\n";
|
|
}
|
|
|
|
// Otherwise flush our existing content and move the row cursor on
|
|
else
|
|
{
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
++$row;
|
|
}
|
|
|
|
break;
|
|
|
|
// Hyperlinks
|
|
case 'a' :
|
|
|
|
foreach ($attributeArray as $attributeName => $attributeValue)
|
|
{
|
|
switch ($attributeName)
|
|
{
|
|
case 'href':
|
|
|
|
// Set the url
|
|
$sheet->getCell($column . $row)
|
|
->getHyperlink()
|
|
->setUrl($attributeValue);
|
|
|
|
// Set styling
|
|
if ( isset($this->_formats[$child->nodeName]) )
|
|
{
|
|
$sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Add empty space
|
|
$cellContent .= ' ';
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
|
|
break;
|
|
|
|
// Headings/paragraphs and lists
|
|
case 'h1' :
|
|
case 'h2' :
|
|
case 'h3' :
|
|
case 'h4' :
|
|
case 'h5' :
|
|
case 'h6' :
|
|
case 'ol' :
|
|
case 'ul' :
|
|
case 'p' :
|
|
|
|
if ( $this->_tableLevel > 0 )
|
|
{
|
|
$cellContent .= "\n";
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
|
|
// Set style
|
|
if ( isset($this->_formats[$child->nodeName]) )
|
|
{
|
|
$sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( $cellContent > '' )
|
|
{
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
$row += 2;
|
|
}
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
|
|
// Set style
|
|
if ( isset($this->_formats[$child->nodeName]) )
|
|
{
|
|
$sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
|
|
}
|
|
|
|
$row += 2;
|
|
$column = 'A';
|
|
}
|
|
break;
|
|
|
|
// List istem
|
|
case 'li' :
|
|
|
|
if ( $this->_tableLevel > 0 )
|
|
{
|
|
// If we're inside a table, replace with a \n
|
|
$cellContent .= "\n";
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
}
|
|
else
|
|
{
|
|
if ( $cellContent > '' )
|
|
{
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
}
|
|
|
|
++$row;
|
|
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
$column = 'A';
|
|
}
|
|
break;
|
|
|
|
// Tables
|
|
case 'table' :
|
|
|
|
// Flush the cells
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
|
|
// Set the start column
|
|
$column = $this->_setTableStartColumn($column);
|
|
|
|
if ( $this->_tableLevel > 1 )
|
|
--$row;
|
|
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
|
|
// Release the table start column
|
|
$column = $this->_releaseTableStartColumn();
|
|
|
|
if ( $this->_tableLevel > 1 )
|
|
{
|
|
++$column;
|
|
}
|
|
else
|
|
{
|
|
++$row;
|
|
}
|
|
|
|
break;
|
|
|
|
// Heading and body
|
|
case 'thead' :
|
|
case 'tbody' :
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
break;
|
|
|
|
case 'img':
|
|
$this->insertImageBySrc($sheet, $column, $row, $child);
|
|
break;
|
|
|
|
// Table rows
|
|
case 'tr' :
|
|
|
|
// Get start column
|
|
$column = $this->_getTableStartColumn();
|
|
|
|
// Set empty cell content
|
|
$cellContent = '';
|
|
|
|
// Continue processing
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
|
|
++$row;
|
|
|
|
// reset the span height
|
|
$this->spanHeight = 1;
|
|
|
|
break;
|
|
|
|
// Table heading
|
|
case 'th' :
|
|
// Continue processing
|
|
$this->_processHeadings($child, $sheet, $row, $column, $cellContent);
|
|
|
|
// If we have a colspan, count the right amount of columns, else just 1
|
|
for ($w = 0; $w < $this->spanWidth; $w++)
|
|
{
|
|
++$column;
|
|
}
|
|
|
|
// reset the span width after the process
|
|
$this->spanWidth = 1;
|
|
|
|
break;
|
|
|
|
// Table cell
|
|
case 'td' :
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
|
|
// If we have a colspan, count the right amount of columns, else just 1
|
|
for ($w = 0; $w < $this->spanWidth; $w++)
|
|
{
|
|
++$column;
|
|
}
|
|
|
|
// reset the span width after the process
|
|
$this->spanWidth = 1;
|
|
break;
|
|
|
|
// Html Body
|
|
case 'body' :
|
|
$row = 1;
|
|
$column = 'A';
|
|
$content = '';
|
|
$this->_tableLevel = 0;
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
break;
|
|
|
|
// Default
|
|
default:
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent, $format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the start column
|
|
* @param string $column
|
|
* @return string
|
|
*/
|
|
protected function _setTableStartColumn($column)
|
|
{
|
|
// Set to a
|
|
if ( $this->_tableLevel == 0 )
|
|
$column = 'A';
|
|
|
|
++$this->_tableLevel;
|
|
|
|
// Get nested column
|
|
$this->_nestedColumn[$this->_tableLevel] = $column;
|
|
|
|
return $this->_nestedColumn[$this->_tableLevel];
|
|
}
|
|
|
|
/**
|
|
* Get the table start column
|
|
* @return string
|
|
*/
|
|
protected function _getTableStartColumn()
|
|
{
|
|
return $this->_nestedColumn[$this->_tableLevel];
|
|
}
|
|
|
|
/**
|
|
* Release the table start column
|
|
* @return array
|
|
*/
|
|
protected function _releaseTableStartColumn()
|
|
{
|
|
--$this->_tableLevel;
|
|
|
|
return array_pop($this->_nestedColumn);
|
|
}
|
|
|
|
/**
|
|
* Flush the cells
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param string $cellContent
|
|
* @return void
|
|
*/
|
|
protected function flushCell($sheet, $column, $row, &$cellContent)
|
|
{
|
|
// Process merged cells
|
|
list($column, $cellContent) = $this->processMergedCells($sheet, $column, $row, $cellContent);
|
|
|
|
if ( is_string($cellContent) )
|
|
{
|
|
// Simple String content
|
|
if ( trim($cellContent) > '' )
|
|
{
|
|
// Only actually write it if there's content in the string
|
|
// Write to worksheet to be done here...
|
|
// ... we return the cell so we can mess about with styles more easily
|
|
|
|
$cell = $sheet->setCellValue($column . $row, $cellContent, true);
|
|
$this->_dataArray[$row][$column] = $cellContent;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->_dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
|
|
}
|
|
$cellContent = (string) '';
|
|
}
|
|
|
|
/**
|
|
* Process table headings
|
|
* @param string $child
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $row
|
|
* @param integer $column
|
|
* @param $cellContent
|
|
* @throws \PHPExcel_Exception
|
|
* @return LaravelExcelWorksheet
|
|
*/
|
|
protected function _processHeadings($child, $sheet, $row, $column, $cellContent)
|
|
{
|
|
$this->_processDomElement($child, $sheet, $row, $column, $cellContent);
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
|
|
if ( isset($this->_formats[$child->nodeName]) )
|
|
{
|
|
$sheet->getStyle($column . $row)->applyFromArray($this->_formats[$child->nodeName]);
|
|
}
|
|
|
|
return $sheet;
|
|
}
|
|
|
|
/**
|
|
* Insert a image inside the sheet
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param string $attributes
|
|
* @return void
|
|
*/
|
|
protected function insertImageBySrc($sheet, $column, $row, $attributes)
|
|
{
|
|
// Get attributes
|
|
$src = urldecode($attributes->getAttribute('src'));
|
|
$width = (float) $attributes->getAttribute('width');
|
|
$height = (float) $attributes->getAttribute('height');
|
|
$alt = $attributes->getAttribute('alt');
|
|
|
|
// init drawing
|
|
$drawing = new PHPExcel_Worksheet_Drawing();
|
|
|
|
// Set image
|
|
$drawing->setPath($src);
|
|
$drawing->setName($alt);
|
|
$drawing->setWorksheet($sheet);
|
|
$drawing->setCoordinates($column . $row);
|
|
$drawing->setResizeProportional();
|
|
$drawing->setOffsetX(0);
|
|
$drawing->setOffsetY(10);
|
|
|
|
// Set height and width
|
|
if ( $width > 0 )
|
|
$drawing->setWidth($width);
|
|
|
|
if ( $height > 0 )
|
|
$drawing->setHeight($height);
|
|
|
|
// Set cell width based on image
|
|
$this->parseWidth($sheet, $column, $row, $drawing->getWidth() / 6);
|
|
$this->parseHeight($sheet, $column, $row, $drawing->getHeight() * 0.9);
|
|
}
|
|
|
|
/**
|
|
* Set cell data format
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param integer $width
|
|
* @return void
|
|
*/
|
|
protected function parseDataFormat($sheet, $column, $row, $format)
|
|
{
|
|
$sheet->setColumnFormat([$column.$row => $format]);
|
|
}
|
|
|
|
/**
|
|
* Set column width
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param integer $width
|
|
* @return void
|
|
*/
|
|
protected function parseWidth($sheet, $column, $row, $width)
|
|
{
|
|
$sheet->setWidth($column, $width);
|
|
}
|
|
|
|
/**
|
|
* Set row height
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param integer $height
|
|
* @return void
|
|
*/
|
|
protected function parseHeight($sheet, $column, $row, $height)
|
|
{
|
|
$sheet->setHeight($row, $height);
|
|
}
|
|
|
|
/**
|
|
* Parse colspans
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param integer $spanWidth
|
|
* @param $attributes
|
|
* @return void
|
|
*/
|
|
protected function parseColSpan($sheet, $column, $row, $spanWidth, $attributes)
|
|
{
|
|
$startCell = $column . $row;
|
|
|
|
$this->spanWidth = $spanWidth;
|
|
|
|
// Find end column letter
|
|
for ($i = 0; $i < ($spanWidth - 1); $i++)
|
|
{
|
|
++$column;
|
|
}
|
|
|
|
// Set endcell
|
|
$endCell = ($column) . $row;
|
|
|
|
// Set range
|
|
$range = $startCell . ':' . $endCell;
|
|
|
|
// Remember css inline styles
|
|
foreach ($attributes as $attribute)
|
|
{
|
|
if ( $attribute->name == 'style' )
|
|
{
|
|
$this->styles[$range] = $attribute->value;
|
|
}
|
|
}
|
|
|
|
// Merge the cells
|
|
$sheet->mergeCells($range);
|
|
}
|
|
|
|
/**
|
|
* Parse colspans
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param integer $spanHeight
|
|
* @param $attributes
|
|
* @return void
|
|
*/
|
|
protected function parseRowSpan($sheet, $column, $row, $spanHeight, $attributes)
|
|
{
|
|
// Set the span height
|
|
$this->spanHeight = --$spanHeight;
|
|
|
|
// Set start cell
|
|
$startCell = $column . $row;
|
|
|
|
// Set endcell = current row number + spanheight
|
|
$endCell = $column . ($row + $this->spanHeight);
|
|
$range = $startCell . ':' . $endCell;
|
|
|
|
// Remember css inline styles
|
|
//foreach($attributes as $attribute)
|
|
//{
|
|
// if($attribute->name == 'style')
|
|
// {
|
|
// $this->styles[$range] = $attribute->value;
|
|
// }
|
|
//}
|
|
|
|
// Merge the cells
|
|
$sheet->mergeCells($range);
|
|
}
|
|
|
|
/**
|
|
* Parse the align
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param string $value
|
|
* @return void
|
|
*/
|
|
protected function parseAlign($sheet, $column, $row, $value)
|
|
{
|
|
|
|
$horizontal = false;
|
|
$cells = $sheet->getStyle($column . $row);
|
|
|
|
switch ($value)
|
|
{
|
|
case 'center':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_CENTER;
|
|
break;
|
|
|
|
case 'left':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_LEFT;
|
|
break;
|
|
|
|
case 'right':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT;
|
|
break;
|
|
|
|
case 'justify':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY;
|
|
break;
|
|
}
|
|
|
|
if ( $horizontal )
|
|
$cells->getAlignment()->applyFromArray(
|
|
['horizontal' => $horizontal]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Parse the valign
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param string $value
|
|
* @return void
|
|
*/
|
|
protected function parseValign($sheet, $column, $row, $value)
|
|
{
|
|
|
|
$vertical = false;
|
|
$cells = $sheet->getStyle($column . $row);
|
|
|
|
switch ($value)
|
|
{
|
|
case 'top':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_TOP;
|
|
break;
|
|
|
|
case 'middle':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_CENTER;
|
|
break;
|
|
|
|
case 'bottom':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_BOTTOM;
|
|
break;
|
|
|
|
case 'justify':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY;
|
|
break;
|
|
}
|
|
|
|
if ( $vertical )
|
|
$cells->getAlignment()->applyFromArray(
|
|
['vertical' => $vertical]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Parse the inline styles
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param string $styleTag
|
|
* @return void
|
|
*/
|
|
protected function parseInlineStyles($sheet, $column, $row, $styleTag)
|
|
{
|
|
// Seperate the different styles
|
|
$styles = explode(';', $styleTag);
|
|
|
|
$this->parseCssAttributes($sheet, $column, $row, $styles);
|
|
}
|
|
|
|
/**
|
|
* Parse the styles
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param array @styles
|
|
* @return void
|
|
*/
|
|
protected function parseCssAttributes($sheet, $column, $row, $styles = [])
|
|
{
|
|
foreach ($styles as $tag)
|
|
{
|
|
$style = explode(':', $tag);
|
|
$name = trim(reset($style));
|
|
$value = trim(end($style));
|
|
|
|
$this->parseCssProperties($sheet, $column, $row, $name, $value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse CSS
|
|
* @param LaravelExcelWorksheet $sheet
|
|
* @param string $column
|
|
* @param integer $row
|
|
* @param string $name
|
|
* @param string $value
|
|
* @return void
|
|
*/
|
|
protected function parseCssProperties($sheet, $column, $row, $name, $value)
|
|
{
|
|
$cells = $sheet->getStyle($column . $row);
|
|
switch ($name)
|
|
{
|
|
// Cell width
|
|
case 'width':
|
|
$this->parseWidth($sheet, $column, $row, $value);
|
|
break;
|
|
|
|
// Row height
|
|
case 'height':
|
|
$this->parseHeight($sheet, $column, $row, $value);
|
|
break;
|
|
|
|
// BACKGROUND
|
|
case 'background':
|
|
case 'background-color':
|
|
|
|
$original = $value;
|
|
|
|
$value = $this->getColor($value);
|
|
|
|
$cells->getFill()->applyFromArray(
|
|
[
|
|
'type' => PHPExcel_Style_Fill::FILL_SOLID,
|
|
'color' => ['rgb' => $value]
|
|
]
|
|
);
|
|
|
|
break;
|
|
|
|
// TEXT COLOR
|
|
case 'color':
|
|
$value = $this->getColor($value);
|
|
$cells->getFont()->getColor()->applyFromArray(
|
|
['rgb' => $value]
|
|
);
|
|
break;
|
|
|
|
// FONT SIZE
|
|
case 'font-size':
|
|
$cells->getFont()->setSize($value);
|
|
break;
|
|
|
|
// FONT WEIGHT
|
|
case 'font-weight':
|
|
if ( $value == 'bold' || $value >= 500 )
|
|
$cells->getFont()->setBold(true);
|
|
break;
|
|
|
|
// FONT STYLE
|
|
case 'font-style':
|
|
if ( $value == 'italic' )
|
|
$cells->getFont()->setItalic(true);
|
|
break;
|
|
|
|
// FONT FACE
|
|
case 'font-family':
|
|
$cells->getFont()->applyFromArray(
|
|
['name' => $value]
|
|
);
|
|
break;
|
|
|
|
// TEXT DECORATION
|
|
case 'text-decoration':
|
|
switch ($value)
|
|
{
|
|
case 'underline':
|
|
$cells->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
|
|
break;
|
|
|
|
case 'line-through':
|
|
$cells->getFont()->setStrikethrough(true);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// Text align
|
|
case 'text-align':
|
|
|
|
$horizontal = false;
|
|
|
|
switch ($value)
|
|
{
|
|
case 'center':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_CENTER;
|
|
break;
|
|
|
|
case 'left':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_LEFT;
|
|
break;
|
|
|
|
case 'right':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT;
|
|
break;
|
|
|
|
case 'justify':
|
|
$horizontal = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY;
|
|
break;
|
|
}
|
|
|
|
if ( $horizontal )
|
|
$cells->getAlignment()->applyFromArray(
|
|
['horizontal' => $horizontal]
|
|
);
|
|
|
|
break;
|
|
|
|
// Vertical align
|
|
case 'vertical-align':
|
|
|
|
$vertical = false;
|
|
|
|
switch ($value)
|
|
{
|
|
case 'top':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_TOP;
|
|
break;
|
|
|
|
case 'middle':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_CENTER;
|
|
break;
|
|
|
|
case 'bottom':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_BOTTOM;
|
|
break;
|
|
|
|
case 'justify':
|
|
$vertical = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY;
|
|
break;
|
|
}
|
|
|
|
if ( $vertical )
|
|
$cells->getAlignment()->applyFromArray(
|
|
['vertical' => $vertical]
|
|
);
|
|
break;
|
|
|
|
// Borders
|
|
case 'border':
|
|
case 'borders':
|
|
$borders = explode(' ', $value);
|
|
if (!empty($borders[1])) {
|
|
$style = $borders[1];
|
|
$color = end($borders);
|
|
$color = $this->getColor($color);
|
|
$borderStyle = $this->borderStyle($style);
|
|
|
|
$cells->getBorders()->applyFromArray(
|
|
['allborders' => ['style' => $borderStyle, 'color' => ['rgb' => $color]]]
|
|
);
|
|
}
|
|
break;
|
|
|
|
// Border-top
|
|
case 'border-top':
|
|
$borders = explode(' ', $value);
|
|
if (!empty($borders[1])) {
|
|
$style = $borders[1];
|
|
$color = end($borders);
|
|
$color = $this->getColor($color);
|
|
|
|
$borderStyle = $this->borderStyle($style);
|
|
|
|
$cells->getBorders()->getTop()->applyFromArray(
|
|
['style' => $borderStyle, 'color' => ['rgb' => $color]]
|
|
);
|
|
}
|
|
break;
|
|
|
|
// Border-bottom
|
|
case 'border-bottom':
|
|
$borders = explode(' ', $value);
|
|
if (!empty($borders[1])) {
|
|
$style = $borders[1];
|
|
$color = end($borders);
|
|
$color = $this->getColor($color);
|
|
$borderStyle = $this->borderStyle($style);
|
|
|
|
$cells->getBorders()->getBottom()->applyFromArray(
|
|
['style' => $borderStyle, 'color' => ['rgb' => $color]]
|
|
);
|
|
}
|
|
break;
|
|
|
|
// Border-right
|
|
case 'border-right':
|
|
$borders = explode(' ', $value);
|
|
if (!empty($borders[1])) {
|
|
$style = $borders[1];
|
|
$color = end($borders);
|
|
$color = $this->getColor($color);
|
|
$borderStyle = $this->borderStyle($style);
|
|
|
|
$cells->getBorders()->getRight()->applyFromArray(
|
|
['style' => $borderStyle, 'color' => ['rgb' => $color]]
|
|
);
|
|
}
|
|
break;
|
|
|
|
// Border-left
|
|
case 'border-left':
|
|
$borders = explode(' ', $value);
|
|
if (!empty($borders[1])) {
|
|
$style = $borders[1];
|
|
$color = end($borders);
|
|
$color = $this->getColor($color);
|
|
$borderStyle = $this->borderStyle($style);
|
|
|
|
$cells->getBorders()->getLeft()->applyFromArray(
|
|
['style' => $borderStyle, 'color' => ['rgb' => $color]]
|
|
);
|
|
}
|
|
break;
|
|
|
|
// wrap-text
|
|
case 'wrap-text':
|
|
|
|
if ( $value == 'true' )
|
|
$wrap = true;
|
|
|
|
if ( !$value || $value == 'false' )
|
|
$wrap = false;
|
|
|
|
$cells->getAlignment()->setWrapText($wrap);
|
|
|
|
break;
|
|
|
|
case 'text-indent':
|
|
$cells->getAlignment()->setIndent((int)$value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the color
|
|
* @param string $color
|
|
* @return string
|
|
*/
|
|
public function getColor($color)
|
|
{
|
|
$color = str_replace('#', '', $color);
|
|
|
|
// If color is only 3 chars long, mirror it to 6 chars
|
|
if ( strlen($color) == 3 )
|
|
$color = $color . $color;
|
|
|
|
return $color;
|
|
}
|
|
|
|
/**
|
|
* Get the border style
|
|
* @param string $style
|
|
* @return string
|
|
*/
|
|
public function borderStyle($style)
|
|
{
|
|
switch ($style)
|
|
{
|
|
case 'solid';
|
|
return PHPExcel_Style_Border::BORDER_THIN;
|
|
break;
|
|
|
|
case 'dashed':
|
|
return PHPExcel_Style_Border::BORDER_DASHED;
|
|
break;
|
|
|
|
case 'dotted':
|
|
return PHPExcel_Style_Border::BORDER_DOTTED;
|
|
break;
|
|
|
|
case 'medium':
|
|
return PHPExcel_Style_Border::BORDER_MEDIUM;
|
|
break;
|
|
|
|
case 'thick':
|
|
return PHPExcel_Style_Border::BORDER_THICK;
|
|
break;
|
|
|
|
case 'none':
|
|
return PHPExcel_Style_Border::BORDER_NONE;
|
|
break;
|
|
|
|
case 'dash-dot':
|
|
return PHPExcel_Style_Border::BORDER_DASHDOT;
|
|
break;
|
|
|
|
case 'dash-dot-dot':
|
|
return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
|
|
break;
|
|
|
|
case 'double':
|
|
return PHPExcel_Style_Border::BORDER_DOUBLE;
|
|
break;
|
|
|
|
case 'hair':
|
|
return PHPExcel_Style_Border::BORDER_HAIR;
|
|
break;
|
|
|
|
case 'medium-dash-dot':
|
|
return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
|
|
break;
|
|
|
|
case 'medium-dash-dot-dot':
|
|
return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
|
|
break;
|
|
|
|
case 'medium-dashed':
|
|
return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
|
|
break;
|
|
|
|
case 'slant-dash-dot':
|
|
return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
|
|
break;
|
|
|
|
default:
|
|
return '';
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $sheet
|
|
* @param $column
|
|
* @param $row
|
|
* @param $cellContent
|
|
* @throws \PHPExcel_Exception
|
|
* @return array
|
|
*/
|
|
private function processMergedCells($sheet, &$column, $row, $cellContent)
|
|
{
|
|
// Find the cells
|
|
$cell = $sheet->getCell($column . $row);
|
|
|
|
// Get the merged cells
|
|
foreach ($sheet->getMergeCells() as $mergedCells)
|
|
{
|
|
// If cells is in the merged cells range
|
|
if ( $cell->isInRange($mergedCells) )
|
|
{
|
|
// Get columns
|
|
preg_match("/(.*):(.*?)/u", $mergedCells, $matches);
|
|
|
|
// skip the first item in the merge
|
|
if ( $matches[1] != $column . $row )
|
|
{
|
|
$newCol = PHPExcel_Cell::stringFromColumnIndex(
|
|
(PHPExcel_Cell::columnIndexFromString($column) + 1) - 1
|
|
);
|
|
|
|
$column = $newCol;
|
|
|
|
// Set style for merged cells
|
|
if ( isset($this->styles[$row]) )
|
|
$this->parseInlineStyles($sheet, $column, $row, $this->styles[$row]);
|
|
|
|
// Flush cell
|
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
|
}
|
|
}
|
|
}
|
|
|
|
return [$column, $cellContent];
|
|
}
|
|
}
|