Skip to content

Commit

Permalink
Merge pull request svrnm#6 from lucentlogix/master
Browse files Browse the repository at this point in the history
Added feature to preserve existing formulas, together with example
  • Loading branch information
svrnm authored Oct 14, 2016
2 parents e49bed0 + 62e3784 commit 2b621bb
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 6 deletions.
17 changes: 17 additions & 0 deletions examples/preserve-formulas/example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
require_once('../../vendor/autoload.php');
$dataTable = new Svrnm\ExcelDataTables\ExcelDataTable();
$in = 'spec.xlsx';
$out = 'test.xlsx';
$data = array(
array("Date" => new \DateTime('2014-01-01 13:00:00'), "Value 1" => 0, "Value 2" => 1),
array("Date" => new \DateTime('2014-01-02 14:00:00'), "Value 1" => 1, "Value 2" => 0),
array("Date" => new \DateTime('2014-01-03 15:00:00'), "Value 1" => 2, "Value 2" => -1),
array("Date" => new \DateTime('2014-01-04 16:00:00'), "Value 1" => 3, "Value 2" => -2),
array("Date" => new \DateTime('2014-01-05 17:00:00'), "Value 1" => 4, "Value 2" => -3),
array("Date" => new \DateTime('2014-01-03 15:00:00'), "Value 1" => 30, "Value 2" => -1),
array("Date" => new \DateTime('2014-01-04 16:00:00'), "Value 1" => 3, "Value 2" => -2),
array("Date" => new \DateTime('2014-01-05 17:00:00'), "Value 1" => 4, "Value 2" => -3),
);
$dataTable->showHeaders()->preserveFormulas('Data')->addRows($data)->refreshTableRange('Data')->attachToFile($in, $out, false);
?>
50 changes: 50 additions & 0 deletions examples/preserve-formulas/performance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
ini_set('memory_limit', '2048M');
require_once('../../vendor/autoload.php');
$in = 'spec.xlsx';
$out = 'test.xlsx';
$lastPeak = 0;

$rows = 64;
$cols = 20;

while($lastPeak < 1024*1024*300) {


$data = array();
for($i = 0; $i < $rows; $i++) {
$row = array();
for($j = 0; $j < $cols; $j++) {
switch($j%3) {
case 0:
$row[] = $i;
break;
case 1:
$row[] = '('.$i.','.$j.')' ;
break;
case 2:
$row[] = new DateTime('2014-01-01');
break;
}
}
$data[] = $row;
}

$start = microtime(true);
$dataTable = new Svrnm\ExcelDataTables\ExcelDataTable();
$dataTable->showHeaders();
$dataTable->preserveFormulas('Data');
$dataTable->addRows($data);
$time0 = microtime(true) - $start;
$dataTable->attachToFile($in, $out);
$time1 = microtime(true)-$start;
$lastPeak = memory_get_peak_usage();
echo $rows.' x '.$cols.":\t";
echo ($time0)." s\t";
echo ($time1)." s\t";
echo floor((($rows)/$time1))." rows/s\t";
echo floor((($rows*$cols)/$time1))." entries/s\t";
echo ($lastPeak/(1024*1024)).' MB'.PHP_EOL;
$rows*=2;
}
?>
Binary file added examples/preserve-formulas/spec.xlsx
Binary file not shown.
Binary file added examples/preserve-formulas/test.xlsx
Binary file not shown.
34 changes: 33 additions & 1 deletion src/Svrnm/ExcelDataTables/ExcelDataTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ class ExcelDataTable
*/
protected $refreshTableRange = null;

/**
* If set, injects column formulas into the output
*
* @var null|string
*/
protected $preserveFormulas = null;

/**
* Variable to hold calculated columns from source
*
* @var null|array
*/
protected $calculatedColumns = null;

/**
* Instantiate a new ExcelDataTable object
*
Expand Down Expand Up @@ -399,12 +413,18 @@ public function setSheetName($name) {
* @return $this
*/
public function attachToFile($srcFilename, $targetFilename = null, $forceAutoCalculation = false) {
if ($this->preserveFormulas){
$temp_xlsx = new ExcelWorkbook($srcFilename);
$calculatedColumns = $temp_xlsx->getCalculatedColumns($this->preserveFormulas);
unset($temp_xlsx);
}

$xlsx = new ExcelWorkbook($srcFilename);
$worksheet = new ExcelWorksheet();
if(!is_null($targetFilename)) {
$xlsx->setFilename($targetFilename);
}
$worksheet->addRows($this->toArray());
$worksheet->addRows($this->toArray(), $calculatedColumns);
$xlsx->addWorksheet($worksheet, $this->sheetId, $this->sheetName);
if($forceAutoCalculation) {
$xlsx->enableAutoCalculation();
Expand Down Expand Up @@ -448,4 +468,16 @@ public function refreshTableRange($table_name = 'Data')
return $this;
}

/**
* This function extracts the existing column formulas and injects them.
*
* @param string $table_name name of the excel table
* @return $this
*/
public function preserveFormulas($table_name = 'Data')
{
$this->preserveFormulas = $table_name;
return $this;
}

}
28 changes: 28 additions & 0 deletions src/Svrnm/ExcelDataTables/ExcelWorkbook.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,34 @@ public function refreshTableRange($tableName, $numRows)
return $this;
}

public function getCalculatedColumns($tableName)
{
$id = $this->getTableIdByName($tableName);
if(isset($id)){
$document = new \DOMDocument();
$document->loadXML($this->getXLSX()->getFromName('xl/tables/table' . $id . '.xml'));
$columns = $document->getElementsByTagName('tableColumn');
foreach($columns as $key => $column) {
if($column->getElementsByTagName("calculatedColumnFormula")->length){
$header = $column->getAttribute('name');
$formula = $column->nodeValue;
$calculatedColumn = array(
'index' => $key,
'header' => $header,
'content' => array(
$header => array(
'type' => 'formula',
'value' => $formula,
)
)
);
$calculatedColumns[] = $calculatedColumn;
}
}
return $calculatedColumns;
}
}

/**
* Return the ZipArchive representation of the current workbook
*
Expand Down
23 changes: 18 additions & 5 deletions src/Svrnm/ExcelDataTables/ExcelWorksheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ class ExcelWorksheet
const COLUMN_TYPE_STRING = 0;
const COLUMN_TYPE_NUMBER = 1;
const COLUMN_TYPE_DATETIME = 2;
const COLUMN_TYPE_FORMULA = 3;

protected static $columnTypes = array(
'string' => 0,
'number' => 1,
'datetime' => 2
'datetime' => 2,
'formula' => 3
);

/**
Expand Down Expand Up @@ -243,7 +245,7 @@ protected function addColumnToRow($row, $column) {
if(is_array($column)
&& isset($column['type'])
&& isset($column['value'])
&& in_array($column['type'], array('string', 'number', 'datetime'))) {
&& in_array($column['type'], array('string', 'number', 'datetime', 'formula'))) {
//$function = 'add'.ucfirst($column['type']).'ColumnToRow';
//return $this->$function($row, $column['value']);
$this->rows[$row][] = array(self::$columnTypes[$column['type']], $column['value']);
Expand All @@ -268,6 +270,9 @@ public function toXMLColumn($column) {
return '<c s="'.$this->dateTimeFormatId.'"><v>'.static::convertDate($column[1]).'</v></c>';
break;
// case self::COLUMN_TYPE_STRING:
case self::COLUMN_TYPE_FORMULA:
return '<c><f>'.$column[1].'</f></c>';
break;
default:
return '<c t="inlineStr"><is><t>'.strtr($column[1], array(
"&" => "&amp;",
Expand Down Expand Up @@ -408,9 +413,17 @@ protected function append($name, $attributes = array(), $parent = null) {
return $element;
}

public function addRows($array)
{
foreach($array as $row) {
public function addRows($array, $calculatedColumns = null){
foreach($array as $key => $row) {
if(isset($calculatedColumns)){
foreach ($calculatedColumns as $calculatedColumn) {
if($key == 0){
array_splice($row, $calculatedColumn['index'], 0, $calculatedColumn['header']);
} else {
array_splice($row, $calculatedColumn['index'], 0, $calculatedColumn['content']);
}
}
}
$this->addRow($row);
}
return $this;
Expand Down

0 comments on commit 2b621bb

Please sign in to comment.