parent
30c880b5e6
commit
c920a77649
|
|
@ -3345,18 +3345,15 @@ class Calculation
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $cellReference
|
|
||||||
* @param mixed $cellValue
|
* @param mixed $cellValue
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function getValueFromCache($cellReference, &$cellValue)
|
public function getValueFromCache(string $cellReference, &$cellValue): bool
|
||||||
{
|
{
|
||||||
|
$this->debugLog->writeDebugLog("Testing cache value for cell {$cellReference}");
|
||||||
// Is calculation cacheing enabled?
|
// Is calculation cacheing enabled?
|
||||||
// Is the value present in calculation cache?
|
// If so, is the required value present in calculation cache?
|
||||||
$this->debugLog->writeDebugLog('Testing cache value for cell ', $cellReference);
|
|
||||||
if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
|
if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
|
||||||
$this->debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache');
|
$this->debugLog->writeDebugLog("Retrieving value for cell {$cellReference} from cache");
|
||||||
// Return the cached result
|
// Return the cached result
|
||||||
|
|
||||||
$cellValue = $this->calculationCache[$cellReference];
|
$cellValue = $this->calculationCache[$cellReference];
|
||||||
|
|
@ -3418,7 +3415,7 @@ class Calculation
|
||||||
if (($cellID !== null) && ($this->getValueFromCache($wsCellReference, $cellValue))) {
|
if (($cellID !== null) && ($this->getValueFromCache($wsCellReference, $cellValue))) {
|
||||||
return $cellValue;
|
return $cellValue;
|
||||||
}
|
}
|
||||||
$this->debugLog->writeDebugLog('Evaluating formula for cell ', $wsCellReference);
|
$this->debugLog->writeDebugLog("Evaluating formula for cell {$wsCellReference}");
|
||||||
|
|
||||||
if (($wsTitle[0] !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) {
|
if (($wsTitle[0] !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) {
|
||||||
if ($this->cyclicFormulaCount <= 0) {
|
if ($this->cyclicFormulaCount <= 0) {
|
||||||
|
|
@ -3440,7 +3437,7 @@ class Calculation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->debugLog->writeDebugLog('Formula for cell ', $wsCellReference, ' is ', $formula);
|
$this->debugLog->writeDebugLog("Formula for cell {$wsCellReference} is {$formula}");
|
||||||
// Parse the formula onto the token stack and calculate the value
|
// Parse the formula onto the token stack and calculate the value
|
||||||
$this->cyclicReferenceStack->push($wsCellReference);
|
$this->cyclicReferenceStack->push($wsCellReference);
|
||||||
|
|
||||||
|
|
@ -4810,23 +4807,22 @@ class Calculation
|
||||||
* @param mixed $operand1
|
* @param mixed $operand1
|
||||||
* @param mixed $operand2
|
* @param mixed $operand2
|
||||||
* @param string $operation
|
* @param string $operation
|
||||||
* @param bool $recursingArrays
|
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
|
private function executeArrayComparison($cellID, $operand1, $operand2, $operation, Stack &$stack, bool $recursingArrays)
|
||||||
{
|
{
|
||||||
// If we're dealing with matrix operations, we want a matrix result
|
|
||||||
if ((is_array($operand1)) || (is_array($operand2))) {
|
|
||||||
$result = [];
|
$result = [];
|
||||||
if ((is_array($operand1)) && (!is_array($operand2))) {
|
if (!is_array($operand2)) {
|
||||||
|
// Operand 1 is an array, Operand 2 is a scalar
|
||||||
foreach ($operand1 as $x => $operandData) {
|
foreach ($operand1 as $x => $operandData) {
|
||||||
$this->debugLog->writeDebugLog('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);
|
$this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack);
|
||||||
$r = $stack->pop();
|
$r = $stack->pop();
|
||||||
$result[$x] = $r['value'];
|
$result[$x] = $r['value'];
|
||||||
}
|
}
|
||||||
} elseif ((!is_array($operand1)) && (is_array($operand2))) {
|
} elseif (!is_array($operand1)) {
|
||||||
|
// Operand 1 is a scalar, Operand 2 is an array
|
||||||
foreach ($operand2 as $x => $operandData) {
|
foreach ($operand2 as $x => $operandData) {
|
||||||
$this->debugLog->writeDebugLog('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);
|
$this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack);
|
||||||
|
|
@ -4834,6 +4830,7 @@ class Calculation
|
||||||
$result[$x] = $r['value'];
|
$result[$x] = $r['value'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Operand 1 and Operand 2 are both arrays
|
||||||
if (!$recursingArrays) {
|
if (!$recursingArrays) {
|
||||||
self::checkMatrixOperands($operand1, $operand2, 2);
|
self::checkMatrixOperands($operand1, $operand2, 2);
|
||||||
}
|
}
|
||||||
|
|
@ -4852,6 +4849,22 @@ class Calculation
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param null|string $cellID
|
||||||
|
* @param mixed $operand1
|
||||||
|
* @param mixed $operand2
|
||||||
|
* @param string $operation
|
||||||
|
* @param bool $recursingArrays
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
|
||||||
|
{
|
||||||
|
// If we're dealing with matrix operations, we want a matrix result
|
||||||
|
if ((is_array($operand1)) || (is_array($operand2))) {
|
||||||
|
return $this->executeArrayComparison($cellID, $operand1, $operand2, $operation, $stack, $recursingArrays);
|
||||||
|
}
|
||||||
|
|
||||||
// Simple validate the two operands if they are string values
|
// Simple validate the two operands if they are string values
|
||||||
if (is_string($operand1) && $operand1 > '' && $operand1[0] == self::FORMULA_STRING_QUOTE) {
|
if (is_string($operand1) && $operand1 > '' && $operand1[0] == self::FORMULA_STRING_QUOTE) {
|
||||||
$operand1 = self::unwrapResult($operand1);
|
$operand1 = self::unwrapResult($operand1);
|
||||||
|
|
@ -4863,10 +4876,10 @@ class Calculation
|
||||||
// Use case insensitive comparaison if not OpenOffice mode
|
// Use case insensitive comparaison if not OpenOffice mode
|
||||||
if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) {
|
if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) {
|
||||||
if (is_string($operand1)) {
|
if (is_string($operand1)) {
|
||||||
$operand1 = strtoupper($operand1);
|
$operand1 = Shared\StringHelper::strToUpper($operand1);
|
||||||
}
|
}
|
||||||
if (is_string($operand2)) {
|
if (is_string($operand2)) {
|
||||||
$operand2 = strtoupper($operand2);
|
$operand2 = Shared\StringHelper::strToUpper($operand2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,11 @@ class Conditional
|
||||||
$targetValue = Functions::flattenSingleValue($arguments[0]);
|
$targetValue = Functions::flattenSingleValue($arguments[0]);
|
||||||
$argc = count($arguments) - 1;
|
$argc = count($arguments) - 1;
|
||||||
$switchCount = floor($argc / 2);
|
$switchCount = floor($argc / 2);
|
||||||
$switchSatisfied = false;
|
|
||||||
$hasDefaultClause = $argc % 2 !== 0;
|
$hasDefaultClause = $argc % 2 !== 0;
|
||||||
$defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1];
|
$defaultClause = $argc % 2 === 0 ? null : $arguments[$argc];
|
||||||
|
|
||||||
if ($switchCount) {
|
$switchSatisfied = false;
|
||||||
|
if ($switchCount > 0) {
|
||||||
for ($index = 0; $index < $switchCount; ++$index) {
|
for ($index = 0; $index < $switchCount; ++$index) {
|
||||||
if ($targetValue == $arguments[$index * 2 + 1]) {
|
if ($targetValue == $arguments[$index * 2 + 1]) {
|
||||||
$result = $arguments[$index * 2 + 2];
|
$result = $arguments[$index * 2 + 2];
|
||||||
|
|
@ -98,7 +98,7 @@ class Conditional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$switchSatisfied) {
|
if ($switchSatisfied !== true) {
|
||||||
$result = $hasDefaultClause ? $defaultClause : Functions::NA();
|
$result = $hasDefaultClause ? $defaultClause : Functions::NA();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,12 +161,14 @@ class Conditional
|
||||||
*/
|
*/
|
||||||
public static function IFS(...$arguments)
|
public static function IFS(...$arguments)
|
||||||
{
|
{
|
||||||
if (count($arguments) % 2 != 0) {
|
$argumentCount = count($arguments);
|
||||||
|
|
||||||
|
if ($argumentCount % 2 != 0) {
|
||||||
return Functions::NA();
|
return Functions::NA();
|
||||||
}
|
}
|
||||||
// We use instance of Exception as a falseValue in order to prevent string collision with value in cell
|
// We use instance of Exception as a falseValue in order to prevent string collision with value in cell
|
||||||
$falseValueException = new Exception();
|
$falseValueException = new Exception();
|
||||||
for ($i = 0; $i < count($arguments); $i += 2) {
|
for ($i = 0; $i < $argumentCount; $i += 2) {
|
||||||
$testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
|
$testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
|
||||||
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]);
|
$returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]);
|
||||||
$result = self::statementIf($testValue, $returnIfTrue, $falseValueException);
|
$result = self::statementIf($testValue, $returnIfTrue, $falseValueException);
|
||||||
|
|
|
||||||
|
|
@ -339,7 +339,8 @@ abstract class Coordinate
|
||||||
|
|
||||||
private static function processRangeSetOperators(array $operators, array $cells): array
|
private static function processRangeSetOperators(array $operators, array $cells): array
|
||||||
{
|
{
|
||||||
for ($offset = 0; $offset < count($operators); ++$offset) {
|
$operatorCount = count($operators);
|
||||||
|
for ($offset = 0; $offset < $operatorCount; ++$offset) {
|
||||||
$operator = $operators[$offset];
|
$operator = $operators[$offset];
|
||||||
if ($operator !== ' ') {
|
if ($operator !== ' ') {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -350,6 +351,7 @@ abstract class Coordinate
|
||||||
$operators = array_values($operators);
|
$operators = array_values($operators);
|
||||||
$cells = array_values($cells);
|
$cells = array_values($cells);
|
||||||
--$offset;
|
--$offset;
|
||||||
|
--$operatorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cells;
|
return $cells;
|
||||||
|
|
|
||||||
|
|
@ -506,49 +506,33 @@ class Properties
|
||||||
switch ($propertyType) {
|
switch ($propertyType) {
|
||||||
case 'empty': // Empty
|
case 'empty': // Empty
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
break;
|
|
||||||
case 'null': // Null
|
case 'null': // Null
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'i1': // 1-Byte Signed Integer
|
case 'i1': // 1-Byte Signed Integer
|
||||||
case 'i2': // 2-Byte Signed Integer
|
case 'i2': // 2-Byte Signed Integer
|
||||||
case 'i4': // 4-Byte Signed Integer
|
case 'i4': // 4-Byte Signed Integer
|
||||||
case 'i8': // 8-Byte Signed Integer
|
case 'i8': // 8-Byte Signed Integer
|
||||||
case 'int': // Integer
|
case 'int': // Integer
|
||||||
return (int) $propertyValue;
|
return (int) $propertyValue;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'ui1': // 1-Byte Unsigned Integer
|
case 'ui1': // 1-Byte Unsigned Integer
|
||||||
case 'ui2': // 2-Byte Unsigned Integer
|
case 'ui2': // 2-Byte Unsigned Integer
|
||||||
case 'ui4': // 4-Byte Unsigned Integer
|
case 'ui4': // 4-Byte Unsigned Integer
|
||||||
case 'ui8': // 8-Byte Unsigned Integer
|
case 'ui8': // 8-Byte Unsigned Integer
|
||||||
case 'uint': // Unsigned Integer
|
case 'uint': // Unsigned Integer
|
||||||
return abs((int) $propertyValue);
|
return abs((int) $propertyValue);
|
||||||
|
|
||||||
break;
|
|
||||||
case 'r4': // 4-Byte Real Number
|
case 'r4': // 4-Byte Real Number
|
||||||
case 'r8': // 8-Byte Real Number
|
case 'r8': // 8-Byte Real Number
|
||||||
case 'decimal': // Decimal
|
case 'decimal': // Decimal
|
||||||
return (float) $propertyValue;
|
return (float) $propertyValue;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'lpstr': // LPSTR
|
case 'lpstr': // LPSTR
|
||||||
case 'lpwstr': // LPWSTR
|
case 'lpwstr': // LPWSTR
|
||||||
case 'bstr': // Basic String
|
case 'bstr': // Basic String
|
||||||
return $propertyValue;
|
return $propertyValue;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'date': // Date and Time
|
case 'date': // Date and Time
|
||||||
case 'filetime': // File Time
|
case 'filetime': // File Time
|
||||||
return strtotime($propertyValue);
|
return strtotime($propertyValue);
|
||||||
|
|
||||||
break;
|
|
||||||
case 'bool': // Boolean
|
case 'bool': // Boolean
|
||||||
return $propertyValue == 'true';
|
return $propertyValue == 'true';
|
||||||
|
|
||||||
break;
|
|
||||||
case 'cy': // Currency
|
case 'cy': // Currency
|
||||||
case 'error': // Error Status Code
|
case 'error': // Error Status Code
|
||||||
case 'vector': // Vector
|
case 'vector': // Vector
|
||||||
|
|
@ -563,8 +547,6 @@ class Properties
|
||||||
case 'clsid': // Class ID
|
case 'clsid': // Class ID
|
||||||
case 'cf': // Clipboard Data
|
case 'cf': // Clipboard Data
|
||||||
return $propertyValue;
|
return $propertyValue;
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $propertyValue;
|
return $propertyValue;
|
||||||
|
|
@ -584,31 +566,21 @@ class Properties
|
||||||
case 'ui8': // 8-Byte Unsigned Integer
|
case 'ui8': // 8-Byte Unsigned Integer
|
||||||
case 'uint': // Unsigned Integer
|
case 'uint': // Unsigned Integer
|
||||||
return self::PROPERTY_TYPE_INTEGER;
|
return self::PROPERTY_TYPE_INTEGER;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'r4': // 4-Byte Real Number
|
case 'r4': // 4-Byte Real Number
|
||||||
case 'r8': // 8-Byte Real Number
|
case 'r8': // 8-Byte Real Number
|
||||||
case 'decimal': // Decimal
|
case 'decimal': // Decimal
|
||||||
return self::PROPERTY_TYPE_FLOAT;
|
return self::PROPERTY_TYPE_FLOAT;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'empty': // Empty
|
case 'empty': // Empty
|
||||||
case 'null': // Null
|
case 'null': // Null
|
||||||
case 'lpstr': // LPSTR
|
case 'lpstr': // LPSTR
|
||||||
case 'lpwstr': // LPWSTR
|
case 'lpwstr': // LPWSTR
|
||||||
case 'bstr': // Basic String
|
case 'bstr': // Basic String
|
||||||
return self::PROPERTY_TYPE_STRING;
|
return self::PROPERTY_TYPE_STRING;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'date': // Date and Time
|
case 'date': // Date and Time
|
||||||
case 'filetime': // File Time
|
case 'filetime': // File Time
|
||||||
return self::PROPERTY_TYPE_DATE;
|
return self::PROPERTY_TYPE_DATE;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'bool': // Boolean
|
case 'bool': // Boolean
|
||||||
return self::PROPERTY_TYPE_BOOLEAN;
|
return self::PROPERTY_TYPE_BOOLEAN;
|
||||||
|
|
||||||
break;
|
|
||||||
case 'cy': // Currency
|
case 'cy': // Currency
|
||||||
case 'error': // Error Status Code
|
case 'error': // Error Status Code
|
||||||
case 'vector': // Vector
|
case 'vector': // Vector
|
||||||
|
|
@ -623,8 +595,6 @@ class Properties
|
||||||
case 'clsid': // Class ID
|
case 'clsid': // Class ID
|
||||||
case 'cf': // Clipboard Data
|
case 'cf': // Clipboard Data
|
||||||
return self::PROPERTY_TYPE_UNKNOWN;
|
return self::PROPERTY_TYPE_UNKNOWN;
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::PROPERTY_TYPE_UNKNOWN;
|
return self::PROPERTY_TYPE_UNKNOWN;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue