diff --git a/Classes/PHPExcel.php b/Classes/PHPExcel.php index 2a450c4c..19213c24 100644 --- a/Classes/PHPExcel.php +++ b/Classes/PHPExcel.php @@ -42,6 +42,13 @@ if (!defined('PHPEXCEL_ROOT')) { */ class PHPExcel { + /** + * Unique ID + * + * @var string + */ + private $_uniqueID; + /** * Document properties * @@ -63,6 +70,13 @@ class PHPExcel */ private $_workSheetCollection = array(); + /** + * Calculation Engine + * + * @var PHPExcel_Calculation + */ + private $_calculationEngine = NULL; + /** * Active sheet index * @@ -103,6 +117,9 @@ class PHPExcel */ public function __construct() { + $this->_uniqueID = uniqid(); + $this->_calculationEngine = PHPExcel_Calculation::getInstance($this); + // Initialise worksheet collection and add one worksheet $this->_workSheetCollection = array(); $this->_workSheetCollection[] = new PHPExcel_Worksheet($this); @@ -126,13 +143,22 @@ class PHPExcel $this->addCellStyleXf(new PHPExcel_Style); } + /** + * Code to execute when this worksheet is unset() + * + */ + public function __destruct() { + PHPExcel_Calculation::unsetInstance($this); + $this->disconnectWorksheets(); + } // function __destruct() /** * Disconnect all worksheets from this PHPExcel workbook object, * typically so that the PHPExcel object can be unset * */ - public function disconnectWorksheets() { + public function disconnectWorksheets() + { $worksheet = NULL; foreach($this->_workSheetCollection as $k => &$worksheet) { $worksheet->disconnectCells(); @@ -142,13 +168,15 @@ class PHPExcel $this->_workSheetCollection = array(); } - /** - * Code to execute when this worksheet is unset() - * - */ - function __destruct() { - $this->disconnectWorksheets(); - } + /** + * Return the calculation engine for this worksheet + * + * @return PHPExcel_Calculation + */ + public function getCalculationEngine() + { + return $this->_calculationEngine; + } // function getCellCacheController() /** * Get properties @@ -849,12 +877,14 @@ class PHPExcel foreach ($sheet->getColumnDimensions() as $columnDimension) { $columnDimension->setXfIndex( $map[$columnDimension->getXfIndex()] ); } - } - // also do garbage collection for all the sheets - foreach ($this->getWorksheetIterator() as $sheet) { + // also do garbage collection for all the sheets $sheet->garbageCollect(); } } + public function getID() { + return $this->_uniqueID; + } + } diff --git a/Classes/PHPExcel/CachedObjectStorage/APC.php b/Classes/PHPExcel/CachedObjectStorage/APC.php index 8f1e931e..2e61f03b 100644 --- a/Classes/PHPExcel/CachedObjectStorage/APC.php +++ b/Classes/PHPExcel/CachedObjectStorage/APC.php @@ -154,8 +154,8 @@ class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_Cach // Set current entry to the requested entry $this->_currentObjectID = $pCoord; $this->_currentObject = unserialize($obj); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/CacheBase.php b/Classes/PHPExcel/CachedObjectStorage/CacheBase.php index 924b4b44..6dd6c1a5 100644 --- a/Classes/PHPExcel/CachedObjectStorage/CacheBase.php +++ b/Classes/PHPExcel/CachedObjectStorage/CacheBase.php @@ -86,6 +86,11 @@ abstract class PHPExcel_CachedObjectStorage_CacheBase { } // function __construct() + public function getParent() + { + return $this->_parent; + } + /** * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell? * @@ -101,6 +106,27 @@ abstract class PHPExcel_CachedObjectStorage_CacheBase { } // function isDataSet() + /** + * Move a cell object from one address to another + * + * @param string $fromAddress Current address of the cell to move + * @param string $toAddress Destination address of the cell to move + * @return boolean + */ + public function moveCell($fromAddress, $toAddress) { + if ($fromAddress === $this->_currentObjectID) { + $this->_currentObjectID = $toAddress; + } + $this->_currentCellIsDirty = true; + if (isset($this->_cellCache[$fromAddress])) { + $this->_cellCache[$toAddress] = &$this->_cellCache[$fromAddress]; + unset($this->_cellCache[$fromAddress]); + } + + return TRUE; + } // function moveCell() + + /** * Add or Update a cell in cache * @@ -188,6 +214,23 @@ abstract class PHPExcel_CachedObjectStorage_CacheBase { } + public function getCurrentAddress() + { + return $this->_currentObjectID; + } + + public function getCurrentColumn() + { + list($column,$row) = sscanf($this->_currentObjectID, '%[A-Z]%d'); + return $column; + } + + public function getCurrentRow() + { + list($column,$row) = sscanf($this->_currentObjectID, '%[A-Z]%d'); + return $row; + } + /** * Get highest worksheet column * @@ -237,7 +280,7 @@ abstract class PHPExcel_CachedObjectStorage_CacheBase { $this->_parent = $parent; if (($this->_currentObject !== NULL) && (is_object($this->_currentObject))) { - $this->_currentObject->attach($parent); + $this->_currentObject->attach($this); } } // function copyCellCollection() diff --git a/Classes/PHPExcel/CachedObjectStorage/DiscISAM.php b/Classes/PHPExcel/CachedObjectStorage/DiscISAM.php index 3fde3851..956fd56e 100644 --- a/Classes/PHPExcel/CachedObjectStorage/DiscISAM.php +++ b/Classes/PHPExcel/CachedObjectStorage/DiscISAM.php @@ -124,8 +124,8 @@ class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage $this->_currentObjectID = $pCoord; fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']); $this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz'])); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/Igbinary.php b/Classes/PHPExcel/CachedObjectStorage/Igbinary.php index 6e33468a..7e7d1dfc 100644 --- a/Classes/PHPExcel/CachedObjectStorage/Igbinary.php +++ b/Classes/PHPExcel/CachedObjectStorage/Igbinary.php @@ -96,8 +96,8 @@ class PHPExcel_CachedObjectStorage_Igbinary extends PHPExcel_CachedObjectStorage // Set current entry to the requested entry $this->_currentObjectID = $pCoord; $this->_currentObject = igbinary_unserialize($this->_cellCache[$pCoord]); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/Memcache.php b/Classes/PHPExcel/CachedObjectStorage/Memcache.php index 76ff9096..a5440599 100644 --- a/Classes/PHPExcel/CachedObjectStorage/Memcache.php +++ b/Classes/PHPExcel/CachedObjectStorage/Memcache.php @@ -158,8 +158,8 @@ class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage // Set current entry to the requested entry $this->_currentObjectID = $pCoord; $this->_currentObject = unserialize($obj); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/Memory.php b/Classes/PHPExcel/CachedObjectStorage/Memory.php index 416b1e47..1e05b062 100644 --- a/Classes/PHPExcel/CachedObjectStorage/Memory.php +++ b/Classes/PHPExcel/CachedObjectStorage/Memory.php @@ -48,11 +48,15 @@ class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_C * * @param string $pCoord Coordinate address of the cell to update * @param PHPExcel_Cell $cell Cell to update - * @return void + * @return PHPExcel_Cell * @throws PHPExcel_Exception */ public function addCacheData($pCoord, PHPExcel_Cell $cell) { $this->_cellCache[$pCoord] = $cell; + + // Set current entry to the new/updated entry + $this->_currentObjectID = $pCoord; + return $cell; } // function addCacheData() @@ -67,10 +71,14 @@ class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_C public function getCacheData($pCoord) { // Check if the entry that has been requested actually exists if (!isset($this->_cellCache[$pCoord])) { + $this->_currentObjectID = NULL; // Return null if requested entry doesn't exist in cache return null; } + // Set current entry to the requested entry + $this->_currentObjectID = $pCoord; + // Return requested entry return $this->_cellCache[$pCoord]; } // function getCacheData() diff --git a/Classes/PHPExcel/CachedObjectStorage/MemoryGZip.php b/Classes/PHPExcel/CachedObjectStorage/MemoryGZip.php index ecb29b8c..43ed104f 100644 --- a/Classes/PHPExcel/CachedObjectStorage/MemoryGZip.php +++ b/Classes/PHPExcel/CachedObjectStorage/MemoryGZip.php @@ -96,8 +96,8 @@ class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStora // Set current entry to the requested entry $this->_currentObjectID = $pCoord; $this->_currentObject = unserialize(gzinflate($this->_cellCache[$pCoord])); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/MemorySerialized.php b/Classes/PHPExcel/CachedObjectStorage/MemorySerialized.php index 3feb5faf..5e1f8381 100644 --- a/Classes/PHPExcel/CachedObjectStorage/MemorySerialized.php +++ b/Classes/PHPExcel/CachedObjectStorage/MemorySerialized.php @@ -96,8 +96,8 @@ class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjec // Set current entry to the requested entry $this->_currentObjectID = $pCoord; $this->_currentObject = unserialize($this->_cellCache[$pCoord]); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/PHPTemp.php b/Classes/PHPExcel/CachedObjectStorage/PHPTemp.php index e6eafb7f..5b13e668 100644 --- a/Classes/PHPExcel/CachedObjectStorage/PHPTemp.php +++ b/Classes/PHPExcel/CachedObjectStorage/PHPTemp.php @@ -116,8 +116,8 @@ class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_ $this->_currentObjectID = $pCoord; fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']); $this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz'])); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CachedObjectStorage/SQLite.php b/Classes/PHPExcel/CachedObjectStorage/SQLite.php index 915d21d0..5e82c089 100644 --- a/Classes/PHPExcel/CachedObjectStorage/SQLite.php +++ b/Classes/PHPExcel/CachedObjectStorage/SQLite.php @@ -116,8 +116,8 @@ class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_C $cellResult = $cellResultSet->fetchSingle(); $this->_currentObject = unserialize($cellResult); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; @@ -169,6 +169,32 @@ class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_C } // function deleteCacheData() + /** + * Move a cell object from one address to another + * + * @param string $fromAddress Current address of the cell to move + * @param string $toAddress Destination address of the cell to move + * @return boolean + */ + public function moveCell($fromAddress, $toAddress) { + if ($fromAddress === $this->_currentObjectID) { + $this->_currentObjectID = $toAddress; + } + + $query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$toAddress."'"; + $result = $this->_DBHandle->exec($query); + if ($result === false) + throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); + + $query = "UPDATE kvp_".$this->_TableName." SET id='".$toAddress."' WHERE id='".$fromAddress."'"; + $result = $this->_DBHandle->exec($query); + if ($result === false) + throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); + + return TRUE; + } // function moveCell() + + /** * Get a list of all cell addresses currently held in cache * @@ -256,6 +282,10 @@ class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_C * Destroy this cell collection */ public function __destruct() { + if (!is_null($this->_DBHandle)) { + $this->_DBHandle->queryExec('DROP TABLE kvp_'.$this->_TableName); + $this->_DBHandle->close(); + } $this->_DBHandle = null; } // function __destruct() diff --git a/Classes/PHPExcel/CachedObjectStorage/SQLite3.php b/Classes/PHPExcel/CachedObjectStorage/SQLite3.php index f9ca246e..ecd80294 100644 --- a/Classes/PHPExcel/CachedObjectStorage/SQLite3.php +++ b/Classes/PHPExcel/CachedObjectStorage/SQLite3.php @@ -49,6 +49,11 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ */ private $_DBHandle = null; + private $_selectQuery; + private $_insertQuery; + private $_updateQuery; + private $_deleteQuery; + /** * Store cell data in cache for the current cell object if it's "dirty", * and the 'nullify' the current cell object @@ -60,10 +65,9 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ if ($this->_currentCellIsDirty) { $this->_currentObject->detach(); - $query = $this->_DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES(:id,:data)"); - $query->bindValue('id',$this->_currentObjectID,SQLITE3_TEXT); - $query->bindValue('data',serialize($this->_currentObject),SQLITE3_BLOB); - $result = $query->execute(); + $this->_insertQuery->bindValue('id',$this->_currentObjectID,SQLITE3_TEXT); + $this->_insertQuery->bindValue('data',serialize($this->_currentObject),SQLITE3_BLOB); + $result = $this->_insertQuery->execute(); if ($result === false) throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); $this->_currentCellIsDirty = false; @@ -106,21 +110,23 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ } $this->_storeData(); - $query = "SELECT value FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'"; - $cellResult = $this->_DBHandle->querySingle($query); - if ($cellResult === false) { + $this->_selectQuery->bindValue('id',$pCoord,SQLITE3_TEXT); + $cellResult = $this->_selectQuery->execute(); + if ($cellResult === FALSE) { throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); - } elseif (is_null($cellResult)) { + } + $cellData = $cellResult->fetchArray(SQLITE3_ASSOC); + if ($cellData === FALSE) { // Return null if requested entry doesn't exist in cache - return null; + return NULL; } // Set current entry to the requested entry $this->_currentObjectID = $pCoord; - $this->_currentObject = unserialize($cellResult); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + $this->_currentObject = unserialize($cellData['value']); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; @@ -135,19 +141,18 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ */ public function isDataSet($pCoord) { if ($pCoord === $this->_currentObjectID) { - return true; + return TRUE; } // Check if the requested entry exists in the cache - $query = "SELECT id FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'"; - $cellResult = $this->_DBHandle->querySingle($query); - if ($cellResult === false) { + $this->_selectQuery->bindValue('id',$pCoord,SQLITE3_TEXT); + $cellResult = $this->_selectQuery->execute(); + if ($cellResult === FALSE) { throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); - } elseif (is_null($cellResult)) { - // Return null if requested entry doesn't exist in cache - return false; } - return true; + $cellData = $cellResult->fetchArray(SQLITE3_ASSOC); + + return ($cellData === FALSE) ? FALSE : TRUE; } // function isDataSet() @@ -160,17 +165,44 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ public function deleteCacheData($pCoord) { if ($pCoord === $this->_currentObjectID) { $this->_currentObject->detach(); - $this->_currentObjectID = $this->_currentObject = null; + $this->_currentObjectID = $this->_currentObject = NULL; } // Check if the requested entry exists in the cache - $query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'"; - $result = $this->_DBHandle->exec($query); + $this->_deleteQuery->bindValue('id',$pCoord,SQLITE3_TEXT); + $result = $this->_deleteQuery->execute(); + if ($result === FALSE) + throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); + + $this->_currentCellIsDirty = FALSE; + } // function deleteCacheData() + + + /** + * Move a cell object from one address to another + * + * @param string $fromAddress Current address of the cell to move + * @param string $toAddress Destination address of the cell to move + * @return boolean + */ + public function moveCell($fromAddress, $toAddress) { + if ($fromAddress === $this->_currentObjectID) { + $this->_currentObjectID = $toAddress; + } + + $this->_deleteQuery->bindValue('id',$toAddress,SQLITE3_TEXT); + $result = $this->_deleteQuery->execute(); if ($result === false) throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); - $this->_currentCellIsDirty = false; - } // function deleteCacheData() + $this->_updateQuery->bindValue('toid',$toAddress,SQLITE3_TEXT); + $this->_updateQuery->bindValue('fromid',$fromAddress,SQLITE3_TEXT); + $result = $this->_updateQuery->execute(); + if ($result === false) + throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); + + return TRUE; + } // function moveCell() /** @@ -253,6 +285,11 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) throw new PHPExcel_Exception($this->_DBHandle->lastErrorMsg()); } + + $this->_selectQuery = $this->_DBHandle->prepare("SELECT value FROM kvp_".$this->_TableName." WHERE id = :id"); + $this->_insertQuery = $this->_DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES(:id,:data)"); + $this->_updateQuery = $this->_DBHandle->prepare("UPDATE kvp_".$this->_TableName." SET id=:toId WHERE id=:fromId"); + $this->_deleteQuery = $this->_DBHandle->prepare("DELETE FROM kvp_".$this->_TableName." WHERE id = :id"); } // function __construct() @@ -261,6 +298,7 @@ class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_ */ public function __destruct() { if (!is_null($this->_DBHandle)) { + $this->_DBHandle->exec('DROP TABLE kvp_'.$this->_TableName); $this->_DBHandle->close(); } $this->_DBHandle = null; diff --git a/Classes/PHPExcel/CachedObjectStorage/Wincache.php b/Classes/PHPExcel/CachedObjectStorage/Wincache.php index 38d61166..97b16397 100644 --- a/Classes/PHPExcel/CachedObjectStorage/Wincache.php +++ b/Classes/PHPExcel/CachedObjectStorage/Wincache.php @@ -158,8 +158,8 @@ class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage // Set current entry to the requested entry $this->_currentObjectID = $pCoord; $this->_currentObject = unserialize($obj); - // Re-attach the parent worksheet - $this->_currentObject->attach($this->_parent); + // Re-attach this as the cell's parent + $this->_currentObject->attach($this); // Return requested entry return $this->_currentObject; diff --git a/Classes/PHPExcel/CalcEngine/CyclicReferenceStack.php b/Classes/PHPExcel/CalcEngine/CyclicReferenceStack.php new file mode 100644 index 00000000..e64b4686 --- /dev/null +++ b/Classes/PHPExcel/CalcEngine/CyclicReferenceStack.php @@ -0,0 +1,58 @@ +_stack); + } + + public function push($value) { + $this->_stack[] = $value; + } // function push() + + public function pop() { + return array_pop($this->_stack); + } // function pop() + + public function onStack($value) { + return in_array($value,$this->_stack); + } + + public function clear() { + $this->_stack = array(); + } // function push() + + public function showStack() { + return $this->_stack; + } + +} // class PHPExcel_CalcEngine_CyclicReferenceStack diff --git a/Classes/PHPExcel/CalcEngine/Logger.php b/Classes/PHPExcel/CalcEngine/Logger.php new file mode 100644 index 00000000..250f841d --- /dev/null +++ b/Classes/PHPExcel/CalcEngine/Logger.php @@ -0,0 +1,121 @@ +_cellStack = $stack; + } + + public function setWriteDebugLog($pValue = FALSE) { + $this->_writeDebugLog = $pValue; + } + + public function getWriteDebugLog() { + return $this->_writeDebugLog; + } + + public function setEchoDebugLog($pValue = FALSE) { + $this->_echoDebugLog = $pValue; + } + + public function getEchoDebugLog() { + return $this->_echoDebugLog; + } + + public function writeDebugLog() { + // Only write the debug log if logging is enabled + if ($this->_writeDebugLog) { + $message = implode(func_get_args()); + $cellReference = implode(' -> ', $this->_cellStack->showStack()); + if ($this->_echoDebugLog) { + echo $cellReference, + ($this->_cellStack->count() > 0 ? ' => ' : ''), + $message, + PHP_EOL; + } + $this->_debugLog[] = $cellReference . + ($this->_cellStack->count() > 0 ? ' => ' : '') . + $message; + } + } // function _writeDebug() + + public function clearLog() { + $this->_debugLog = array(); + } // function flushLogger() + + public function getLog() { + return $this->_debugLog; + } // function flushLogger() + +} // class PHPExcel_CalcEngine_Logger + diff --git a/Classes/PHPExcel/Calculation.php b/Classes/PHPExcel/Calculation.php index 254a4e9c..c98e50cb 100644 --- a/Classes/PHPExcel/Calculation.php +++ b/Classes/PHPExcel/Calculation.php @@ -96,13 +96,29 @@ class PHPExcel_Calculation { private static $_instance; + /** + * Instance of the workbook this Calculation Engine is using + * + * @access private + * @var PHPExcel + */ + private $_workbook; + + /** + * List of instances of the calculation engine that we've instantiated + * + * @access private + * @var PHPExcel_Calculation[] + */ + private static $_workbookSets; + /** * Calculation cache * * @access private * @var array */ - private static $_calculationCache = array (); + private $_calculationCache = array (); /** @@ -111,7 +127,7 @@ class PHPExcel_Calculation { * @access private * @var boolean */ - private static $_calculationCacheEnabled = true; + private $_calculationCacheEnabled = TRUE; /** @@ -121,10 +137,10 @@ class PHPExcel_Calculation { * @access private * @var array */ - private static $_operators = array('+' => true, '-' => true, '*' => true, '/' => true, - '^' => true, '&' => true, '%' => false, '~' => false, - '>' => true, '<' => true, '=' => true, '>=' => true, - '<=' => true, '<>' => true, '|' => true, ':' => true + private static $_operators = array('+' => TRUE, '-' => TRUE, '*' => TRUE, '/' => TRUE, + '^' => TRUE, '&' => TRUE, '%' => FALSE, '~' => FALSE, + '>' => TRUE, '<' => TRUE, '=' => TRUE, '>=' => TRUE, + '<=' => TRUE, '<>' => TRUE, '|' => TRUE, ':' => TRUE ); @@ -134,12 +150,21 @@ class PHPExcel_Calculation { * @access private * @var array */ - private static $_binaryOperators = array('+' => true, '-' => true, '*' => true, '/' => true, - '^' => true, '&' => true, '>' => true, '<' => true, - '=' => true, '>=' => true, '<=' => true, '<>' => true, - '|' => true, ':' => true + private static $_binaryOperators = array('+' => TRUE, '-' => TRUE, '*' => TRUE, '/' => TRUE, + '^' => TRUE, '&' => TRUE, '>' => TRUE, '<' => TRUE, + '=' => TRUE, '>=' => TRUE, '<=' => TRUE, '<>' => TRUE, + '|' => TRUE, ':' => TRUE ); + /** + * The debug log generated by the calculation engine + * + * @access private + * @var PHPExcel_CalcEngine_Logger + * + */ + private $debugLog; + /** * Flag to determine how formula errors should be handled * If true, then a user error will be triggered @@ -149,7 +174,7 @@ class PHPExcel_Calculation { * @var boolean * */ - public $suppressFormulaErrors = false; + public $suppressFormulaErrors = FALSE; /** * Error message for any error that was raised/thrown by the calculation engine @@ -158,31 +183,7 @@ class PHPExcel_Calculation { * @var string * */ - public $formulaError = null; - - /** - * Flag to determine whether a debug log should be generated by the calculation engine - * If true, then a debug log will be generated - * If false, then a debug log will not be generated - * - * @access public - * @var boolean - * - */ - public $writeDebugLog = false; - - /** - * Flag to determine whether a debug log should be echoed by the calculation engine - * If true, then a debug log will be echoed - * If false, then a debug log will not be echoed - * A debug log can only be echoed if it is generated - * - * @access public - * @var boolean - * - */ - public $echoDebugLog = false; - + public $formulaError = NULL; /** * An array of the nested cell references accessed by the calculation engine, used for the debug log @@ -191,22 +192,14 @@ class PHPExcel_Calculation { * @var array of string * */ - private $debugLogStack = array(); + private $_cyclicReferenceStack; - /** - * The debug log generated by the calculation engine - * - * @access public - * @var array of string - * - */ - public $debugLog = array(); private $_cyclicFormulaCount = 0; private $_cyclicFormulaCell = ''; public $cyclicFormulaCount = 0; - private $_savedPrecision = 12; + private $_savedPrecision = 14; private static $_localeLanguage = 'en_us'; // US English (default locale) @@ -221,9 +214,9 @@ class PHPExcel_Calculation { // Constant conversion from text name/value to actual (datatyped) value - private static $_ExcelConstants = array('TRUE' => true, - 'FALSE' => false, - 'NULL' => null + private static $_ExcelConstants = array('TRUE' => TRUE, + 'FALSE' => FALSE, + 'NULL' => NULL ); // PHPExcel functions @@ -395,7 +388,7 @@ class PHPExcel_Calculation { 'COLUMN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMN', 'argumentCount' => '-1', - 'passByReference' => array(true) + 'passByReference' => array(TRUE) ), 'COLUMNS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMNS', @@ -804,7 +797,7 @@ class PHPExcel_Calculation { 'HYPERLINK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::HYPERLINK', 'argumentCount' => '1,2', - 'passCellReference'=> true + 'passCellReference'=> TRUE ), 'HYPGEOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, 'functionCall' => 'PHPExcel_Calculation_Statistical::HYPGEOMDIST', @@ -893,7 +886,7 @@ class PHPExcel_Calculation { 'INDIRECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDIRECT', 'argumentCount' => '1,2', - 'passCellReference'=> true + 'passCellReference'=> TRUE ), 'INFO' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', @@ -1210,8 +1203,8 @@ class PHPExcel_Calculation { 'OFFSET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::OFFSET', 'argumentCount' => '3,5', - 'passCellReference'=> true, - 'passByReference' => array(true) + 'passCellReference'=> TRUE, + 'passByReference' => array(TRUE) ), 'OR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_OR', @@ -1356,7 +1349,7 @@ class PHPExcel_Calculation { 'ROW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROW', 'argumentCount' => '-1', - 'passByReference' => array(true) + 'passByReference' => array(TRUE) ), 'ROWS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROWS', @@ -1671,12 +1664,20 @@ class PHPExcel_Calculation { - private function __construct() { - $setPrecision = (PHP_INT_SIZE == 4) ? 12 : 16; + private function __construct(PHPExcel $workbook = NULL) { + $setPrecision = (PHP_INT_SIZE == 4) ? 14 : 16; $this->_savedPrecision = ini_get('precision'); if ($this->_savedPrecision < $setPrecision) { ini_set('precision',$setPrecision); } + + if ($workbook !== NULL) { + self::$_workbookSets[$workbook->getID()] = $this; + } + + $this->_workbook = $workbook; + $this->_cyclicReferenceStack = new PHPExcel_CalcEngine_CyclicReferenceStack(); + $this->_debugLog = new PHPExcel_CalcEngine_Logger($this->_cyclicReferenceStack); } // function __construct() @@ -1702,7 +1703,14 @@ class PHPExcel_Calculation { * @access public * @return PHPExcel_Calculation */ - public static function getInstance() { + public static function getInstance(PHPExcel $workbook = NULL) { + if ($workbook !== NULL) { + if (isset(self::$_workbookSets[$workbook->getID()])) { + return self::$_workbookSets[$workbook->getID()]; + } + return new PHPExcel_Calculation($workbook); + } + if (!isset(self::$_instance) || (self::$_instance === NULL)) { self::$_instance = new PHPExcel_Calculation(); } @@ -1710,6 +1718,13 @@ class PHPExcel_Calculation { return self::$_instance; } // function getInstance() + public static function unsetInstance(PHPExcel $workbook = NULL) { + if ($workbook !== NULL) { + if (isset(self::$_workbookSets[$workbook->getID()])) { + unset(self::$_workbookSets[$workbook->getID()]); + } + } + } /** * Flush the calculation cache for any existing instance of this class @@ -1718,13 +1733,15 @@ class PHPExcel_Calculation { * @access public * @return null */ - public static function flushInstance() { - if (isset(self::$_instance) && (self::$_instance !== NULL)) { - self::$_instance->clearCalculationCache(); - } + public function flushInstance() { + $this->clearCalculationCache(); } // function flushInstance() + public function getDebugLog() { + return $this->_debugLog; + } + /** * __clone implementation. Cloning should not be allowed in a Singleton! * @@ -1732,7 +1749,7 @@ class PHPExcel_Calculation { * @throws PHPExcel_Calculation_Exception */ public final function __clone() { - throw new PHPExcel_Calculation_Exception ('Cloning a Singleton is not allowed!'); + throw new PHPExcel_Calculation_Exception ('Cloning the calculation engine is not allowed!'); } // function __clone() @@ -1768,10 +1785,10 @@ class PHPExcel_Calculation { ($returnType == self::RETURN_ARRAY_AS_ERROR) || ($returnType == self::RETURN_ARRAY_AS_ARRAY)) { self::$returnArrayAsType = $returnType; - return true; + return TRUE; } - return false; - } // function setExcelCalendar() + return FALSE; + } // function setArrayReturnType() /** @@ -1782,7 +1799,7 @@ class PHPExcel_Calculation { */ public static function getArrayReturnType() { return self::$returnArrayAsType; - } // function getExcelCalendar() + } // function getArrayReturnType() /** @@ -1792,18 +1809,17 @@ class PHPExcel_Calculation { * @return boolean */ public function getCalculationCacheEnabled() { - return self::$_calculationCacheEnabled; + return $this->_calculationCacheEnabled; } // function getCalculationCacheEnabled() - /** * Enable/disable calculation cache * * @access public * @param boolean $pValue */ - public function setCalculationCacheEnabled($pValue = true) { - self::$_calculationCacheEnabled = $pValue; + public function setCalculationCacheEnabled($pValue = TRUE) { + $this->_calculationCacheEnabled = $pValue; $this->clearCalculationCache(); } // function setCalculationCacheEnabled() @@ -1812,7 +1828,7 @@ class PHPExcel_Calculation { * Enable calculation cache */ public function enableCalculationCache() { - $this->setCalculationCacheEnabled(true); + $this->setCalculationCacheEnabled(TRUE); } // function enableCalculationCache() @@ -1820,7 +1836,7 @@ class PHPExcel_Calculation { * Disable calculation cache */ public function disableCalculationCache() { - $this->setCalculationCacheEnabled(false); + $this->setCalculationCacheEnabled(FALSE); } // function disableCalculationCache() @@ -1828,9 +1844,28 @@ class PHPExcel_Calculation { * Clear calculation cache */ public function clearCalculationCache() { - self::$_calculationCache = array(); + $this->_calculationCache = array(); } // function clearCalculationCache() + /** + * Clear calculation cache for a specified worksheet + */ + public function clearCalculationCacheForWorksheet($worksheetName) { + if (isset($this->_calculationCache[$worksheetName])) { + unset($this->_calculationCache[$worksheetName]); + } + } // function clearCalculationCacheForWorksheet() + + /** + * Rename calculation cache for a specified worksheet + */ + public function renameCalculationCacheForWorksheet($fromWorksheetName, $toWorksheetName) { + if (isset($this->_calculationCache[$fromWorksheetName])) { + $this->_calculationCache[$toWorksheetName] = &$this->_calculationCache[$fromWorksheetName]; + unset($this->_calculationCache[$fromWorksheetName]); + } + } // function renameCalculationCacheForWorksheet() + /** * Get the currently defined locale code @@ -1850,7 +1885,7 @@ class PHPExcel_Calculation { public function setLocale($locale='en_us') { // Identify our locale and language $language = $locale = strtolower($locale); - if (strpos($locale,'_') !== false) { + if (strpos($locale,'_') !== FALSE) { list($language) = explode('_',$locale); } @@ -1871,14 +1906,14 @@ class PHPExcel_Calculation { // If there isn't a locale specific function file, look for a language specific function file $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'functions'; if (!file_exists($functionNamesFile)) { - return false; + return FALSE; } } // Retrieve the list of locale or language specific function names $localeFunctions = file($functionNamesFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($localeFunctions as $localeFunction) { list($localeFunction) = explode('##',$localeFunction); // Strip out comments - if (strpos($localeFunction,'=') !== false) { + if (strpos($localeFunction,'=') !== FALSE) { list($fName,$lfName) = explode('=',$localeFunction); $fName = trim($fName); $lfName = trim($lfName); @@ -1899,7 +1934,7 @@ class PHPExcel_Calculation { $localeSettings = file($configFile,FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($localeSettings as $localeSetting) { list($localeSetting) = explode('##',$localeSetting); // Strip out comments - if (strpos($localeSetting,'=') !== false) { + if (strpos($localeSetting,'=') !== FALSE) { list($settingName,$settingValue) = explode('=',$localeSetting); $settingName = strtoupper(trim($settingName)); switch ($settingName) { @@ -1913,11 +1948,11 @@ class PHPExcel_Calculation { } self::$functionReplaceFromExcel = self::$functionReplaceToExcel = - self::$functionReplaceFromLocale = self::$functionReplaceToLocale = null; + self::$functionReplaceFromLocale = self::$functionReplaceToLocale = NULL; self::$_localeLanguage = $locale; - return true; + return TRUE; } - return false; + return FALSE; } // function setLocale() @@ -1927,9 +1962,9 @@ class PHPExcel_Calculation { for ($i = 0; $i < $strlen; ++$i) { $chr = mb_substr($formula,$i,1); switch ($chr) { - case '{' : $inBraces = true; + case '{' : $inBraces = TRUE; break; - case '}' : $inBraces = false; + case '}' : $inBraces = FALSE; break; case $fromSeparator : if (!$inBraces) { @@ -1943,13 +1978,13 @@ class PHPExcel_Calculation { private static function _translateFormula($from,$to,$formula,$fromSeparator,$toSeparator) { // Convert any Excel function names to the required language if (self::$_localeLanguage !== 'en_us') { - $inBraces = false; + $inBraces = FALSE; // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators - if (strpos($formula,'"') !== false) { + if (strpos($formula,'"') !== FALSE) { // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded // the formula $temp = explode('"',$formula); - $i = false; + $i = FALSE; foreach($temp as &$value) { // Only count/replace in alternating array entries if ($i = !$i) { @@ -1970,8 +2005,8 @@ class PHPExcel_Calculation { return $formula; } - private static $functionReplaceFromExcel = null; - private static $functionReplaceToLocale = null; + private static $functionReplaceFromExcel = NULL; + private static $functionReplaceToLocale = NULL; public function _translateFormulaToLocale($formula) { if (self::$functionReplaceFromExcel === NULL) { @@ -1999,8 +2034,8 @@ class PHPExcel_Calculation { } // function _translateFormulaToLocale() - private static $functionReplaceFromLocale = null; - private static $functionReplaceToExcel = null; + private static $functionReplaceFromLocale = NULL; + private static $functionReplaceToExcel = NULL; public function _translateFormulaToEnglish($formula) { if (self::$functionReplaceFromLocale === NULL) { @@ -2096,7 +2131,7 @@ class PHPExcel_Calculation { * @return mixed * @throws PHPExcel_Calculation_Exception */ - public function calculate(PHPExcel_Cell $pCell = null) { + public function calculate(PHPExcel_Cell $pCell = NULL) { try { return $this->calculateCellValue($pCell); } catch (PHPExcel_Exception $e) { @@ -2114,25 +2149,22 @@ class PHPExcel_Calculation { * @return mixed * @throws PHPExcel_Calculation_Exception */ - public function calculateCellValue(PHPExcel_Cell $pCell = null, $resetLog = true) { - if ($resetLog) { - // Initialise the logging settings if requested - $this->formulaError = null; - $this->debugLog = $this->debugLogStack = array(); - $this->_cyclicFormulaCount = 1; - - $returnArrayAsType = self::$returnArrayAsType; - self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY; - } - - // Read the formula from the cell + public function calculateCellValue(PHPExcel_Cell $pCell = NULL, $resetLog = TRUE) { if ($pCell === NULL) { return NULL; } + $returnArrayAsType = self::$returnArrayAsType; if ($resetLog) { - self::$returnArrayAsType = $returnArrayAsType; + // Initialise the logging settings if requested + $this->formulaError = null; + $this->_debugLog->clearLog(); + $this->_cyclicReferenceStack->clear(); + $this->_cyclicFormulaCount = 1; + + self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY; } + // Execute the calculation for the cell formula try { $result = self::_unwrapResult($this->_calculateFormulaValue($pCell->getValue(), $pCell->getCoordinate(), $pCell)); @@ -2141,6 +2173,7 @@ class PHPExcel_Calculation { } if ((is_array($result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) { + self::$returnArrayAsType = $returnArrayAsType; $testResult = PHPExcel_Calculation_Functions::flattenArray($result); if (self::$returnArrayAsType == self::RETURN_ARRAY_AS_ERROR) { return PHPExcel_Calculation_Functions::VALUE(); @@ -2161,6 +2194,8 @@ class PHPExcel_Calculation { } $result = array_shift($testResult); } + self::$returnArrayAsType = $returnArrayAsType; + if ($result === NULL) { return 0; @@ -2198,15 +2233,16 @@ class PHPExcel_Calculation { * @return mixed * @throws PHPExcel_Calculation_Exception */ - public function calculateFormula($formula, $cellID=null, PHPExcel_Cell $pCell = null) { + public function calculateFormula($formula, $cellID=NULL, PHPExcel_Cell $pCell = NULL) { // Initialise the logging settings $this->formulaError = null; - $this->debugLog = $this->debugLogStack = array(); + $this->_debugLog->clearLog(); + $this->_cyclicReferenceStack->clear(); // Disable calculation cacheing because it only applies to cell calculations, not straight formulae // But don't actually flush any cache $resetCache = $this->getCalculationCacheEnabled(); - self::$_calculationCacheEnabled = false; + $this->_calculationCacheEnabled = FALSE; // Execute the calculation try { $result = self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell)); @@ -2215,12 +2251,33 @@ class PHPExcel_Calculation { } // Reset calculation cacheing to its previous state - self::$_calculationCacheEnabled = $resetCache; + $this->_calculationCacheEnabled = $resetCache; return $result; } // function calculateFormula() + public function getValueFromCache($worksheetName, $cellID, &$cellValue) { + // Is calculation cacheing enabled? + // Is the value present in calculation cache? +//echo 'Test cache for ',$worksheetName,'!',$cellID,PHP_EOL; + $this->_debugLog->writeDebugLog('Testing cache value for cell ', $worksheetName, '!', $cellID); + if (($this->_calculationCacheEnabled) && (isset($this->_calculationCache[$worksheetName][$cellID]))) { +//echo 'Retrieve from cache',PHP_EOL; + $this->_debugLog->writeDebugLog('Retrieving value for cell ', $worksheetName, '!', $cellID, ' from cache'); + // Return the cached result + $cellValue = $this->_calculationCache[$worksheetName][$cellID]; + return TRUE; + } + return FALSE; + } + + public function saveValueToCache($worksheetName, $cellID, $cellValue) { + if ($this->_calculationCacheEnabled) { + $this->_calculationCache[$worksheetName][$cellID] = $cellValue; + } + } + /** * Parse a cell formula and calculate its value * @@ -2231,45 +2288,23 @@ class PHPExcel_Calculation { * @throws PHPExcel_Calculation_Exception */ public function _calculateFormulaValue($formula, $cellID=null, PHPExcel_Cell $pCell = null) { -// echo ''.$cellID.'
'; $cellValue = ''; // Basic validation that this is indeed a formula - // We simply return the "cell value" (formula) if not + // We simply return the cell value if not $formula = trim($formula); if ($formula{0} != '=') return self::_wrapResult($formula); $formula = ltrim(substr($formula,1)); if (!isset($formula{0})) return self::_wrapResult($formula); - $wsTitle = "\x00Wrk"; - if ($pCell !== NULL) { - $pCellParent = $pCell->getParent(); - if ($pCellParent !== NULL) { - $wsTitle = $pCellParent->getTitle(); - } - } - // Is calculation cacheing enabled? - if ($cellID !== NULL) { - if (self::$_calculationCacheEnabled) { - // Is the value present in calculation cache? - $this->_writeDebug('Testing cache value for cell ', $cellID); -// echo 'Testing cache value
'; - if (isset(self::$_calculationCache[$wsTitle][$cellID])) { -// echo 'Value is in cache
'; - $this->_writeDebug('Retrieving value for ', $cellID, ' from cache'); - // Return the cached result - $returnValue = self::$_calculationCache[$wsTitle][$cellID]; -// echo 'Retrieving data value of '.$returnValue.' for '.$cellID.' from cache
'; - if (is_array($returnValue)) { - $returnValue = PHPExcel_Calculation_Functions::flattenArray($returnValue); - return array_shift($returnValue); - } - return $returnValue; - } - } + $pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; + $wsTitle = ($pCellParent !== NULL) ? $pCellParent->getTitle() : "\x00Wrk"; + + if (($cellID !== NULL) && ($this->getValueFromCache($wsTitle, $cellID, $cellValue))) { + return $cellValue; } - if ((in_array($wsTitle.'!'.$cellID,$this->debugLogStack)) && ($wsTitle != "\x00Wrk")) { + if (($wsTitle{0} !== "\x00") && ($this->_cyclicReferenceStack->onStack($wsTitle.'!'.$cellID))) { if ($this->cyclicFormulaCount <= 0) { return $this->_raiseFormulaError('Cyclic Reference in Formula'); } elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) && @@ -2287,16 +2322,15 @@ class PHPExcel_Calculation { } } } - $this->debugLogStack[] = $wsTitle.'!'.$cellID; + // Parse the formula onto the token stack and calculate the value + $this->_cyclicReferenceStack->push($wsTitle.'!'.$cellID); $cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell); - array_pop($this->debugLogStack); + $this->_cyclicReferenceStack->pop(); // Save to calculation cache if ($cellID !== NULL) { - if (self::$_calculationCacheEnabled) { - self::$_calculationCache[$wsTitle][$cellID] = $cellValue; - } + $this->saveValueToCache($wsTitle, $cellID, $cellValue); } // Return the calculated value @@ -2457,7 +2491,7 @@ class PHPExcel_Calculation { * @return mixed */ private function _showValue($value) { - if ($this->writeDebugLog) { + if ($this->_debugLog->getWriteDebugLog()) { $testArray = PHPExcel_Calculation_Functions::flattenArray($value); if (count($testArray) == 1) { $value = array_pop($testArray); @@ -2492,7 +2526,7 @@ class PHPExcel_Calculation { * @return mixed */ private function _showTypeDetails($value) { - if ($this->writeDebugLog) { + if ($this->_debugLog->getWriteDebugLog()) { $testArray = PHPExcel_Calculation_Functions::flattenArray($value); if (count($testArray) == 1) { $value = array_pop($testArray); @@ -2527,15 +2561,15 @@ class PHPExcel_Calculation { static $matrixReplaceTo = array('MKMATRIX(MKMATRIX(','),MKMATRIX(','))'); // Convert any Excel matrix references to the MKMATRIX() function - if (strpos($formula,'{') !== false) { + if (strpos($formula,'{') !== FALSE) { // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators - if (strpos($formula,'"') !== false) { + if (strpos($formula,'"') !== FALSE) { // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded // the formula $temp = explode('"',$formula); // Open and Closed counts used for trapping mismatched braces in the formula $openCount = $closeCount = 0; - $i = false; + $i = FALSE; foreach($temp as &$value) { // Only count/replace in alternating array entries if ($i = !$i) { @@ -2578,43 +2612,46 @@ class PHPExcel_Calculation { } // function _mkMatrix() + // Binary Operators + // These operators always work on two values + // Array key is the operator, the value indicates whether this is a left or right associative operator + private static $_operatorAssociativity = array( + '^' => 0, // Exponentiation + '*' => 0, '/' => 0, // Multiplication and Division + '+' => 0, '-' => 0, // Addition and Subtraction + '&' => 0, // Concatenation + '|' => 0, ':' => 0, // Intersect and Range + '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison + ); + + // Comparison (Boolean) Operators + // These operators work on two values, but always return a boolean result + private static $_comparisonOperators = array('>' => TRUE, '<' => TRUE, '=' => TRUE, '>=' => TRUE, '<=' => TRUE, '<>' => TRUE); + + // Operator Precedence + // This list includes all valid operators, whether binary (including boolean) or unary (such as %) + // Array key is the operator, the value is its precedence + private static $_operatorPrecedence = array( + ':' => 8, // Range + '|' => 7, // Intersect + '~' => 6, // Negation + '%' => 5, // Percentage + '^' => 4, // Exponentiation + '*' => 3, '/' => 3, // Multiplication and Division + '+' => 2, '-' => 2, // Addition and Subtraction + '&' => 1, // Concatenation + '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison + ); + // Convert infix to postfix notation - private function _parseFormula($formula, PHPExcel_Cell $pCell = null) { - if (($formula = self::_convertMatrixReferences(trim($formula))) === false) { + private function _parseFormula($formula, PHPExcel_Cell $pCell = NULL) { + if (($formula = self::_convertMatrixReferences(trim($formula))) === FALSE) { return FALSE; } // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet), // so we store the parent worksheet so that we can re-attach it when necessary - $pCellParent = ($pCell !== NULL) ? $pCell->getParent() : NULL; - - // Binary Operators - // These operators always work on two values - // Array key is the operator, the value indicates whether this is a left or right associative operator - $operatorAssociativity = array('^' => 0, // Exponentiation - '*' => 0, '/' => 0, // Multiplication and Division - '+' => 0, '-' => 0, // Addition and Subtraction - '&' => 0, // Concatenation - '|' => 0, ':' => 0, // Intersect and Range - '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison - ); - // Comparison (Boolean) Operators - // These operators work on two values, but always return a boolean result - $comparisonOperators = array('>' => true, '<' => true, '=' => true, '>=' => true, '<=' => true, '<>' => true); - - // Operator Precedence - // This list includes all valid operators, whether binary (including boolean) or unary (such as %) - // Array key is the operator, the value is its precedence - $operatorPrecedence = array(':' => 8, // Range - '|' => 7, // Intersect - '~' => 6, // Negation - '%' => 5, // Percentage - '^' => 4, // Exponentiation - '*' => 3, '/' => 3, // Multiplication and Division - '+' => 2, '-' => 2, // Addition and Subtraction - '&' => 1, // Concatenation - '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison - ); + $pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; $regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION. '|'.self::CALCULATION_REGEXP_NUMBER. @@ -2629,55 +2666,55 @@ class PHPExcel_Calculation { $index = 0; $stack = new PHPExcel_Calculation_Token_Stack; $output = array(); - $expectingOperator = false; // We use this test in syntax-checking the expression to determine when a + $expectingOperator = FALSE; // We use this test in syntax-checking the expression to determine when a // - is a negation or + is a positive operator rather than an operation - $expectingOperand = false; // We use this test in syntax-checking the expression to determine whether an operand + $expectingOperand = FALSE; // We use this test in syntax-checking the expression to determine whether an operand // should be null in a function call // The guts of the lexical parser // Loop through the formula extracting each operator and operand in turn - while(true) { -// echo 'Assessing Expression '.substr($formula, $index).'
'; + while(TRUE) { +//echo 'Assessing Expression '.substr($formula, $index),PHP_EOL; $opCharacter = $formula{$index}; // Get the first character of the value at the current index position -// echo 'Initial character of expression block is '.$opCharacter.'
'; - if ((isset($comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset($comparisonOperators[$formula{$index+1}]))) { +//echo 'Initial character of expression block is '.$opCharacter,PHP_EOL; + if ((isset(self::$_comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$_comparisonOperators[$formula{$index+1}]))) { $opCharacter .= $formula{++$index}; -// echo 'Initial character of expression block is comparison operator '.$opCharacter.'
'; +//echo 'Initial character of expression block is comparison operator '.$opCharacter.PHP_EOL; } // Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match); -// echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').'
'; -// var_dump($match); +//echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').PHP_EOL; +//var_dump($match); if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus? -// echo 'Element is a Negation operator
'; +//echo 'Element is a Negation operator',PHP_EOL; $stack->push('Unary Operator','~'); // Put a negation on the stack ++$index; // and drop the negation symbol } elseif ($opCharacter == '%' && $expectingOperator) { -// echo 'Element is a Percentage operator
'; +//echo 'Element is a Percentage operator',PHP_EOL; $stack->push('Unary Operator','%'); // Put a percentage on the stack ++$index; } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded? -// echo 'Element is a Positive number, not Plus operator
'; +//echo 'Element is a Positive number, not Plus operator',PHP_EOL; ++$index; // Drop the redundant plus symbol } elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) { // We have to explicitly deny a tilde or pipe, because they are legal return $this->_raiseFormulaError("Formula Error: Illegal character '~'"); // on the stack but not in the input expression } elseif ((isset(self::$_operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack? -// echo 'Element with value '.$opCharacter.' is an Operator
'; +//echo 'Element with value '.$opCharacter.' is an Operator',PHP_EOL; while($stack->count() > 0 && ($o2 = $stack->last()) && isset(self::$_operators[$o2['value']]) && - @($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) { + @(self::$_operatorAssociativity[$opCharacter] ? self::$_operatorPrecedence[$opCharacter] < self::$_operatorPrecedence[$o2['value']] : self::$_operatorPrecedence[$opCharacter] <= self::$_operatorPrecedence[$o2['value']])) { $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output } $stack->push('Binary Operator',$opCharacter); // Finally put our current operator onto the stack ++$index; - $expectingOperator = false; + $expectingOperator = FALSE; } elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis? -// echo 'Element is a Closing bracket
'; - $expectingOperand = false; +//echo 'Element is a Closing bracket',PHP_EOL; + $expectingOperand = FALSE; while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last ( if ($o2 === NULL) return $this->_raiseFormulaError('Formula Error: Unexpected closing brace ")"'); else $output[] = $o2; @@ -2685,65 +2722,65 @@ class PHPExcel_Calculation { $d = $stack->last(2); if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) { // Did this parenthesis just close a function? $functionName = $matches[1]; // Get the function name -// echo 'Closed Function is '.$functionName.'
'; +//echo 'Closed Function is '.$functionName,PHP_EOL; $d = $stack->pop(); $argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack) -// if ($argumentCount == 0) { -// echo 'With no arguments
'; -// } elseif ($argumentCount == 1) { -// echo 'With 1 argument
'; -// } else { -// echo 'With '.$argumentCount.' arguments
'; -// } +//if ($argumentCount == 0) { +// echo 'With no arguments',PHP_EOL; +//} elseif ($argumentCount == 1) { +// echo 'With 1 argument',PHP_EOL; +//} else { +// echo 'With '.$argumentCount.' arguments',PHP_EOL; +//} $output[] = $d; // Dump the argument count on the output $output[] = $stack->pop(); // Pop the function and push onto the output if (isset(self::$_controlFunctions[$functionName])) { -// echo 'Built-in function '.$functionName.'
'; +//echo 'Built-in function '.$functionName,PHP_EOL; $expectedArgumentCount = self::$_controlFunctions[$functionName]['argumentCount']; $functionCall = self::$_controlFunctions[$functionName]['functionCall']; } elseif (isset(self::$_PHPExcelFunctions[$functionName])) { -// echo 'PHPExcel function '.$functionName.'
'; +//echo 'PHPExcel function '.$functionName,PHP_EOL; $expectedArgumentCount = self::$_PHPExcelFunctions[$functionName]['argumentCount']; $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall']; } else { // did we somehow push a non-function on the stack? this should never happen return $this->_raiseFormulaError("Formula Error: Internal error, non-function on stack"); } // Check the argument count - $argumentCountError = false; + $argumentCountError = FALSE; if (is_numeric($expectedArgumentCount)) { if ($expectedArgumentCount < 0) { -// echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount).'
'; +//echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount),PHP_EOL; if ($argumentCount > abs($expectedArgumentCount)) { - $argumentCountError = true; + $argumentCountError = TRUE; $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount); } } else { -// echo '$expectedArgumentCount is numeric '.$expectedArgumentCount.'
'; +//echo '$expectedArgumentCount is numeric '.$expectedArgumentCount,PHP_EOL; if ($argumentCount != $expectedArgumentCount) { - $argumentCountError = true; + $argumentCountError = TRUE; $expectedArgumentCountString = $expectedArgumentCount; } } } elseif ($expectedArgumentCount != '*') { $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/',$expectedArgumentCount,$argMatch); -// print_r($argMatch); -// echo '
'; +//print_r($argMatch); +//echo PHP_EOL; switch ($argMatch[2]) { case '+' : if ($argumentCount < $argMatch[1]) { - $argumentCountError = true; + $argumentCountError = TRUE; $expectedArgumentCountString = $argMatch[1].' or more '; } break; case '-' : if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) { - $argumentCountError = true; + $argumentCountError = TRUE; $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3]; } break; case ',' : if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) { - $argumentCountError = true; + $argumentCountError = TRUE; $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3]; } break; @@ -2756,7 +2793,7 @@ class PHPExcel_Calculation { ++$index; } elseif ($opCharacter == ',') { // Is this the separator for function arguments? -// echo 'Element is a Function argument separator
'; +//echo 'Element is a Function argument separator',PHP_EOL; while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last ( if ($o2 === NULL) return $this->_raiseFormulaError("Formula Error: Unexpected ,"); else $output[] = $o2; // pop the argument expression stuff and push onto the output @@ -2764,7 +2801,7 @@ class PHPExcel_Calculation { // If we've a comma when we're expecting an operand, then what we actually have is a null operand; // so push a null onto the stack if (($expectingOperand) || (!$expectingOperator)) { - $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null); + $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => NULL); } // make sure there was a function $d = $stack->last(2); @@ -2773,8 +2810,8 @@ class PHPExcel_Calculation { $d = $stack->pop(); $stack->push($d['type'],++$d['value'],$d['reference']); // increment the argument count $stack->push('Brace', '('); // put the ( back on, we'll need to pop back to it again - $expectingOperator = false; - $expectingOperand = true; + $expectingOperator = FALSE; + $expectingOperand = TRUE; ++$index; } elseif ($opCharacter == '(' && !$expectingOperator) { @@ -2783,8 +2820,8 @@ class PHPExcel_Calculation { ++$index; } elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number? - $expectingOperator = true; - $expectingOperand = false; + $expectingOperator = TRUE; + $expectingOperand = FALSE; $val = $match[1]; $length = strlen($val); // echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function
'; @@ -2797,14 +2834,14 @@ class PHPExcel_Calculation { $ax = preg_match('/^\s*(\s*\))/i', substr($formula, $index+$length), $amatch); if ($ax) { $stack->push('Operand Count for Function '.strtoupper($val).')', 0); - $expectingOperator = true; + $expectingOperator = TRUE; } else { $stack->push('Operand Count for Function '.strtoupper($val).')', 1); - $expectingOperator = false; + $expectingOperator = FALSE; } $stack->push('Brace', '('); } else { // it's a var w/ implicit multiplication - $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => null); + $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => NULL); } } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) { // echo 'Element '.$val.' is a Cell reference
'; @@ -2829,7 +2866,7 @@ class PHPExcel_Calculation { } $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val); -// $expectingOperator = false; +// $expectingOperator = FALSE; } else { // it's a variable, constant, string, number or boolean // echo 'Element is a Variable, Constant, String, Number or Boolean
'; // If the last entry on the stack was a : operator, then we may have a row or column range reference @@ -2837,12 +2874,12 @@ class PHPExcel_Calculation { if ($testPrevOp['value'] == ':') { $startRowColRef = $output[count($output)-1]['value']; $rangeWS1 = ''; - if (strpos('!',$startRowColRef) !== false) { + if (strpos('!',$startRowColRef) !== FALSE) { list($rangeWS1,$startRowColRef) = explode('!',$startRowColRef); } if ($rangeWS1 != '') $rangeWS1 .= '!'; $rangeWS2 = $rangeWS1; - if (strpos('!',$val) !== false) { + if (strpos('!',$val) !== FALSE) { list($rangeWS2,$val) = explode('!',$val); } if ($rangeWS2 != '') $rangeWS2 .= '!'; @@ -2861,14 +2898,14 @@ class PHPExcel_Calculation { } } - $localeConstant = false; + $localeConstant = FALSE; if ($opCharacter == '"') { // echo 'Element is a String
'; // UnEscape any quotes within the string $val = self::_wrapResult(str_replace('""','"',self::_unwrapResult($val))); } elseif (is_numeric($val)) { // echo 'Element is a Number
'; - if ((strpos($val,'.') !== false) || (stripos($val,'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) { + if ((strpos($val,'.') !== FALSE) || (stripos($val,'e') !== FALSE) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) { // echo 'Casting '.$val.' to float
'; $val = (float) $val; } else { @@ -2879,11 +2916,11 @@ class PHPExcel_Calculation { $excelConstant = trim(strtoupper($val)); // echo 'Element '.$excelConstant.' is an Excel Constant
'; $val = self::$_ExcelConstants[$excelConstant]; - } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$_localeBoolean)) !== false) { + } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$_localeBoolean)) !== FALSE) { // echo 'Element '.$localeConstant.' is an Excel Constant
'; $val = self::$_ExcelConstants[$localeConstant]; } - $details = array('type' => 'Value', 'value' => $val, 'reference' => null); + $details = array('type' => 'Value', 'value' => $val, 'reference' => NULL); if ($localeConstant) { $details['localeValue'] = $localeConstant; } $output[] = $details; } @@ -2893,9 +2930,9 @@ class PHPExcel_Calculation { ++$index; } elseif ($opCharacter == ')') { // miscellaneous error checking if ($expectingOperand) { - $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null); - $expectingOperand = false; - $expectingOperator = true; + $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => NULL); + $expectingOperand = FALSE; + $expectingOperator = TRUE; } else { return $this->_raiseFormulaError("Formula Error: Unexpected ')'"); } @@ -2931,11 +2968,11 @@ class PHPExcel_Calculation { while($stack->count() > 0 && ($o2 = $stack->last()) && isset(self::$_operators[$o2['value']]) && - @($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) { + @(self::$_operatorAssociativity[$opCharacter] ? self::$_operatorPrecedence[$opCharacter] < self::$_operatorPrecedence[$o2['value']] : self::$_operatorPrecedence[$opCharacter] <= self::$_operatorPrecedence[$o2['value']])) { $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output } $stack->push('Binary Operator','|'); // Put an Intersect Operator on the stack - $expectingOperator = false; + $expectingOperator = FALSE; } } } @@ -2965,11 +3002,12 @@ class PHPExcel_Calculation { } // evaluate postfix notation - private function _processTokenStack($tokens, $cellID = null, PHPExcel_Cell $pCell = null) { - if ($tokens == false) return false; + private function _processTokenStack($tokens, $cellID = NULL, PHPExcel_Cell $pCell = NULL) { + if ($tokens == FALSE) return FALSE; - // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet), - // so we store the parent worksheet so that we can re-attach it when necessary + // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent cell collection), + // so we store the parent cell collection so that we can re-attach it when necessary + $pCellWorksheet = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; $pCellParent = ($pCell !== NULL) ? $pCell->getParent() : null; $stack = new PHPExcel_Calculation_Token_Stack; @@ -2991,9 +3029,9 @@ class PHPExcel_Calculation { // Log what we're doing if ($token == ':') { - $this->_writeDebug('Evaluating Range ', $this->_showValue($operand1Data['reference']), ' ', $token, ' ', $this->_showValue($operand2Data['reference'])); + $this->_debugLog->writeDebugLog('Evaluating Range ', $this->_showValue($operand1Data['reference']), ' ', $token, ' ', $this->_showValue($operand2Data['reference'])); } else { - $this->_writeDebug('Evaluating ', $this->_showValue($operand1), ' ', $token, ' ', $this->_showValue($operand2)); + $this->_debugLog->writeDebugLog('Evaluating ', $this->_showValue($operand1), ' ', $token, ' ', $this->_showValue($operand2)); } // Process the operation in the appropriate manner @@ -3010,12 +3048,12 @@ class PHPExcel_Calculation { // Binary Operators case ':' : // Range $sheet1 = $sheet2 = ''; - if (strpos($operand1Data['reference'],'!') !== false) { + if (strpos($operand1Data['reference'],'!') !== FALSE) { list($sheet1,$operand1Data['reference']) = explode('!',$operand1Data['reference']); } else { - $sheet1 = ($pCellParent !== NULL) ? $pCellParent->getTitle() : ''; + $sheet1 = ($pCellParent !== NULL) ? $pCellWorksheet->getTitle() : ''; } - if (strpos($operand2Data['reference'],'!') !== false) { + if (strpos($operand2Data['reference'],'!') !== FALSE) { list($sheet2,$operand2Data['reference']) = explode('!',$operand2Data['reference']); } else { $sheet2 = $sheet1; @@ -3049,13 +3087,13 @@ class PHPExcel_Calculation { } $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow); if ($pCellParent !== NULL) { - $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($sheet1), false); + $cellValue = $this->extractCellRange($cellRef, $this->_workbook->getSheetByName($sheet1), FALSE); } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } $stack->push('Cell Reference',$cellValue,$cellRef); } else { - $stack->push('Error',PHPExcel_Calculation_Functions::REF(),null); + $stack->push('Error',PHPExcel_Calculation_Functions::REF(),NULL); } break; @@ -3094,13 +3132,13 @@ class PHPExcel_Calculation { $matrixResult = $matrix->concat($operand2); $result = $matrixResult->getArray(); } catch (PHPExcel_Exception $ex) { - $this->_writeDebug('JAMA Matrix Exception: ', $ex->getMessage()); + $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage()); $result = '#VALUE!'; } } else { $result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"'; } - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); $stack->push('Value',$result); break; case '|' : // Intersect @@ -3114,7 +3152,7 @@ class PHPExcel_Calculation { } } $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow); - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($cellIntersect)); + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($cellIntersect)); $stack->push('Value',$cellIntersect,$cellRef); break; } @@ -3126,11 +3164,11 @@ class PHPExcel_Calculation { $arg = $arg['value']; if ($token === '~') { // echo 'Token is a negation operator
'; - $this->_writeDebug('Evaluating Negation of ', $this->_showValue($arg)); + $this->_debugLog->writeDebugLog('Evaluating Negation of ', $this->_showValue($arg)); $multiplier = -1; } else { // echo 'Token is a percentile operator
'; - $this->_writeDebug('Evaluating Percentile of ', $this->_showValue($arg)); + $this->_debugLog->writeDebugLog('Evaluating Percentile of ', $this->_showValue($arg)); $multiplier = 0.01; } if (is_array($arg)) { @@ -3140,17 +3178,17 @@ class PHPExcel_Calculation { $matrixResult = $matrix1->arrayTimesEquals($multiplier); $result = $matrixResult->getArray(); } catch (PHPExcel_Exception $ex) { - $this->_writeDebug('JAMA Matrix Exception: ', $ex->getMessage()); + $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage()); $result = '#VALUE!'; } - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); $stack->push('Value',$result); } else { $this->_executeNumericBinaryOperation($cellID,$multiplier,$arg,'*','arrayTimesEquals',$stack); } } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $token, $matches)) { - $cellRef = null; + $cellRef = NULL; // echo 'Element '.$token.' is a Cell reference
'; if (isset($matches[8])) { // echo 'Reference is a Range of cells
'; @@ -3161,29 +3199,29 @@ class PHPExcel_Calculation { $cellRef = $matches[6].$matches[7].':'.$matches[9].$matches[10]; if ($matches[2] > '') { $matches[2] = trim($matches[2],"\"'"); - if ((strpos($matches[2],'[') !== false) || (strpos($matches[2],']') !== false)) { + if ((strpos($matches[2],'[') !== FALSE) || (strpos($matches[2],']') !== FALSE)) { // It's a Reference to an external workbook (not currently supported) return $this->_raiseFormulaError('Unable to access External Workbook'); } $matches[2] = trim($matches[2],"\"'"); // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'
'; - $this->_writeDebug('Evaluating Cell Range ', $cellRef, ' in worksheet ', $matches[2]); + $this->_debugLog->writeDebugLog('Evaluating Cell Range ', $cellRef, ' in worksheet ', $matches[2]); if ($pCellParent !== NULL) { - $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false); + $cellValue = $this->extractCellRange($cellRef, $this->_workbook->getSheetByName($matches[2]), FALSE); } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cells ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); + $this->_debugLog->writeDebugLog('Evaluation Result for cells ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); // $cellRef = $matches[2].'!'.$cellRef; } else { // echo '$cellRef='.$cellRef.' in current worksheet
'; - $this->_writeDebug('Evaluating Cell Range ', $cellRef, ' in current worksheet'); + $this->_debugLog->writeDebugLog('Evaluating Cell Range ', $cellRef, ' in current worksheet'); if ($pCellParent !== NULL) { - $cellValue = $this->extractCellRange($cellRef, $pCellParent, false); + $cellValue = $this->extractCellRange($cellRef, $pCellWorksheet, FALSE); } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cells ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); + $this->_debugLog->writeDebugLog('Evaluation Result for cells ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); } } } else { @@ -3195,34 +3233,34 @@ class PHPExcel_Calculation { $cellRef = $matches[6].$matches[7]; if ($matches[2] > '') { $matches[2] = trim($matches[2],"\"'"); - if ((strpos($matches[2],'[') !== false) || (strpos($matches[2],']') !== false)) { + if ((strpos($matches[2],'[') !== FALSE) || (strpos($matches[2],']') !== FALSE)) { // It's a Reference to an external workbook (not currently supported) return $this->_raiseFormulaError('Unable to access External Workbook'); } // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'
'; - $this->_writeDebug('Evaluating Cell ', $cellRef, ' in worksheet ', $matches[2]); + $this->_debugLog->writeDebugLog('Evaluating Cell ', $cellRef, ' in worksheet ', $matches[2]); if ($pCellParent !== NULL) { - if ($pCellParent->getParent()->getSheetByName($matches[2])->cellExists($cellRef)) { - $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false); + if ($this->_workbook->getSheetByName($matches[2])->cellExists($cellRef)) { + $cellValue = $this->extractCellRange($cellRef, $this->_workbook->getSheetByName($matches[2]), FALSE); $pCell->attach($pCellParent); } else { - $cellValue = null; + $cellValue = NULL; } } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cell ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); + $this->_debugLog->writeDebugLog('Evaluation Result for cell ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); // $cellRef = $matches[2].'!'.$cellRef; } else { // echo '$cellRef='.$cellRef.' in current worksheet
'; - $this->_writeDebug('Evaluating Cell ', $cellRef, ' in current worksheet'); - if ($pCellParent->cellExists($cellRef)) { - $cellValue = $this->extractCellRange($cellRef, $pCellParent, false); + $this->_debugLog->writeDebugLog('Evaluating Cell ', $cellRef, ' in current worksheet'); + if ($pCellParent->isDataSet($cellRef)) { + $cellValue = $this->extractCellRange($cellRef, $pCellWorksheet, FALSE); $pCell->attach($pCellParent); } else { - $cellValue = null; + $cellValue = NULL; } - $this->_writeDebug('Evaluation Result for cell ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); + $this->_debugLog->writeDebugLog('Evaluation Result for cell ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); } } } @@ -3235,7 +3273,7 @@ class PHPExcel_Calculation { $argCount = $stack->pop(); $argCount = $argCount['value']; if ($functionName != 'MKMATRIX') { - $this->_writeDebug('Evaluating Function ', self::_localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's')); + $this->_debugLog->writeDebugLog('Evaluating Function ', self::_localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's')); } if ((isset(self::$_PHPExcelFunctions[$functionName])) || (isset(self::$_controlFunctions[$functionName]))) { // function if (isset(self::$_PHPExcelFunctions[$functionName])) { @@ -3278,30 +3316,30 @@ class PHPExcel_Calculation { // print_r($args); // echo '
'; if ($functionName != 'MKMATRIX') { - if ($this->writeDebugLog) { + if ($this->_debugLog->getWriteDebugLog()) { krsort($argArrayVals); - $this->_writeDebug('Evaluating ', self::_localeFunc($functionName), '( ', implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)), ' )'); + $this->_debugLog->writeDebugLog('Evaluating ', self::_localeFunc($functionName), '( ', implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)), ' )'); } } // Process each argument in turn, building the return value as an array // if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) { // $operand1 = $args[1]; -// $this->_writeDebug('Argument is a matrix: ', $this->_showValue($operand1)); +// $this->_debugLog->writeDebugLog('Argument is a matrix: ', $this->_showValue($operand1)); // $result = array(); // $row = 0; // foreach($operand1 as $args) { // if (is_array($args)) { // foreach($args as $arg) { -// $this->_writeDebug('Evaluating ', self::_localeFunc($functionName), '( ', $this->_showValue($arg), ' )'); +// $this->_debugLog->writeDebugLog('Evaluating ', self::_localeFunc($functionName), '( ', $this->_showValue($arg), ' )'); // $r = call_user_func_array($functionCall,$arg); -// $this->_writeDebug('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); +// $this->_debugLog->writeDebugLog('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); // $result[$row][] = $r; // } // ++$row; // } else { -// $this->_writeDebug('Evaluating ', self::_localeFunc($functionName), '( ', $this->_showValue($args), ' )'); +// $this->_debugLog->writeDebugLog('Evaluating ', self::_localeFunc($functionName), '( ', $this->_showValue($args), ' )'); // $r = call_user_func_array($functionCall,$args); -// $this->_writeDebug('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); +// $this->_debugLog->writeDebugLog('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); // $result[] = $r; // } // } @@ -3310,7 +3348,7 @@ class PHPExcel_Calculation { if ($passCellReference) { $args[] = $pCell; } - if (strpos($functionCall,'::') !== false) { + if (strpos($functionCall,'::') !== FALSE) { $result = call_user_func_array(explode('::',$functionCall),$args); } else { foreach($args as &$arg) { @@ -3321,7 +3359,7 @@ class PHPExcel_Calculation { } // } if ($functionName != 'MKMATRIX') { - $this->_writeDebug('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($result)); + $this->_debugLog->writeDebugLog('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($result)); } $stack->push('Value',self::_wrapResult($result)); } @@ -3332,7 +3370,7 @@ class PHPExcel_Calculation { $excelConstant = strtoupper($token); // echo 'Token is a PHPExcel constant: '.$excelConstant.'
'; $stack->push('Constant Value',self::$_ExcelConstants[$excelConstant]); - $this->_writeDebug('Evaluating Constant ', $excelConstant, ' as ', $this->_showTypeDetails(self::$_ExcelConstants[$excelConstant])); + $this->_debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->_showTypeDetails(self::$_ExcelConstants[$excelConstant])); } elseif ((is_numeric($token)) || ($token === NULL) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) { // echo 'Token is a number, boolean, string, null or an Excel error
'; $stack->push('Value',$token); @@ -3341,10 +3379,10 @@ class PHPExcel_Calculation { // echo 'Token is a named range
'; $namedRange = $matches[6]; // echo 'Named Range is '.$namedRange.'
'; - $this->_writeDebug('Evaluating Named Range ', $namedRange); - $cellValue = $this->extractNamedRange($namedRange, ((null !== $pCell) ? $pCellParent : null), false); + $this->_debugLog->writeDebugLog('Evaluating Named Range ', $namedRange); + $cellValue = $this->extractNamedRange($namedRange, ((NULL !== $pCell) ? $pCellWorksheet : NULL), FALSE); $pCell->attach($pCellParent); - $this->_writeDebug('Evaluation Result for named range ', $namedRange, ' is ', $this->_showTypeDetails($cellValue)); + $this->_debugLog->writeDebugLog('Evaluation Result for named range ', $namedRange, ' is ', $this->_showTypeDetails($cellValue)); $stack->push('Named Range',$cellValue,$namedRange); } else { return $this->_raiseFormulaError("undefined variable '$token'"); @@ -3363,7 +3401,7 @@ class PHPExcel_Calculation { } // function _processTokenStack() - private function _validateBinaryOperand($cellID,&$operand,&$stack) { + private function _validateBinaryOperand($cellID, &$operand, &$stack) { // Numbers, matrices and booleans can pass straight through, as they're already valid if (is_string($operand)) { // We only need special validations for the operand if it is a string @@ -3374,36 +3412,36 @@ class PHPExcel_Calculation { // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations if ($operand > '' && $operand{0} == '#') { $stack->push('Value', $operand); - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($operand)); - return false; + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($operand)); + return FALSE; } elseif (!PHPExcel_Shared_String::convertToNumberIfFraction($operand)) { // If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations $stack->push('Value', '#VALUE!'); - $this->_writeDebug('Evaluation Result is a ', $this->_showTypeDetails('#VALUE!')); - return false; + $this->_debugLog->writeDebugLog('Evaluation Result is a ', $this->_showTypeDetails('#VALUE!')); + return FALSE; } } } // return a true if the value of the operand is one that we can use in normal binary operations - return true; + return TRUE; } // function _validateBinaryOperand() - private function _executeBinaryComparisonOperation($cellID,$operand1,$operand2,$operation,&$stack,$recursingArrays=false) { + private function _executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, &$stack, $recursingArrays=FALSE) { // If we're dealing with matrix operations, we want a matrix result if ((is_array($operand1)) || (is_array($operand2))) { $result = array(); if ((is_array($operand1)) && (!is_array($operand2))) { foreach($operand1 as $x => $operandData) { - $this->_writeDebug('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2)); + $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2)); $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2,$operation,$stack); $r = $stack->pop(); $result[$x] = $r['value']; } } elseif ((!is_array($operand1)) && (is_array($operand2))) { foreach($operand2 as $x => $operandData) { - $this->_writeDebug('Evaluating Comparison ', $this->_showValue($operand1), ' ', $operation, ' ', $this->_showValue($operandData)); + $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->_showValue($operand1), ' ', $operation, ' ', $this->_showValue($operandData)); $this->_executeBinaryComparisonOperation($cellID,$operand1,$operandData,$operation,$stack); $r = $stack->pop(); $result[$x] = $r['value']; @@ -3411,17 +3449,17 @@ class PHPExcel_Calculation { } else { if (!$recursingArrays) { self::_checkMatrixOperands($operand1,$operand2,2); } foreach($operand1 as $x => $operandData) { - $this->_writeDebug('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2[$x])); - $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,true); + $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2[$x])); + $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,TRUE); $r = $stack->pop(); $result[$x] = $r['value']; } } // Log the result details - $this->_writeDebug('Comparison Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Array',$result); - return true; + return TRUE; } // Simple validate the two operands if they are string values @@ -3457,31 +3495,31 @@ class PHPExcel_Calculation { } // Log the result details - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Value',$result); - return true; + return TRUE; } // function _executeBinaryComparisonOperation() private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) { // Validate the two operands - if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return false; - if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return false; + if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return FALSE; + if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return FALSE; - $executeMatrixOperation = false; + $executeMatrixOperation = FALSE; // If either of the operands is a matrix, we need to treat them both as matrices // (converting the other operand to a matrix if need be); then perform the required // matrix operation if ((is_array($operand1)) || (is_array($operand2))) { // Ensure that both operands are arrays/matrices - $executeMatrixOperation = true; + $executeMatrixOperation = TRUE; $mSize = array(); list($mSize[],$mSize[],$mSize[],$mSize[]) = self::_checkMatrixOperands($operand1,$operand2,2); // But if they're both single cell matrices, then we can treat them as simple values if (array_sum($mSize) == 4) { - $executeMatrixOperation = false; + $executeMatrixOperation = FALSE; $operand1 = $operand1[0][0]; $operand2 = $operand2[0][0]; } @@ -3495,7 +3533,7 @@ class PHPExcel_Calculation { $matrixResult = $matrix->$matrixFunction($operand2); $result = $matrixResult->getArray(); } catch (PHPExcel_Exception $ex) { - $this->_writeDebug('JAMA Matrix Exception: ', $ex->getMessage()); + $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage()); $result = '#VALUE!'; } } else { @@ -3522,8 +3560,8 @@ class PHPExcel_Calculation { if ($operand2 == 0) { // Trap for Divide by Zero error $stack->push('Value','#DIV/0!'); - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails('#DIV/0!')); - return false; + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails('#DIV/0!')); + return FALSE; } else { $result = $operand1/$operand2; } @@ -3537,29 +3575,17 @@ class PHPExcel_Calculation { } // Log the result details - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Value',$result); - return true; + return TRUE; } // function _executeNumericBinaryOperation() - private function _writeDebug() { - // Only write the debug log if logging is enabled - if ($this->writeDebugLog) { - $message = implode('',func_get_args()); - if ($this->echoDebugLog) { - echo implode(' -> ',$this->debugLogStack).' -> '.$message,'
'; - } - $this->debugLog[] = implode(' -> ',$this->debugLogStack).' -> '.$message; - } - } // function _writeDebug() - - // trigger an error, but nicely, if need be protected function _raiseFormulaError($errorMessage) { $this->formulaError = $errorMessage; - $this->debugLogStack = array(); + $this->_cyclicReferenceStack->clear(); if (!$this->suppressFormulaErrors) throw new PHPExcel_Calculation_Exception($errorMessage); trigger_error($errorMessage, E_USER_ERROR); } // function _raiseFormulaError() @@ -3573,44 +3599,45 @@ class PHPExcel_Calculation { * @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned. * @throws PHPExcel_Calculation_Exception */ - public function extractCellRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) { + public function extractCellRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = NULL, $resetLog=TRUE) { // Return value $returnValue = array (); -// echo 'extractCellRange('.$pRange.')
'; +// echo 'extractCellRange('.$pRange.')',PHP_EOL; if ($pSheet !== NULL) { -// echo 'Passed sheet name is '.$pSheet->getTitle().'
'; -// echo 'Range reference is '.$pRange.'
'; + $pSheetName = $pSheet->getTitle(); +// echo 'Passed sheet name is '.$pSheetName.PHP_EOL; +// echo 'Range reference is '.$pRange.PHP_EOL; if (strpos ($pRange, '!') !== false) { -// echo '$pRange reference includes sheet reference
'; - $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true); - $pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]); -// echo 'New sheet name is '.$pSheet->getTitle().'
'; - $pRange = $worksheetReference[1]; -// echo 'Adjusted Range reference is '.$pRange.'
'; +// echo '$pRange reference includes sheet reference',PHP_EOL; + list($pSheetName,$pRange) = PHPExcel_Worksheet::extractSheetTitle($pRange, true); +// echo 'New sheet name is '.$pSheetName,PHP_EOL; +// echo 'Adjusted Range reference is '.$pRange,PHP_EOL; + $pSheet = $this->_workbook->getSheetByName($pSheetName); } // Extract range $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange); - $pRange = $pSheet->getTitle().'!'.$pRange; + $pRange = $pSheetName.'!'.$pRange; if (!isset($aReferences[1])) { // Single cell in range list($currentCol,$currentRow) = sscanf($aReferences[0],'%[A-Z]%d'); + $cellValue = NULL; if ($pSheet->cellExists($aReferences[0])) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = null; + $returnValue[$currentRow][$currentCol] = NULL; } } else { // Extract cell data for all cells in the range foreach ($aReferences as $reference) { // Extract range list($currentCol,$currentRow) = sscanf($reference,'%[A-Z]%d'); - + $cellValue = NULL; if ($pSheet->cellExists($reference)) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = null; + $returnValue[$currentRow][$currentCol] = NULL; } } } @@ -3629,21 +3656,21 @@ class PHPExcel_Calculation { * @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned. * @throws PHPExcel_Calculation_Exception */ - public function extractNamedRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) { + public function extractNamedRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = NULL, $resetLog=TRUE) { // Return value $returnValue = array (); // echo 'extractNamedRange('.$pRange.')
'; if ($pSheet !== NULL) { -// echo 'Current sheet name is '.$pSheet->getTitle().'
'; + $pSheetName = $pSheet->getTitle(); +// echo 'Current sheet name is '.$pSheetName.'
'; // echo 'Range reference is '.$pRange.'
'; if (strpos ($pRange, '!') !== false) { -// echo '$pRange reference includes sheet reference
'; - $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true); - $pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]); -// echo 'New sheet name is '.$pSheet->getTitle().'
'; - $pRange = $worksheetReference[1]; -// echo 'Adjusted Range reference is '.$pRange.'
'; +// echo '$pRange reference includes sheet reference',PHP_EOL; + list($pSheetName,$pRange) = PHPExcel_Worksheet::extractSheetTitle($pRange, true); +// echo 'New sheet name is '.$pSheetName,PHP_EOL; +// echo 'Adjusted Range reference is '.$pRange,PHP_EOL; + $pSheet = $this->_workbook->getSheetByName($pSheetName); } // Named range? @@ -3678,10 +3705,11 @@ class PHPExcel_Calculation { if (!isset($aReferences[1])) { // Single cell (or single column or row) in range list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]); + $cellValue = NULL; if ($pSheet->cellExists($aReferences[0])) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = null; + $returnValue[$currentRow][$currentCol] = NULL; } } else { // Extract cell data for all cells in the range @@ -3689,10 +3717,11 @@ class PHPExcel_Calculation { // Extract range list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference); // echo 'NAMED RANGE: $currentCol='.$currentCol.' $currentRow='.$currentRow.'
'; + $cellValue = NULL; if ($pSheet->cellExists($reference)) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = null; + $returnValue[$currentRow][$currentCol] = NULL; } } } @@ -3716,7 +3745,7 @@ class PHPExcel_Calculation { if (isset(self::$_PHPExcelFunctions[$pFunction])) { return (self::$_PHPExcelFunctions[$pFunction]['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY'); } else { - return false; + return FALSE; } } // function isImplemented() diff --git a/Classes/PHPExcel/Calculation/Token/Stack.php b/Classes/PHPExcel/Calculation/Token/Stack.php index 081a38dc..bdf9d555 100644 --- a/Classes/PHPExcel/Calculation/Token/Stack.php +++ b/Classes/PHPExcel/Calculation/Token/Stack.php @@ -67,7 +67,9 @@ class PHPExcel_Calculation_Token_Stack { } // function last() - function __construct() { + function clear() { + $this->_stack = array(); + $this->_count = 0; } } // class PHPExcel_Calculation_Token_Stack diff --git a/Classes/PHPExcel/Cell.php b/Classes/PHPExcel/Cell.php index 2e9cd327..cbaddc15 100644 --- a/Classes/PHPExcel/Cell.php +++ b/Classes/PHPExcel/Cell.php @@ -50,13 +50,6 @@ class PHPExcel_Cell */ private static $_valueBinder = NULL; - /** - * Cell Address (e.g. A1) - * - * @var string - */ - private $_coordinate; - /** * Value of the cell * @@ -86,7 +79,7 @@ class PHPExcel_Cell /** * Parent worksheet * - * @var PHPExcel_Worksheet + * @var PHPExcel_CachedObjectStorage_CacheBase */ private $_parent; @@ -110,7 +103,8 @@ class PHPExcel_Cell * @return void **/ public function notifyCacheController() { - $this->_parent->getCellCacheController()->updateCacheData($this); + $this->_parent->updateCacheData($this); + return $this; } @@ -118,7 +112,9 @@ class PHPExcel_Cell $this->_parent = NULL; } - public function attach($parent) { + public function attach(PHPExcel_CachedObjectStorage_CacheBase $parent) { + + $this->_parent = $parent; } @@ -126,23 +122,18 @@ class PHPExcel_Cell /** * Create a new Cell * - * @param string $pColumn - * @param int $pRow * @param mixed $pValue * @param string $pDataType * @param PHPExcel_Worksheet $pSheet * @throws PHPExcel_Exception */ - public function __construct($pCoordinate = 'A1', $pValue = NULL, $pDataType = NULL, PHPExcel_Worksheet $pSheet = NULL) + public function __construct($pValue = NULL, $pDataType = NULL, PHPExcel_Worksheet $pSheet = NULL) { - // Initialise cell coordinate - $this->_coordinate = strtoupper($pCoordinate); - // Initialise cell value $this->_value = $pValue; - // Set worksheet - $this->_parent = $pSheet; + // Set worksheet cache + $this->_parent = $pSheet->getCellCacheController(); // Set datatype? if ($pDataType !== NULL) { @@ -166,8 +157,7 @@ class PHPExcel_Cell */ public function getColumn() { - list($column) = sscanf($this->_coordinate, '%[A-Z]%d'); - return $column; + return $this->_parent->getCurrentColumn(); } /** @@ -177,8 +167,7 @@ class PHPExcel_Cell */ public function getRow() { - list(,$row) = sscanf($this->_coordinate, '%[A-Z]%d'); - return $row; + return $this->_parent->getCurrentRow(); } /** @@ -188,7 +177,7 @@ class PHPExcel_Cell */ public function getCoordinate() { - return $this->_coordinate; + return $this->_parent->getCurrentAddress(); } /** @@ -210,7 +199,7 @@ class PHPExcel_Cell { return (string) PHPExcel_Style_NumberFormat::toFormattedString( $this->getCalculatedValue(), - $this->_parent->getParent()->getCellXfByIndex($this->getXfIndex()) + $this->getWorksheet()->getParent()->getCellXfByIndex($this->getXfIndex()) ->getNumberFormat()->getFormatCode() ); } @@ -284,31 +273,39 @@ class PHPExcel_Cell */ public function getCalculatedValue($resetLog = TRUE) { -// echo 'Cell '.$this->getCoordinate().' value is a '.$this->_dataType.' with a value of '.$this->getValue().'
'; +//echo 'Cell '.$this->getCoordinate().' value is a '.$this->_dataType.' with a value of '.$this->getValue().PHP_EOL; if ($this->_dataType == PHPExcel_Cell_DataType::TYPE_FORMULA) { try { -// echo 'Cell value for '.$this->getCoordinate().' is a formula: Calculating value
'; - $result = PHPExcel_Calculation::getInstance()->calculateCellValue($this,$resetLog); -// echo $this->getCoordinate().' calculation result is '.$result.'
'; +//echo 'Cell value for '.$this->getCoordinate().' is a formula: Calculating value'.PHP_EOL; + $result = PHPExcel_Calculation::getInstance( + $this->getWorksheet()->getParent() + )->calculateCellValue($this,$resetLog); +//echo $this->getCoordinate().' calculation result is '.$result.PHP_EOL; + // We don't yet handle array returns + if (is_array($result)) { + while (is_array($result)) { + $result = array_pop($result); + } + } } catch ( PHPExcel_Exception $ex ) { if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->_calculatedValue !== NULL)) { -// echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().'
'; +//echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().PHP_EOL; return $this->_calculatedValue; // Fallback for calculations referencing external files. } -// echo 'Calculation Exception: '.$ex->getMessage().'
'; +//echo 'Calculation Exception: '.$ex->getMessage().PHP_EOL; $result = '#N/A'; throw( new PHPExcel_Calculation_Exception( - $this->getParent()->getTitle().'!'.$this->getCoordinate().' -> '.$ex->getMessage() + $this->getWorksheet()->getTitle().'!'.$this->getCoordinate().' -> '.$ex->getMessage() ) ); } if ($result === '#Not Yet Implemented') { -// echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().'
'; +//echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().PHP_EOL; return $this->_calculatedValue; // Fallback if calculation engine does not support the formula. } -// echo 'Returning calculated value of '.$result.' for cell '.$this->getCoordinate().'
'; +//echo 'Returning calculated value of '.$result.' for cell '.$this->getCoordinate().PHP_EOL; return $result; } @@ -388,7 +385,7 @@ class PHPExcel_Cell throw new PHPExcel_Exception('Cannot check for data validation when cell is not bound to a worksheet'); } - return $this->_parent->dataValidationExists($this->getCoordinate()); + return $this->getWorksheet()->dataValidationExists($this->getCoordinate()); } /** @@ -403,7 +400,7 @@ class PHPExcel_Cell throw new PHPExcel_Exception('Cannot get data validation for cell that is not bound to a worksheet'); } - return $this->_parent->getDataValidation($this->getCoordinate()); + return $this->getWorksheet()->getDataValidation($this->getCoordinate()); } /** @@ -419,7 +416,7 @@ class PHPExcel_Cell throw new PHPExcel_Exception('Cannot set data validation for cell that is not bound to a worksheet'); } - $this->_parent->setDataValidation($this->getCoordinate(), $pDataValidation); + $this->getWorksheet()->setDataValidation($this->getCoordinate(), $pDataValidation); return $this->notifyCacheController(); } @@ -436,7 +433,7 @@ class PHPExcel_Cell throw new PHPExcel_Exception('Cannot check for hyperlink when cell is not bound to a worksheet'); } - return $this->_parent->hyperlinkExists($this->getCoordinate()); + return $this->getWorksheet()->hyperlinkExists($this->getCoordinate()); } /** @@ -451,7 +448,7 @@ class PHPExcel_Cell throw new PHPExcel_Exception('Cannot get hyperlink for cell that is not bound to a worksheet'); } - return $this->_parent->getHyperlink($this->getCoordinate()); + return $this->getWorksheet()->getHyperlink($this->getCoordinate()); } /** @@ -467,7 +464,7 @@ class PHPExcel_Cell throw new PHPExcel_Exception('Cannot set hyperlink for cell that is not bound to a worksheet'); } - $this->_parent->setHyperlink($this->getCoordinate(), $pHyperlink); + $this->getWorksheet()->setHyperlink($this->getCoordinate(), $pHyperlink); return $this->notifyCacheController(); } @@ -481,6 +478,15 @@ class PHPExcel_Cell return $this->_parent; } + /** + * Get parent worksheet + * + * @return PHPExcel_Worksheet + */ + public function getWorksheet() { + return $this->_parent->getParent(); + } + /** * Re-bind parent * @@ -488,7 +494,7 @@ class PHPExcel_Cell * @return PHPExcel_Cell */ public function rebindParent(PHPExcel_Worksheet $parent) { - $this->_parent = $parent; + $this->_parent = $parent->getCellCacheController(); return $this->notifyCacheController(); } @@ -859,11 +865,11 @@ class PHPExcel_Cell */ public static function compareCells(PHPExcel_Cell $a, PHPExcel_Cell $b) { - if ($a->_row < $b->_row) { + if ($a->getRow() < $b->getRow()) { return -1; - } elseif ($a->_row > $b->_row) { + } elseif ($a->getRow() > $b->getRow()) { return 1; - } elseif (self::columnIndexFromString($a->_column) < self::columnIndexFromString($b->_column)) { + } elseif (self::columnIndexFromString($a->getColumn()) < self::columnIndexFromString($b->getColumn())) { return -1; } else { return 1; diff --git a/Classes/PHPExcel/Cell/AdvancedValueBinder.php b/Classes/PHPExcel/Cell/AdvancedValueBinder.php index 0b5efec0..9c96a1b9 100644 --- a/Classes/PHPExcel/Cell/AdvancedValueBinder.php +++ b/Classes/PHPExcel/Cell/AdvancedValueBinder.php @@ -86,7 +86,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder if ($matches[1] == '-') $value = 0 - $value; $cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( '??/??' ); return true; } elseif (preg_match('/^([+-]?)([0-9]*) +([0-9]*)\s?\/\s*([0-9]*)$/', $value, $matches)) { @@ -95,7 +95,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder if ($matches[1] == '-') $value = 0 - $value; $cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( '# ??/??' ); return true; } @@ -106,7 +106,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder $value = (float) str_replace('%', '', $value) / 100; $cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00 ); return true; } @@ -120,7 +120,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder $value = (float) trim(str_replace(array($currencyCode, $thousandsSeparator, $decimalSeparator), array('', '', '.'), $value)); $cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( str_replace('$', $currencyCode, PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE ) ); @@ -130,7 +130,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder $value = (float) trim(str_replace(array('$',','), '', $value)); $cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE ); return true; } @@ -142,7 +142,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder $days = $h / 24 + $m / 1440; $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3 ); return true; } @@ -155,7 +155,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder // Convert value to number $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4 ); return true; } @@ -170,7 +170,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder } else { $formatCode = 'yyyy-mm-dd'; } - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getNumberFormat()->setFormatCode($formatCode); return true; } @@ -180,7 +180,7 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder $value = PHPExcel_Shared_String::SanitizeUTF8($value); $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING); // Set style - $cell->getParent()->getStyle( $cell->getCoordinate() ) + $cell->getWorksheet()->getStyle( $cell->getCoordinate() ) ->getAlignment()->setWrapText(TRUE); return true; } diff --git a/Classes/PHPExcel/Chart/DataSeriesValues.php b/Classes/PHPExcel/Chart/DataSeriesValues.php index 4a206482..034ac9e2 100644 --- a/Classes/PHPExcel/Chart/DataSeriesValues.php +++ b/Classes/PHPExcel/Chart/DataSeriesValues.php @@ -279,7 +279,7 @@ class PHPExcel_Chart_DataSeriesValues public function refresh(PHPExcel_Worksheet $worksheet, $flatten = TRUE) { if ($this->_dataSource !== NULL) { - $calcEngine = PHPExcel_Calculation::getInstance(); + $calcEngine = PHPExcel_Calculation::getInstance($worksheet->getParent()); $newDataValues = PHPExcel_Calculation::_unwrapResult( $calcEngine->_calculateFormulaValue( '='.$this->_dataSource, diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index 5357a938..9791ead2 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -204,7 +204,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @var PHPExcel_Worksheet_AutoFilter */ - private $_autoFilter = null; + private $_autoFilter = NULL; /** * Freeze pane @@ -362,12 +362,12 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_protection = new PHPExcel_Worksheet_Protection(); // Default row dimension - $this->_defaultRowDimension = new PHPExcel_Worksheet_RowDimension(null); + $this->_defaultRowDimension = new PHPExcel_Worksheet_RowDimension(NULL); // Default column dimension - $this->_defaultColumnDimension = new PHPExcel_Worksheet_ColumnDimension(null); + $this->_defaultColumnDimension = new PHPExcel_Worksheet_ColumnDimension(NULL); - $this->_autoFilter = new PHPExcel_Worksheet_AutoFilter(null, $this); + $this->_autoFilter = new PHPExcel_Worksheet_AutoFilter(NULL, $this); } @@ -376,11 +376,10 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * typically so that the worksheet object can be unset * */ - public function disconnectCells() - { - if ( $this->_cellCollection != null ){ + public function disconnectCells() { + if ( $this->_cellCollection !== NULL){ $this->_cellCollection->unsetWorksheetCells(); - $this->_cellCollection = null; + $this->_cellCollection = NULL; } // detach ourself from the workbook, so that it can then delete this worksheet successfully $this->_parent = null; @@ -391,9 +390,10 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * */ function __destruct() { - if ($this->_cellCollection !== null) { - $this->disconnectCells(); - } + PHPExcel_Calculation::getInstance($this->_parent) + ->clearCalculationCacheForWorksheet($this->_title); + + $this->disconnectCells(); } /** @@ -401,8 +401,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @return PHPExcel_CachedObjectStorage_xxx */ - public function getCellCacheController() - { + public function getCellCacheController() { return $this->_cellCollection; } // function getCellCacheController() @@ -451,7 +450,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Re-order cell collection return $this->sortCellCollection(); } - if ($this->_cellCollection !== null) { + if ($this->_cellCollection !== NULL) { return $this->_cellCollection->getCellList(); } return array(); @@ -464,7 +463,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ public function sortCellCollection() { - if ($this->_cellCollection !== null) { + if ($this->_cellCollection !== NULL) { return $this->_cellCollection->getSortedCellList(); } return array(); @@ -709,21 +708,22 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // loop through all cells in the worksheet foreach ($this->getCellCollection(false) as $cellID) { $cell = $this->getCell($cellID); - if (isset($autoSizes[$cell->getColumn()])) { + if (isset($autoSizes[$this->_cellCollection->getCurrentColumn()])) { // Determine width if cell does not participate in a merge - if (!isset($isMergeCell[$cell->getCoordinate()])) { + if (!isset($isMergeCell[$this->_cellCollection->getCurrentAddress()])) { // Calculated value - $cellValue = $cell->getCalculatedValue(); - // To formatted string - $cellValue = PHPExcel_Style_NumberFormat::toFormattedString($cellValue, $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode()); + $cellValue = PHPExcel_Style_NumberFormat::toFormattedString( + $cell->getCalculatedValue(), + $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode() + ); - $autoSizes[$cell->getColumn()] = max( - (float)$autoSizes[$cell->getColumn()], + $autoSizes[$this->_cellCollection->getCurrentColumn()] = max( + (float) $autoSizes[$this->_cellCollection->getCurrentColumn()], (float)PHPExcel_Shared_Font::calculateColumnWidth( - $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont(), + $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont(), $cellValue, - $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getAlignment()->getTextRotation(), + $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getAlignment()->getTextRotation(), $this->getDefaultStyle()->getFont() ) ); @@ -746,8 +746,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @return PHPExcel */ - public function getParent() - { + public function getParent() { return $this->_parent; } @@ -757,8 +756,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param PHPExcel $parent * @return PHPExcel_Worksheet */ - public function rebindParent(PHPExcel $parent) - { + public function rebindParent(PHPExcel $parent) { $namedRanges = $this->_parent->getNamedRanges(); foreach ($namedRanges as $namedRange) { $parent->addNamedRange($namedRange); @@ -791,7 +789,6 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * This should be left as the default true, unless you are * certain that no formula cells on any worksheet contain * references to this worksheet - * * @return PHPExcel_Worksheet */ public function setTitle($pValue = 'Worksheet', $updateFormulaCellReferences = true) @@ -807,16 +804,16 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Old title $oldTitle = $this->getTitle(); - if ($this->getParent()) { + if ($this->_parent) { // Is there already such sheet name? - if ($this->getParent()->sheetNameExists($pValue)) { + if ($this->_parent->sheetNameExists($pValue)) { // Use name, but append with lowest possible integer if (PHPExcel_Shared_String::CountCharacters($pValue) > 29) { $pValue = PHPExcel_Shared_String::Substring($pValue,0,29); } $i = 1; - while ($this->getParent()->sheetNameExists($pValue . ' ' . $i)) { + while ($this->_parent->sheetNameExists($pValue . ' ' . $i)) { ++$i; if ($i == 10) { if (PHPExcel_Shared_String::CountCharacters($pValue) > 28) { @@ -838,11 +835,13 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_title = $pValue; $this->_dirty = true; - if ($this->getParent()) { + if ($this->_parent) { // New title $newTitle = $this->getTitle(); + PHPExcel_Calculation::getInstance($this->_parent) + ->renameCalculationCacheForWorksheet($oldTitle, $newTitle); if ($updateFormulaCellReferences) - PHPExcel_ReferenceHelper::getInstance()->updateNamedFormulas($this->getParent(), $oldTitle, $newTitle); + PHPExcel_ReferenceHelper::getInstance()->updateNamedFormulas($this->_parent, $oldTitle, $newTitle); } return $this; @@ -853,8 +852,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @return string Sheet state (visible, hidden, veryHidden) */ - public function getSheetState() - { + public function getSheetState() { return $this->_sheetState; } @@ -864,8 +862,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param string $value Sheet state (visible, hidden, veryHidden) * @return PHPExcel_Worksheet */ - public function setSheetState($value = PHPExcel_Worksheet::SHEETSTATE_VISIBLE) - { + public function setSheetState($value = PHPExcel_Worksheet::SHEETSTATE_VISIBLE) { $this->_sheetState = $value; return $this; } @@ -1110,14 +1107,14 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Worksheet reference? if (strpos($pCoordinate, '!') !== false) { $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pCoordinate, true); - return $this->getParent()->getSheetByName($worksheetReference[0])->getCell($worksheetReference[1]); + return $this->_parent->getSheetByName($worksheetReference[0])->getCell($worksheetReference[1]); } // Named range? if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $pCoordinate, $matches)) && (preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $pCoordinate, $matches))) { $namedRange = PHPExcel_NamedRange::resolveRange($pCoordinate, $this); - if ($namedRange !== null) { + if ($namedRange !== NULL) { $pCoordinate = $namedRange->getRange(); return $namedRange->getWorksheet()->getCell($pCoordinate); } @@ -1136,7 +1133,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Coordinates $aCoordinates = PHPExcel_Cell::coordinateFromString($pCoordinate); - $cell = $this->_cellCollection->addCacheData($pCoordinate,new PHPExcel_Cell($pCoordinate, null, PHPExcel_Cell_DataType::TYPE_NULL, $this)); + $cell = $this->_cellCollection->addCacheData($pCoordinate,new PHPExcel_Cell(NULL, PHPExcel_Cell_DataType::TYPE_NULL, $this)); $this->_cellCollectionIsSorted = false; if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($aCoordinates[0])) @@ -1176,7 +1173,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $coordinate = $columnLetter . $pRow; if (!$this->_cellCollection->isDataSet($coordinate)) { - $cell = $this->_cellCollection->addCacheData($coordinate, new PHPExcel_Cell($coordinate, null, PHPExcel_Cell_DataType::TYPE_NULL, $this)); + $cell = $this->_cellCollection->addCacheData($coordinate, new PHPExcel_Cell(NULL, PHPExcel_Cell_DataType::TYPE_NULL, $this)); $this->_cellCollectionIsSorted = false; if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < $pColumn) @@ -1202,14 +1199,14 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Worksheet reference? if (strpos($pCoordinate, '!') !== false) { $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pCoordinate, true); - return $this->getParent()->getSheetByName($worksheetReference[0])->cellExists($worksheetReference[1]); + return $this->_parent->getSheetByName($worksheetReference[0])->cellExists($worksheetReference[1]); } // Named range? if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $pCoordinate, $matches)) && (preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $pCoordinate, $matches))) { $namedRange = PHPExcel_NamedRange::resolveRange($pCoordinate, $this); - if ($namedRange !== null) { + if ($namedRange !== NULL) { $pCoordinate = $namedRange->getRange(); if ($this->getHashCode() != $namedRange->getWorksheet()->getHashCode()) { if (!$namedRange->getLocalOnly()) { @@ -1522,7 +1519,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * Please note that this will overwrite existing cell styles for cells in range! * - * @param [PHPExcel_Style_Conditional] $pCellStyle Cell style to duplicate + * @param array of PHPExcel_Style_Conditional $pCellStyle Cell style to duplicate * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") * @throws PHPExcel_Exception * @return PHPExcel_Worksheet @@ -1899,7 +1896,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ public function removeAutoFilter() { - $this->_autoFilter->setRange(null); + $this->_autoFilter->setRange(NULL); return $this; } @@ -2179,7 +2176,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable /** * Set comments array for the entire sheet. * - * @param [PHPExcel_Comment] $pValue + * @param array of PHPExcel_Comment * @return PHPExcel_Worksheet */ public function setComments($pValue = array()) @@ -2397,10 +2394,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * True - Return rows and columns indexed by their actual row and column IDs * @return array */ - public function rangeToArray( - $pRange = 'A1', $nullValue = null, $calculateFormulas = true, - $formatData = true, $returnCellRef = false) - { + public function rangeToArray($pRange = 'A1', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { // Returnvalue $returnValue = array(); // Identify the range that we need to extract from the worksheet @@ -2445,7 +2439,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable ); } } else { - // Cell holds a null + // Cell holds a NULL $returnValue[$rRef][$cRef] = $nullValue; } } else { @@ -2472,20 +2466,14 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @return array * @throws PHPExcel_Exception */ - public function namedRangeToArray( - $pNamedRange = '', $nullValue = null, $calculateFormulas = true, - $formatData = true, $returnCellRef = false - ) - { + public function namedRangeToArray($pNamedRange = '', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { $namedRange = PHPExcel_NamedRange::resolveRange($pNamedRange, $this); - if ($namedRange !== null) { + if ($namedRange !== NULL) { $pWorkSheet = $namedRange->getWorksheet(); $pCellRange = $namedRange->getRange(); - return $pWorkSheet->rangeToArray( - $pCellRange, - $nullValue, $calculateFormulas, $formatData, $returnCellRef - ); + return $pWorkSheet->rangeToArray( $pCellRange, + $nullValue, $calculateFormulas, $formatData, $returnCellRef); } throw new PHPExcel_Exception('Named Range '.$pNamedRange.' does not exist.'); @@ -2502,8 +2490,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * True - Return rows and columns indexed by their actual row and column IDs * @return array */ - public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) - { + public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { // Garbage collect... $this->garbageCollect(); @@ -2511,10 +2498,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $maxCol = $this->getHighestColumn(); $maxRow = $this->getHighestRow(); // Return - return $this->rangeToArray( - 'A1:'.$maxCol.$maxRow, - $nullValue, $calculateFormulas, $formatData, $returnCellRef - ); + return $this->rangeToArray( 'A1:'.$maxCol.$maxRow, + $nullValue, $calculateFormulas, $formatData, $returnCellRef); } /** @@ -2523,8 +2508,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param integer $startRow The row number at which to start iterating * @return PHPExcel_Worksheet_RowIterator */ - public function getRowIterator($startRow = 1) - { + public function getRowIterator($startRow = 1) { return new PHPExcel_Worksheet_RowIterator($this,$startRow); } @@ -2533,8 +2517,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @return PHPExcel_Worksheet */ - public function garbageCollect() - { + public function garbageCollect() { // Flush cache $this->_cellCollection->getCacheData('A1'); // Build a reference table from images @@ -2578,8 +2561,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @return string Hash code */ - public function getHashCode() - { + public function getHashCode() { if ($this->_dirty) { $this->_hash = md5( $this->_title . $this->_autoFilter . @@ -2601,8 +2583,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param bool $returnRange Return range? (see example) * @return mixed */ - public static function extractSheetTitle($pRange, $returnRange = false) - { + public static function extractSheetTitle($pRange, $returnRange = false) { // Sheet title included? if (($sep = strpos($pRange, '!')) === false) { return ''; @@ -2733,8 +2714,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @param string $range * @return string Adjusted range value */ - public function shrinkRangeToFit($range) - { + public function shrinkRangeToFit($range) { $maxCol = $this->getHighestColumn(); $maxRow = $this->getHighestRow(); $maxCol = PHPExcel_Cell::columnIndexFromString($maxCol); @@ -2762,7 +2742,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ public function getTabColor() { - if ($this->_tabColor === null) + if ($this->_tabColor === NULL) $this->_tabColor = new PHPExcel_Style_Color(); return $this->_tabColor; @@ -2788,7 +2768,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ public function isTabColorSet() { - return ($this->_tabColor !== null); + return ($this->_tabColor !== NULL); } /** @@ -2796,8 +2776,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * * @return PHPExcel_Worksheet */ - public function copy() - { + public function copy() { $copied = clone $this; return $copied; @@ -2806,8 +2785,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ - public function __clone() - { + public function __clone() { foreach ($this as $key => $val) { if ($key == '_parent') { continue; diff --git a/Classes/PHPExcel/Writer/CSV.php b/Classes/PHPExcel/Writer/CSV.php index 2ff5b410..3563cb23 100644 --- a/Classes/PHPExcel/Writer/CSV.php +++ b/Classes/PHPExcel/Writer/CSV.php @@ -102,8 +102,8 @@ class PHPExcel_Writer_CSV extends PHPExcel_Writer_Abstract implements PHPExcel_W // Fetch sheet $sheet = $this->_phpExcel->getSheet($this->_sheetIndex); - $saveDebugLog = PHPExcel_Calculation::getInstance()->writeDebugLog; - PHPExcel_Calculation::getInstance()->writeDebugLog = false; + $saveDebugLog = PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->getWriteDebugLog(); + PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog(FALSE); $saveArrayReturnType = PHPExcel_Calculation::getArrayReturnType(); PHPExcel_Calculation::setArrayReturnType(PHPExcel_Calculation::RETURN_ARRAY_AS_VALUE); @@ -139,7 +139,7 @@ class PHPExcel_Writer_CSV extends PHPExcel_Writer_Abstract implements PHPExcel_W fclose($fileHandle); PHPExcel_Calculation::setArrayReturnType($saveArrayReturnType); - PHPExcel_Calculation::getInstance()->writeDebugLog = $saveDebugLog; + PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog($saveDebugLog); } /** diff --git a/Classes/PHPExcel/Writer/Excel2007.php b/Classes/PHPExcel/Writer/Excel2007.php index a74350ca..f09bb271 100644 --- a/Classes/PHPExcel/Writer/Excel2007.php +++ b/Classes/PHPExcel/Writer/Excel2007.php @@ -179,8 +179,8 @@ class PHPExcel_Writer_Excel2007 extends PHPExcel_Writer_Abstract implements PHPE } } - $saveDebugLog = PHPExcel_Calculation::getInstance()->writeDebugLog; - PHPExcel_Calculation::getInstance()->writeDebugLog = false; + $saveDebugLog = PHPExcel_Calculation::getInstance($this->_spreadSheet)->getDebugLog()->getWriteDebugLog(); + PHPExcel_Calculation::getInstance($this->_spreadSheet)->getDebugLog()->setWriteDebugLog(FALSE); $saveDateReturnType = PHPExcel_Calculation_Functions::getReturnDateType(); PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL); @@ -341,7 +341,7 @@ class PHPExcel_Writer_Excel2007 extends PHPExcel_Writer_Abstract implements PHPE } PHPExcel_Calculation_Functions::setReturnDateType($saveDateReturnType); - PHPExcel_Calculation::getInstance()->writeDebugLog = $saveDebugLog; + PHPExcel_Calculation::getInstance($this->_spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog); // Close file if ($objZip->close() === false) { diff --git a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php index 977f172d..cb1437d3 100644 --- a/Classes/PHPExcel/Writer/Excel2007/Worksheet.php +++ b/Classes/PHPExcel/Writer/Excel2007/Worksheet.php @@ -1074,12 +1074,9 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->writeAttribute('t', $mappedType); break; case 'f': // Formula - $calculatedValue = null; - if ($this->getParentWriter()->getPreCalculateFormulas()) { - $calculatedValue = $pCell->getCalculatedValue(); - } else { - $calculatedValue = $cellValue; - } + $calculatedValue = ($this->getParentWriter()->getPreCalculateFormulas()) ? + $pCell->getCalculatedValue() : + $cellValue; if (is_string($calculatedValue)) { $objWriter->writeAttribute('t', 'str'); } @@ -1125,7 +1122,7 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ } if ($this->getParentWriter()->getOffice2003Compatibility() === false) { if ($this->getParentWriter()->getPreCalculateFormulas()) { - $calculatedValue = $pCell->getCalculatedValue(); +// $calculatedValue = $pCell->getCalculatedValue(); if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') { $objWriter->writeElement('v', PHPExcel_Shared_String::FormatNumber($calculatedValue)); } else { diff --git a/Classes/PHPExcel/Writer/Excel5.php b/Classes/PHPExcel/Writer/Excel5.php index 459653c6..a63c1d1c 100644 --- a/Classes/PHPExcel/Writer/Excel5.php +++ b/Classes/PHPExcel/Writer/Excel5.php @@ -120,8 +120,8 @@ class PHPExcel_Writer_Excel5 extends PHPExcel_Writer_Abstract implements PHPExce // garbage collect $this->_phpExcel->garbageCollect(); - $saveDebugLog = PHPExcel_Calculation::getInstance()->writeDebugLog; - PHPExcel_Calculation::getInstance()->writeDebugLog = false; + $saveDebugLog = PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->getWriteDebugLog(); + PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog(FALSE); $saveDateReturnType = PHPExcel_Calculation_Functions::getReturnDateType(); PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL); @@ -226,7 +226,7 @@ class PHPExcel_Writer_Excel5 extends PHPExcel_Writer_Abstract implements PHPExce $res = $root->save($pFilename); PHPExcel_Calculation_Functions::setReturnDateType($saveDateReturnType); - PHPExcel_Calculation::getInstance()->writeDebugLog = $saveDebugLog; + PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog($saveDebugLog); } /** diff --git a/Classes/PHPExcel/Writer/HTML.php b/Classes/PHPExcel/Writer/HTML.php index fb467f36..a30033f1 100644 --- a/Classes/PHPExcel/Writer/HTML.php +++ b/Classes/PHPExcel/Writer/HTML.php @@ -152,8 +152,8 @@ class PHPExcel_Writer_HTML extends PHPExcel_Writer_Abstract implements PHPExcel_ // garbage collect $this->_phpExcel->garbageCollect(); - $saveDebugLog = PHPExcel_Calculation::getInstance()->writeDebugLog; - PHPExcel_Calculation::getInstance()->writeDebugLog = false; + $saveDebugLog = PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->getWriteDebugLog(); + PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog(FALSE); $saveArrayReturnType = PHPExcel_Calculation::getArrayReturnType(); PHPExcel_Calculation::setArrayReturnType(PHPExcel_Calculation::RETURN_ARRAY_AS_VALUE); @@ -184,7 +184,7 @@ class PHPExcel_Writer_HTML extends PHPExcel_Writer_Abstract implements PHPExcel_ fclose($fileHandle); PHPExcel_Calculation::setArrayReturnType($saveArrayReturnType); - PHPExcel_Calculation::getInstance()->writeDebugLog = $saveDebugLog; + PHPExcel_Calculation::getInstance($this->_phpExcel)->getDebugLog()->setWriteDebugLog($saveDebugLog); } /** diff --git a/Examples/06largescale-with-cellcaching-sqlite.php b/Examples/06largescale-with-cellcaching-sqlite.php new file mode 100644 index 00000000..fff36959 --- /dev/null +++ b/Examples/06largescale-with-cellcaching-sqlite.php @@ -0,0 +1,126 @@ +'); + +date_default_timezone_set('Europe/London'); + +/** Include PHPExcel */ +require_once '../Classes/PHPExcel.php'; + +$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_sqlite; +PHPExcel_Settings::setCacheStorageMethod($cacheMethod); +echo date('H:i:s') , " Enable Cell Caching using " , $cacheMethod , " method" , EOL; + + +// Create new PHPExcel object +echo date('H:i:s') , " Create new PHPExcel object" , EOL; +$objPHPExcel = new PHPExcel(); + +// Set document properties +echo date('H:i:s') , " Set properties" , EOL; +$objPHPExcel->getProperties()->setCreator("Maarten Balliauw") + ->setLastModifiedBy("Maarten Balliauw") + ->setTitle("Office 2007 XLSX Test Document") + ->setSubject("Office 2007 XLSX Test Document") + ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.") + ->setKeywords("office 2007 openxml php") + ->setCategory("Test result file"); + + +// Create a first sheet +echo date('H:i:s') , " Add data" , EOL; +$objPHPExcel->setActiveSheetIndex(0); +$objPHPExcel->getActiveSheet()->setCellValue('A1', "Firstname"); +$objPHPExcel->getActiveSheet()->setCellValue('B1', "Lastname"); +$objPHPExcel->getActiveSheet()->setCellValue('C1', "Phone"); +$objPHPExcel->getActiveSheet()->setCellValue('D1', "Fax"); +$objPHPExcel->getActiveSheet()->setCellValue('E1', "Is Client ?"); + + +// Hide "Phone" and "fax" column +echo date('H:i:s') , " Hide 'Phone' and 'fax' columns" , EOL; +$objPHPExcel->getActiveSheet()->getColumnDimension('C')->setVisible(false); +$objPHPExcel->getActiveSheet()->getColumnDimension('D')->setVisible(false); + + +// Set outline levels +echo date('H:i:s') , " Set outline levels" , EOL; +$objPHPExcel->getActiveSheet()->getColumnDimension('E')->setOutlineLevel(1) + ->setVisible(false) + ->setCollapsed(true); + +// Freeze panes +echo date('H:i:s') , " Freeze panes" , EOL; +$objPHPExcel->getActiveSheet()->freezePane('A2'); + + +// Rows to repeat at top +echo date('H:i:s') , " Rows to repeat at top" , EOL; +$objPHPExcel->getActiveSheet()->getPageSetup()->setRowsToRepeatAtTopByStartAndEnd(1, 1); + + +// Add data +for ($i = 2; $i <= 5000; $i++) { + $objPHPExcel->getActiveSheet()->setCellValue('A' . $i, "FName $i") + ->setCellValue('B' . $i, "LName $i") + ->setCellValue('C' . $i, "PhoneNo $i") + ->setCellValue('D' . $i, "FaxNo $i") + ->setCellValue('E' . $i, true); +} + + +// Set active sheet index to the first sheet, so Excel opens this as the first sheet +$objPHPExcel->setActiveSheetIndex(0); + + +// Save Excel 2007 file +echo date('H:i:s') , " Write to Excel2007 format" , EOL; +$callStartTime = microtime(true); + +$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); +$objWriter->save(str_replace('.php', '.xlsx', __FILE__)); +$callEndTime = microtime(true); +$callTime = $callEndTime - $callStartTime; + +echo date('H:i:s') , " File written to " , str_replace('.php', '.xlsx', pathinfo(__FILE__, PATHINFO_BASENAME)) , EOL; +echo 'Call time to write Workbook was ' , sprintf('%.4f',$callTime) , " seconds" , EOL; +// Echo memory usage +echo date('H:i:s') , ' Current memory usage: ' , (memory_get_usage(true) / 1024 / 1024) , " MB" , EOL; + + +// Echo memory peak usage +echo date('H:i:s') , " Peak memory usage: " , (memory_get_peak_usage(true) / 1024 / 1024) , " MB" , EOL; + +// Echo done +echo date('H:i:s') , " Done writing file" , EOL; +echo 'File has been created in ' , getcwd() , EOL; diff --git a/Examples/06largescale-with-cellcaching-sqlite3.php b/Examples/06largescale-with-cellcaching-sqlite3.php new file mode 100644 index 00000000..a4c537a5 --- /dev/null +++ b/Examples/06largescale-with-cellcaching-sqlite3.php @@ -0,0 +1,126 @@ +'); + +date_default_timezone_set('Europe/London'); + +/** Include PHPExcel */ +require_once '../Classes/PHPExcel.php'; + +$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_sqlite3; +PHPExcel_Settings::setCacheStorageMethod($cacheMethod); +echo date('H:i:s') , " Enable Cell Caching using " , $cacheMethod , " method" , EOL; + + +// Create new PHPExcel object +echo date('H:i:s') , " Create new PHPExcel object" , EOL; +$objPHPExcel = new PHPExcel(); + +// Set document properties +echo date('H:i:s') , " Set properties" , EOL; +$objPHPExcel->getProperties()->setCreator("Maarten Balliauw") + ->setLastModifiedBy("Maarten Balliauw") + ->setTitle("Office 2007 XLSX Test Document") + ->setSubject("Office 2007 XLSX Test Document") + ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.") + ->setKeywords("office 2007 openxml php") + ->setCategory("Test result file"); + + +// Create a first sheet +echo date('H:i:s') , " Add data" , EOL; +$objPHPExcel->setActiveSheetIndex(0); +$objPHPExcel->getActiveSheet()->setCellValue('A1', "Firstname"); +$objPHPExcel->getActiveSheet()->setCellValue('B1', "Lastname"); +$objPHPExcel->getActiveSheet()->setCellValue('C1', "Phone"); +$objPHPExcel->getActiveSheet()->setCellValue('D1', "Fax"); +$objPHPExcel->getActiveSheet()->setCellValue('E1', "Is Client ?"); + + +// Hide "Phone" and "fax" column +echo date('H:i:s') , " Hide 'Phone' and 'fax' columns" , EOL; +$objPHPExcel->getActiveSheet()->getColumnDimension('C')->setVisible(false); +$objPHPExcel->getActiveSheet()->getColumnDimension('D')->setVisible(false); + + +// Set outline levels +echo date('H:i:s') , " Set outline levels" , EOL; +$objPHPExcel->getActiveSheet()->getColumnDimension('E')->setOutlineLevel(1) + ->setVisible(false) + ->setCollapsed(true); + +// Freeze panes +echo date('H:i:s') , " Freeze panes" , EOL; +$objPHPExcel->getActiveSheet()->freezePane('A2'); + + +// Rows to repeat at top +echo date('H:i:s') , " Rows to repeat at top" , EOL; +$objPHPExcel->getActiveSheet()->getPageSetup()->setRowsToRepeatAtTopByStartAndEnd(1, 1); + + +// Add data +for ($i = 2; $i <= 5000; $i++) { + $objPHPExcel->getActiveSheet()->setCellValue('A' . $i, "FName $i") + ->setCellValue('B' . $i, "LName $i") + ->setCellValue('C' . $i, "PhoneNo $i") + ->setCellValue('D' . $i, "FaxNo $i") + ->setCellValue('E' . $i, true); +} + + +// Set active sheet index to the first sheet, so Excel opens this as the first sheet +$objPHPExcel->setActiveSheetIndex(0); + + +// Save Excel 2007 file +echo date('H:i:s') , " Write to Excel2007 format" , EOL; +$callStartTime = microtime(true); + +$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); +$objWriter->save(str_replace('.php', '.xlsx', __FILE__)); +$callEndTime = microtime(true); +$callTime = $callEndTime - $callStartTime; + +echo date('H:i:s') , " File written to " , str_replace('.php', '.xlsx', pathinfo(__FILE__, PATHINFO_BASENAME)) , EOL; +echo 'Call time to write Workbook was ' , sprintf('%.4f',$callTime) , " seconds" , EOL; +// Echo memory usage +echo date('H:i:s') , ' Current memory usage: ' , (memory_get_usage(true) / 1024 / 1024) , " MB" , EOL; + + +// Echo memory peak usage +echo date('H:i:s') , " Peak memory usage: " , (memory_get_peak_usage(true) / 1024 / 1024) , " MB" , EOL; + +// Echo done +echo date('H:i:s') , " Done writing file" , EOL; +echo 'File has been created in ' , getcwd() , EOL; diff --git a/changelog.txt b/changelog.txt index 600a33fd..27410f85 100644 --- a/changelog.txt +++ b/changelog.txt @@ -23,7 +23,7 @@ ************************************************************************************** -Fixed in develop branch: +Fixed in develop branch for release v1.7.9: - Feature: (MBaker) Include charts option for HTML Writer - Feature: (MBaker) Added composer file - Bugfix: (Asker) Work item 18777 - Error in PHPEXCEL/Calculation.php script on line 2976 (stack pop check) @@ -41,6 +41,8 @@ Fixed in develop branch: - General: (cfhay) Work item 18958 - Memory and Speed improvements in PHPExcel_Reader_Excel5 - General: (MBaker) Work item GH-78 - Modify listWorksheetNames() and listWorksheetInfo to use XMLReader with streamed XML rather than SimpleXML - General: (dbonsch) Restructuring of PHPExcel Exceptions +- General: (MBaker) Work items 16926 and 15145 - Refactor Calculation Engine from singleton to a Multiton + Ensures that calculation cache is maintained independently for different workbooks - Bugfix: (techhead) Work item GH-70 - Fixed formula/formatting bug when removing rows - Bugfix: (alexgann) Work item GH-63 - Fix to cellExists for non-existent namedRanges - Bugfix: (MBaker) Work item 18844 - cache_in_memory_gzip "eats" last worksheet line, cache_in_memory doesn't @@ -52,6 +54,7 @@ Fixed in develop branch: - Bugfix: (MBaker) Work item GH-113 - canRead() Error for GoogleDocs ODS files: in ODS files from Google Docs there is no mimetype file - Bugfix: (MBaker) Work item GH-80 - "Sheet index is out of bounds." Exception - Bugfix: (ccorliss) Work item GH-105 - Fixed number format fatal error +- Bugfix: (MBaker) - Add DROP TABLE in destructor for SQLite and SQLite3 cache controllers -------------------------------------------------------------------------------- BREAKING CHANGE! As part of the planned changes for handling array formulae in diff --git a/unitTests/Classes/PHPExcel/Cell/AdvancedValueBinderTest.php b/unitTests/Classes/PHPExcel/Cell/AdvancedValueBinderTest.php index a76a2b25..0a6ca54d 100644 --- a/unitTests/Classes/PHPExcel/Cell/AdvancedValueBinderTest.php +++ b/unitTests/Classes/PHPExcel/Cell/AdvancedValueBinderTest.php @@ -35,7 +35,16 @@ class AdvancedValueBinderTest extends PHPUnit_Framework_TestCase */ public function testCurrency($value, $valueBinded, $format, $thousandsSeparator, $decimalSeparator, $currencyCode) { - $sheet = $this->getMock('PHPExcel_Worksheet', array('getStyle', 'getNumberFormat', 'setFormatCode')); + $sheet = $this->getMock( + 'PHPExcel_Worksheet', + array('getStyle', 'getNumberFormat', 'setFormatCode','getCellCacheController') + ); + $cache = $this->getMockBuilder('PHPExcel_CachedObjectStorage_Memory') + ->disableOriginalConstructor() + ->getMock(); + $cache->expects($this->any()) + ->method('getParent') + ->will($this->returnValue($sheet)); $sheet->expects($this->once()) ->method('getStyle') @@ -47,12 +56,15 @@ class AdvancedValueBinderTest extends PHPUnit_Framework_TestCase ->method('setFormatCode') ->with($format) ->will($this->returnSelf()); + $sheet->expects($this->any()) + ->method('getCellCacheController') + ->will($this->returnValue($cache)); PHPExcel_Shared_String::setCurrencyCode($currencyCode); PHPExcel_Shared_String::setDecimalSeparator($decimalSeparator); PHPExcel_Shared_String::setThousandsSeparator($thousandsSeparator); - $cell = new PHPExcel_Cell('A', 1, null, PHPExcel_Cell_DataType::TYPE_STRING, $sheet); + $cell = new PHPExcel_Cell(NULL, PHPExcel_Cell_DataType::TYPE_STRING, $sheet); $binder = new PHPExcel_Cell_AdvancedValueBinder(); $binder->bindValue($cell, $value); diff --git a/unitTests/Classes/PHPExcel/Worksheet/AutoFilterTest.php b/unitTests/Classes/PHPExcel/Worksheet/AutoFilterTest.php index 6a6d5ae8..9907eabc 100644 --- a/unitTests/Classes/PHPExcel/Worksheet/AutoFilterTest.php +++ b/unitTests/Classes/PHPExcel/Worksheet/AutoFilterTest.php @@ -18,6 +18,12 @@ class AutoFilterTest extends PHPUnit_Framework_TestCase $this->_mockWorksheetObject = $this->getMockBuilder('PHPExcel_Worksheet') ->disableOriginalConstructor() ->getMock(); + $this->_mockCacheController = $this->getMockBuilder('PHPExcel_CachedObjectStorage_Memory') + ->disableOriginalConstructor() + ->getMock(); + $this->_mockWorksheetObject->expects($this->any()) + ->method('getCellCacheController') + ->will($this->returnValue($this->_mockCacheController)); $this->_testAutoFilterObject = new PHPExcel_Worksheet_AutoFilter( $this->_testInitialRange, diff --git a/unitTests/rawTestData/Calculation/DateTime/DATEVALUE.data b/unitTests/rawTestData/Calculation/DateTime/DATEVALUE.data index 281c707f..43970c28 100644 --- a/unitTests/rawTestData/Calculation/DateTime/DATEVALUE.data +++ b/unitTests/rawTestData/Calculation/DateTime/DATEVALUE.data @@ -35,11 +35,11 @@ "22 August 98", 36029 "1st March 2007", 39142 // MS Excel will fail with a #VALUE return, but PHPExcel can parse this date "The 1st day of March 2007", "#VALUE!" -"1 Jan", 40909 -"31/12", 41274 +"1 Jan", 41275 +"31/12", 41639 "12/31", 11658 // Excel reads as 1st December 1931, not 31st December in current year -"5-JUL", 41095 -"5 Jul", 41095 +"5-JUL", 41460 +"5 Jul", 41460 "12/2008", 39783 "10/32", 11963 11, "#VALUE!"