Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into

develop
This commit is contained in:
Laurent Destailleur
2023-03-28 23:30:26 +02:00
parent 764ce03d10
commit 2663c8f2f2
131 changed files with 8905 additions and 1298 deletions

View File

@@ -0,0 +1,22 @@
<?php
/**
* Bootstrap for PhpSpreadsheet classes.
*/
// This sucks, but we have to try to find the composer autoloader
$paths = [
__DIR__ . '/../vendor/autoload.php', // In case PhpSpreadsheet is cloned directly
__DIR__ . '/../../../autoload.php', // In case PhpSpreadsheet is a composer dependency.
];
foreach ($paths as $path) {
if (file_exists($path)) {
require_once $path;
return;
}
}
throw new \Exception('Composer autoloader could not be found. Install dependencies with `composer install` and try again.');

View File

@@ -25,7 +25,7 @@ class Calculation
// Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?([A-Z][A-Z0-9\.]*)[\s]*\(';
// Cell reference (cell or range of cells, with or without a sheet reference)
const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d{1,7})';
const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])';
// Named Range of cells
const CALCULATION_REGEXP_NAMEDRANGE = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)';
// Error
@@ -66,6 +66,15 @@ class Calculation
*/
private $calculationCacheEnabled = true;
/**
* Used to generate unique store keys.
*
* @var int
*/
private $branchStoreKeyCounter = 0;
private $branchPruningEnabled = true;
/**
* List of operators that can be used within formulae
* The true/false value indicates whether it is a binary operator or a unary operator.
@@ -254,6 +263,11 @@ class Calculation
'functionCall' => [Logical::class, 'logicalAnd'],
'argumentCount' => '1+',
],
'ARABIC' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'ARABIC'],
'argumentCount' => '1',
],
'AREAS' => [
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
'functionCall' => [Functions::class, 'DUMMY'],
@@ -319,6 +333,11 @@ class Calculation
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '1',
],
'BASE' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'BASE'],
'argumentCount' => '2,3',
],
'BESSELI' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BESSELI'],
@@ -527,7 +546,7 @@ class Calculation
],
'COUNTIFS' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [Statistical::class, 'COUNTIFS'],
'argumentCount' => '2+',
],
'COUPDAYBS' => [
@@ -895,6 +914,16 @@ class Calculation
'functionCall' => [MathTrig::class, 'FLOOR'],
'argumentCount' => '2',
],
'FLOOR.MATH' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'FLOORMATH'],
'argumentCount' => '3',
],
'FLOOR.PRECISE' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'FLOORPRECISE'],
'argumentCount' => '2',
],
'FORECAST' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'FORECAST'],
@@ -1018,6 +1047,16 @@ class Calculation
'functionCall' => [Logical::class, 'IFERROR'],
'argumentCount' => '2',
],
'IFNA' => [
'category' => Category::CATEGORY_LOGICAL,
'functionCall' => [Logical::class, 'IFNA'],
'argumentCount' => '2',
],
'IFS' => [
'category' => Category::CATEGORY_LOGICAL,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '2+',
],
'IMABS' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMABS'],
@@ -1356,10 +1395,10 @@ class Calculation
'functionCall' => [Statistical::class, 'MAXA'],
'argumentCount' => '1+',
],
'MAXIF' => [
'MAXIFS' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'MAXIF'],
'argumentCount' => '2+',
'functionCall' => [Statistical::class, 'MAXIFS'],
'argumentCount' => '3+',
],
'MDETERM' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
@@ -1401,10 +1440,10 @@ class Calculation
'functionCall' => [Statistical::class, 'MINA'],
'argumentCount' => '1+',
],
'MINIF' => [
'MINIFS' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'MINIF'],
'argumentCount' => '2+',
'functionCall' => [Statistical::class, 'MINIFS'],
'argumentCount' => '3+',
],
'MINUTE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
@@ -1474,7 +1513,12 @@ class Calculation
'NETWORKDAYS' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'NETWORKDAYS'],
'argumentCount' => '2+',
'argumentCount' => '2-3',
],
'NETWORKDAYS.INTL' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '2-4',
],
'NOMINAL' => [
'category' => Category::CATEGORY_FINANCIAL,
@@ -2143,7 +2187,12 @@ class Calculation
'WORKDAY' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'WORKDAY'],
'argumentCount' => '2+',
'argumentCount' => '2-3',
],
'WORKDAY.INTL' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '2-4',
],
'XIRR' => [
'category' => Category::CATEGORY_FINANCIAL,
@@ -2196,7 +2245,7 @@ class Calculation
private static $controlFunctions = [
'MKMATRIX' => [
'argumentCount' => '*',
'functionCall' => 'self::mkMatrix',
'functionCall' => [__CLASS__, 'mkMatrix'],
],
];
@@ -2251,6 +2300,7 @@ class Calculation
public function flushInstance()
{
$this->clearCalculationCache();
$this->clearBranchStore();
}
/**
@@ -2394,6 +2444,32 @@ class Calculation
}
}
/**
* Enable/disable calculation cache.
*
* @param bool $pValue
* @param mixed $enabled
*/
public function setBranchPruningEnabled($enabled)
{
$this->branchPruningEnabled = $enabled;
}
public function enableBranchPruning()
{
$this->setBranchPruningEnabled(true);
}
public function disableBranchPruning()
{
$this->setBranchPruningEnabled(false);
}
public function clearBranchStore()
{
$this->branchStoreKeyCounter = 0;
}
/**
* Get the currently defined locale code.
*
@@ -2416,7 +2492,7 @@ class Calculation
// Identify our locale and language
$language = $locale = strtolower($locale);
if (strpos($locale, '_') !== false) {
list($language) = explode('_', $locale);
[$language] = explode('_', $locale);
}
if (count(self::$validLocaleLanguages) == 1) {
self::loadLocales();
@@ -2441,9 +2517,9 @@ class Calculation
// 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
[$localeFunction] = explode('##', $localeFunction); // Strip out comments
if (strpos($localeFunction, '=') !== false) {
list($fName, $lfName) = explode('=', $localeFunction);
[$fName, $lfName] = explode('=', $localeFunction);
$fName = trim($fName);
$lfName = trim($lfName);
if ((isset(self::$phpSpreadsheetFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) {
@@ -2466,9 +2542,9 @@ class Calculation
if (file_exists($configFile)) {
$localeSettings = file($configFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($localeSettings as $localeSetting) {
list($localeSetting) = explode('##', $localeSetting); // Strip out comments
[$localeSetting] = explode('##', $localeSetting); // Strip out comments
if (strpos($localeSetting, '=') !== false) {
list($settingName, $settingValue) = explode('=', $localeSetting);
[$settingName, $settingValue] = explode('=', $localeSetting);
$settingName = strtoupper(trim($settingName));
switch ($settingName) {
case 'ARGUMENTSEPARATOR':
@@ -2772,7 +2848,7 @@ class Calculation
}
self::$returnArrayAsType = $returnArrayAsType;
if ($result === null) {
if ($result === null && $pCell->getWorksheet()->getSheetView()->getShowZeros()) {
return 0;
} elseif ((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) {
return Functions::NAN();
@@ -2823,13 +2899,13 @@ class Calculation
$this->debugLog->clearLog();
$this->cyclicReferenceStack->clear();
$resetCache = $this->getCalculationCacheEnabled();
if ($this->spreadsheet !== null && $cellID === null && $pCell === null) {
$cellID = 'A1';
$pCell = $this->spreadsheet->getActiveSheet()->getCell($cellID);
} else {
// Disable calculation cacheing because it only applies to cell calculations, not straight formulae
// But don't actually flush any cache
$resetCache = $this->getCalculationCacheEnabled();
$this->calculationCacheEnabled = false;
}
@@ -2862,6 +2938,7 @@ class Calculation
if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
$this->debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache');
// Return the cached result
$cellValue = $this->calculationCache[$cellReference];
return true;
@@ -2977,17 +3054,17 @@ class Calculation
// Examine each of the two operands, and turn them into an array if they aren't one already
// Note that this function should only be called if one or both of the operand is already an array
if (!is_array($operand1)) {
list($matrixRows, $matrixColumns) = self::getMatrixDimensions($operand2);
[$matrixRows, $matrixColumns] = self::getMatrixDimensions($operand2);
$operand1 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand1));
$resize = 0;
} elseif (!is_array($operand2)) {
list($matrixRows, $matrixColumns) = self::getMatrixDimensions($operand1);
[$matrixRows, $matrixColumns] = self::getMatrixDimensions($operand1);
$operand2 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand2));
$resize = 0;
}
list($matrix1Rows, $matrix1Columns) = self::getMatrixDimensions($operand1);
list($matrix2Rows, $matrix2Columns) = self::getMatrixDimensions($operand2);
[$matrix1Rows, $matrix1Columns] = self::getMatrixDimensions($operand1);
[$matrix2Rows, $matrix2Columns] = self::getMatrixDimensions($operand2);
if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
$resize = 1;
}
@@ -3197,7 +3274,7 @@ class Calculation
/**
* @param string $formula
*
* @return string
* @return false|string False indicates an error
*/
private function convertMatrixReferences($formula)
{
@@ -3321,9 +3398,53 @@ class Calculation
// - 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
// should be null in a function call
// IF branch pruning
// currently pending storeKey (last item of the storeKeysStack
$pendingStoreKey = null;
// stores a list of storeKeys (string[])
$pendingStoreKeysStack = [];
$expectingConditionMap = []; // ['storeKey' => true, ...]
$expectingThenMap = []; // ['storeKey' => true, ...]
$expectingElseMap = []; // ['storeKey' => true, ...]
$parenthesisDepthMap = []; // ['storeKey' => 4, ...]
// The guts of the lexical parser
// Loop through the formula extracting each operator and operand in turn
while (true) {
// Branch pruning: we adapt the output item to the context (it will
// be used to limit its computation)
$currentCondition = null;
$currentOnlyIf = null;
$currentOnlyIfNot = null;
$previousStoreKey = null;
$pendingStoreKey = end($pendingStoreKeysStack);
if ($this->branchPruningEnabled) {
// this is a condition ?
if (isset($expectingConditionMap[$pendingStoreKey]) && $expectingConditionMap[$pendingStoreKey]) {
$currentCondition = $pendingStoreKey;
$stackDepth = count($pendingStoreKeysStack);
if ($stackDepth > 1) { // nested if
$previousStoreKey = $pendingStoreKeysStack[$stackDepth - 2];
}
}
if (isset($expectingThenMap[$pendingStoreKey]) && $expectingThenMap[$pendingStoreKey]) {
$currentOnlyIf = $pendingStoreKey;
} elseif (isset($previousStoreKey)) {
if (isset($expectingThenMap[$previousStoreKey]) && $expectingThenMap[$previousStoreKey]) {
$currentOnlyIf = $previousStoreKey;
}
}
if (isset($expectingElseMap[$pendingStoreKey]) && $expectingElseMap[$pendingStoreKey]) {
$currentOnlyIfNot = $pendingStoreKey;
} elseif (isset($previousStoreKey)) {
if (isset($expectingElseMap[$previousStoreKey]) && $expectingElseMap[$previousStoreKey]) {
$currentOnlyIfNot = $previousStoreKey;
}
}
}
$opCharacter = $formula[$index]; // Get the first character of the value at the current index position
if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula[$index + 1]]))) {
$opCharacter .= $formula[++$index];
@@ -3333,10 +3454,12 @@ class Calculation
$isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus?
$stack->push('Unary Operator', '~'); // Put a negation on the stack
// Put a negation on the stack
$stack->push('Unary Operator', '~', null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
++$index; // and drop the negation symbol
} elseif ($opCharacter == '%' && $expectingOperator) {
$stack->push('Unary Operator', '%'); // Put a percentage on the stack
// Put a percentage on the stack
$stack->push('Unary Operator', '%', null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
++$index;
} elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded?
++$index; // Drop the redundant plus symbol
@@ -3349,7 +3472,10 @@ class Calculation
@(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
// Finally put our current operator onto the stack
$stack->push('Binary Operator', $opCharacter, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
++$index;
$expectingOperator = false;
} elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis?
@@ -3361,7 +3487,29 @@ class Calculation
$output[] = $o2;
}
$d = $stack->last(2);
if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $d['value'], $matches)) { // Did this parenthesis just close a function?
// Branch pruning we decrease the depth whether is it a function
// call or a parenthesis
if (!empty($pendingStoreKey)) {
$parenthesisDepthMap[$pendingStoreKey] -= 1;
}
if (is_array($d) && preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $d['value'], $matches)) { // Did this parenthesis just close a function?
if (!empty($pendingStoreKey) && $parenthesisDepthMap[$pendingStoreKey] == -1) {
// we are closing an IF(
if ($d['value'] != 'IF(') {
return $this->raiseFormulaError('Parser bug we should be in an "IF("');
}
if ($expectingConditionMap[$pendingStoreKey]) {
return $this->raiseFormulaError('We should not be expecting a condition');
}
$expectingThenMap[$pendingStoreKey] = false;
$expectingElseMap[$pendingStoreKey] = false;
$parenthesisDepthMap[$pendingStoreKey] -= 1;
array_pop($pendingStoreKeysStack);
unset($pendingStoreKey);
}
$functionName = $matches[1]; // Get the function name
$d = $stack->pop();
$argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack)
@@ -3422,6 +3570,20 @@ class Calculation
}
++$index;
} elseif ($opCharacter == ',') { // Is this the separator for function arguments?
if (!empty($pendingStoreKey) &&
$parenthesisDepthMap[$pendingStoreKey] == 0
) {
// We must go to the IF next argument
if ($expectingConditionMap[$pendingStoreKey]) {
$expectingConditionMap[$pendingStoreKey] = false;
$expectingThenMap[$pendingStoreKey] = true;
} elseif ($expectingThenMap[$pendingStoreKey]) {
$expectingThenMap[$pendingStoreKey] = false;
$expectingElseMap[$pendingStoreKey] = true;
} elseif ($expectingElseMap[$pendingStoreKey]) {
return $this->raiseFormulaError('Reaching fourth argument of an IF');
}
}
while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
if ($o2 === null) {
return $this->raiseFormulaError('Formula Error: Unexpected ,');
@@ -3439,13 +3601,19 @@ class Calculation
return $this->raiseFormulaError('Formula Error: Unexpected ,');
}
$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
$itemStoreKey = $d['storeKey'] ?? null;
$itemOnlyIf = $d['onlyIf'] ?? null;
$itemOnlyIfNot = $d['onlyIfNot'] ?? null;
$stack->push($d['type'], ++$d['value'], $d['reference'], $itemStoreKey, $itemOnlyIf, $itemOnlyIfNot); // increment the argument count
$stack->push('Brace', '(', null, $itemStoreKey, $itemOnlyIf, $itemOnlyIfNot); // put the ( back on, we'll need to pop back to it again
$expectingOperator = false;
$expectingOperand = true;
++$index;
} elseif ($opCharacter == '(' && !$expectingOperator) {
$stack->push('Brace', '(');
if (!empty($pendingStoreKey)) { // Branch pruning: we go deeper
$parenthesisDepthMap[$pendingStoreKey] += 1;
}
$stack->push('Brace', '(', null, $currentCondition, $currentOnlyIf, $currentOnlyIf);
++$index;
} elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number?
$expectingOperator = true;
@@ -3456,13 +3624,28 @@ class Calculation
if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $val, $matches)) {
$val = preg_replace('/\s/u', '', $val);
if (isset(self::$phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function
$stack->push('Function', strtoupper($val));
$valToUpper = strtoupper($val);
// here $matches[1] will contain values like "IF"
// and $val "IF("
if ($this->branchPruningEnabled && ($valToUpper == 'IF(')) { // we handle a new if
$pendingStoreKey = $this->getUnusedBranchStoreKey();
$pendingStoreKeysStack[] = $pendingStoreKey;
$expectingConditionMap[$pendingStoreKey] = true;
$parenthesisDepthMap[$pendingStoreKey] = 0;
} else { // this is not a if but we good deeper
if (!empty($pendingStoreKey) && array_key_exists($pendingStoreKey, $parenthesisDepthMap)) {
$parenthesisDepthMap[$pendingStoreKey] += 1;
}
}
$stack->push('Function', $valToUpper, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
// tests if the function is closed right after opening
$ax = preg_match('/^\s*(\s*\))/ui', substr($formula, $index + $length), $amatch);
if ($ax) {
$stack->push('Operand Count for Function ' . strtoupper($val) . ')', 0);
$stack->push('Operand Count for Function ' . $valToUpper . ')', 0, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
$expectingOperator = true;
} else {
$stack->push('Operand Count for Function ' . strtoupper($val) . ')', 1);
$stack->push('Operand Count for Function ' . $valToUpper . ')', 1, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
$expectingOperator = false;
}
$stack->push('Brace', '(');
@@ -3475,7 +3658,7 @@ class Calculation
// If the last entry on the stack was a : operator, then we have a cell range reference
$testPrevOp = $stack->last(1);
if ($testPrevOp['value'] == ':') {
if ($testPrevOp !== null && $testPrevOp['value'] == ':') {
// If we have a worksheet reference, then we're playing with a 3D reference
if ($matches[2] == '') {
// Otherwise, we 'inherit' the worksheet reference from the start cell reference
@@ -3490,32 +3673,39 @@ class Calculation
}
}
$output[] = ['type' => 'Cell Reference', 'value' => $val, 'reference' => $val];
$outputItem = $stack->getStackItem('Cell Reference', $val, $val, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
$output[] = $outputItem;
} else { // it's 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
$testPrevOp = $stack->last(1);
if ($testPrevOp['value'] == ':') {
if ($testPrevOp !== null && $testPrevOp['value'] === ':') {
$startRowColRef = $output[count($output) - 1]['value'];
list($rangeWS1, $startRowColRef) = Worksheet::extractSheetTitle($startRowColRef, true);
[$rangeWS1, $startRowColRef] = Worksheet::extractSheetTitle($startRowColRef, true);
$rangeSheetRef = $rangeWS1;
if ($rangeWS1 != '') {
$rangeWS1 .= '!';
}
list($rangeWS2, $val) = Worksheet::extractSheetTitle($val, true);
[$rangeWS2, $val] = Worksheet::extractSheetTitle($val, true);
if ($rangeWS2 != '') {
$rangeWS2 .= '!';
} else {
$rangeWS2 = $rangeWS1;
}
$refSheet = $pCellParent;
if ($pCellParent !== null && $rangeSheetRef !== $pCellParent->getTitle()) {
$refSheet = $pCellParent->getParent()->getSheetByName($rangeSheetRef);
}
if ((is_int($startRowColRef)) && (ctype_digit($val)) &&
($startRowColRef <= 1048576) && ($val <= 1048576)) {
// Row range
$endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007
$endRowColRef = ($refSheet !== null) ? $refSheet->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007
$output[count($output) - 1]['value'] = $rangeWS1 . 'A' . $startRowColRef;
$val = $rangeWS2 . $endRowColRef . $val;
} elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
(strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
// Column range
$endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007
$endRowColRef = ($refSheet !== null) ? $refSheet->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007
$output[count($output) - 1]['value'] = $rangeWS1 . strtoupper($startRowColRef) . '1';
$val = $rangeWS2 . $val . $endRowColRef;
}
@@ -3537,7 +3727,7 @@ class Calculation
} elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$localeBoolean)) !== false) {
$val = self::$excelConstants[$localeConstant];
}
$details = ['type' => 'Value', 'value' => $val, 'reference' => null];
$details = $stack->getStackItem('Value', $val, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
if ($localeConstant) {
$details['localeValue'] = $localeConstant;
}
@@ -3557,7 +3747,7 @@ class Calculation
} elseif (isset(self::$operators[$opCharacter]) && !$expectingOperator) {
return $this->raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
} else { // I don't even want to know what you did to get here
return $this->raiseFormulaError('Formula Error: An unexpected error occured');
return $this->raiseFormulaError('Formula Error: An unexpected error occurred');
}
// Test for end of formula string
if ($index == strlen($formula)) {
@@ -3640,9 +3830,85 @@ class Calculation
$pCellParent = ($pCell !== null) ? $pCell->getParent() : null;
$stack = new Stack();
// Stores branches that have been pruned
$fakedForBranchPruning = [];
// help us to know when pruning ['branchTestId' => true/false]
$branchStore = [];
// Loop through each token in turn
foreach ($tokens as $tokenData) {
$token = $tokenData['value'];
// Branch pruning: skip useless resolutions
$storeKey = $tokenData['storeKey'] ?? null;
if ($this->branchPruningEnabled && isset($tokenData['onlyIf'])) {
$onlyIfStoreKey = $tokenData['onlyIf'];
$storeValue = $branchStore[$onlyIfStoreKey] ?? null;
$storeValueAsBool = ($storeValue === null) ?
true : (bool) Functions::flattenSingleValue($storeValue);
if (is_array($storeValue)) {
$wrappedItem = end($storeValue);
$storeValue = end($wrappedItem);
}
if (isset($storeValue)
&& (
!$storeValueAsBool
|| Functions::isError($storeValue)
|| ($storeValue === 'Pruned branch')
)
) {
// If branching value is not true, we don't need to compute
if (!isset($fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey])) {
$stack->push('Value', 'Pruned branch (only if ' . $onlyIfStoreKey . ') ' . $token);
$fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey] = true;
}
if (isset($storeKey)) {
// We are processing an if condition
// We cascade the pruning to the depending branches
$branchStore[$storeKey] = 'Pruned branch';
$fakedForBranchPruning['onlyIfNot-' . $storeKey] = true;
$fakedForBranchPruning['onlyIf-' . $storeKey] = true;
}
continue;
}
}
if ($this->branchPruningEnabled && isset($tokenData['onlyIfNot'])) {
$onlyIfNotStoreKey = $tokenData['onlyIfNot'];
$storeValue = $branchStore[$onlyIfNotStoreKey] ?? null;
$storeValueAsBool = ($storeValue === null) ?
true : (bool) Functions::flattenSingleValue($storeValue);
if (is_array($storeValue)) {
$wrappedItem = end($storeValue);
$storeValue = end($wrappedItem);
}
if (isset($storeValue)
&& (
$storeValueAsBool
|| Functions::isError($storeValue)
|| ($storeValue === 'Pruned branch'))
) {
// If branching value is true, we don't need to compute
if (!isset($fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey])) {
$stack->push('Value', 'Pruned branch (only if not ' . $onlyIfNotStoreKey . ') ' . $token);
$fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey] = true;
}
if (isset($storeKey)) {
// We are processing an if condition
// We cascade the pruning to the depending branches
$branchStore[$storeKey] = 'Pruned branch';
$fakedForBranchPruning['onlyIfNot-' . $storeKey] = true;
$fakedForBranchPruning['onlyIf-' . $storeKey] = true;
}
continue;
}
}
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
if (isset(self::$binaryOperators[$token])) {
// We must have two operands, error if we don't
@@ -3672,18 +3938,21 @@ class Calculation
case '<=': // Less than or Equal to
case '=': // Equality
case '<>': // Inequality
$this->executeBinaryComparisonOperation($cellID, $operand1, $operand2, $token, $stack);
$result = $this->executeBinaryComparisonOperation($cellID, $operand1, $operand2, $token, $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
// Binary Operators
case ':': // Range
if (strpos($operand1Data['reference'], '!') !== false) {
list($sheet1, $operand1Data['reference']) = Worksheet::extractSheetTitle($operand1Data['reference'], true);
[$sheet1, $operand1Data['reference']] = Worksheet::extractSheetTitle($operand1Data['reference'], true);
} else {
$sheet1 = ($pCellParent !== null) ? $pCellWorksheet->getTitle() : '';
}
list($sheet2, $operand2Data['reference']) = Worksheet::extractSheetTitle($operand2Data['reference'], true);
[$sheet2, $operand2Data['reference']] = Worksheet::extractSheetTitle($operand2Data['reference'], true);
if (empty($sheet2)) {
$sheet2 = $sheet1;
}
@@ -3728,23 +3997,38 @@ class Calculation
break;
case '+': // Addition
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'plusEquals', $stack);
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'plusEquals', $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
case '-': // Subtraction
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'minusEquals', $stack);
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'minusEquals', $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
case '*': // Multiplication
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayTimesEquals', $stack);
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayTimesEquals', $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
case '/': // Division
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayRightDivide', $stack);
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayRightDivide', $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
case '^': // Exponential
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'power', $stack);
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'power', $stack);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
case '&': // Concatenation
@@ -3777,6 +4061,10 @@ class Calculation
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
$stack->push('Value', $result);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
break;
case '|': // Intersect
$rowIntersect = array_intersect_key($operand1, $operand2);
@@ -3821,6 +4109,9 @@ class Calculation
}
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
$stack->push('Value', $result);
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
} else {
$this->executeNumericBinaryOperation($multiplier, $arg, '*', 'arrayTimesEquals', $stack);
}
@@ -3894,9 +4185,16 @@ class Calculation
}
}
$stack->push('Value', $cellValue, $cellRef);
if (isset($storeKey)) {
$branchStore[$storeKey] = $cellValue;
}
// if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
// if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $token, $matches)) {
if ($pCellParent) {
$pCell->attach($pCellParent);
}
$functionName = $matches[1];
$argCount = $stack->pop();
$argCount = $argCount['value'];
@@ -3939,6 +4237,7 @@ class Calculation
}
}
}
// Reverse the order of the arguments
krsort($args);
@@ -3963,22 +4262,32 @@ class Calculation
}
unset($arg);
}
$result = call_user_func_array($functionCall, $args);
if ($functionName != 'MKMATRIX') {
$this->debugLog->writeDebugLog('Evaluation Result for ', self::localeFunc($functionName), '() function call is ', $this->showTypeDetails($result));
}
$stack->push('Value', self::wrapResult($result));
if (isset($storeKey)) {
$branchStore[$storeKey] = $result;
}
}
} else {
// if the token is a number, boolean, string or an Excel error, push it onto the stack
if (isset(self::$excelConstants[strtoupper($token)])) {
$excelConstant = strtoupper($token);
$stack->push('Constant Value', self::$excelConstants[$excelConstant]);
if (isset($storeKey)) {
$branchStore[$storeKey] = 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] == '#')) {
$stack->push('Value', $token);
// if the token is a named range, push the named range name onto the stack
if (isset($storeKey)) {
$branchStore[$storeKey] = $token;
}
// if the token is a named range, push the named range name onto the stack
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_NAMEDRANGE . '$/i', $token, $matches)) {
$namedRange = $matches[6];
$this->debugLog->writeDebugLog('Evaluating Named Range ', $namedRange);
@@ -3987,6 +4296,9 @@ class Calculation
$pCell->attach($pCellParent);
$this->debugLog->writeDebugLog('Evaluation Result for named range ', $namedRange, ' is ', $this->showTypeDetails($cellValue));
$stack->push('Named Range', $cellValue, $namedRange);
if (isset($storeKey)) {
$branchStore[$storeKey] = $cellValue;
}
} else {
return $this->raiseFormulaError("undefined variable '$token'");
}
@@ -4048,7 +4360,7 @@ class Calculation
* @param Stack $stack
* @param bool $recursingArrays
*
* @return bool
* @return mixed
*/
private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
{
@@ -4085,7 +4397,7 @@ class Calculation
// And push the result onto the stack
$stack->push('Array', $result);
return true;
return $result;
}
// Simple validate the two operands if they are string values
@@ -4175,7 +4487,7 @@ class Calculation
// And push the result onto the stack
$stack->push('Value', $result);
return true;
return $result;
}
/**
@@ -4201,7 +4513,7 @@ class Calculation
* @param string $matrixFunction
* @param mixed $stack
*
* @return bool
* @return bool|mixed
*/
private function executeNumericBinaryOperation($operand1, $operand2, $operation, $matrixFunction, &$stack)
{
@@ -4279,7 +4591,7 @@ class Calculation
// And push the result onto the stack
$stack->push('Value', $result);
return true;
return $result;
}
// trigger an error, but nicely, if need be
@@ -4312,7 +4624,7 @@ class Calculation
if ($pSheet !== null) {
$pSheetName = $pSheet->getTitle();
if (strpos($pRange, '!') !== false) {
list($pSheetName, $pRange) = Worksheet::extractSheetTitle($pRange, true);
[$pSheetName, $pRange] = Worksheet::extractSheetTitle($pRange, true);
$pSheet = $this->spreadsheet->getSheetByName($pSheetName);
}
@@ -4365,7 +4677,7 @@ class Calculation
if ($pSheet !== null) {
$pSheetName = $pSheet->getTitle();
if (strpos($pRange, '!') !== false) {
list($pSheetName, $pRange) = Worksheet::extractSheetTitle($pRange, true);
[$pSheetName, $pRange] = Worksheet::extractSheetTitle($pRange, true);
$pSheet = $this->spreadsheet->getSheetByName($pSheetName);
}
@@ -4389,7 +4701,7 @@ class Calculation
$aReferences = Coordinate::extractAllCellReferencesInRange($pRange);
if (!isset($aReferences[1])) {
// Single cell (or single column or row) in range
list($currentCol, $currentRow) = Coordinate::coordinateFromString($aReferences[0]);
[$currentCol, $currentRow] = Coordinate::coordinateFromString($aReferences[0]);
if ($pSheet->cellExists($aReferences[0])) {
$returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
} else {
@@ -4399,7 +4711,7 @@ class Calculation
// Extract cell data for all cells in the range
foreach ($aReferences as $reference) {
// Extract range
list($currentCol, $currentRow) = Coordinate::coordinateFromString($reference);
[$currentCol, $currentRow] = Coordinate::coordinateFromString($reference);
if ($pSheet->cellExists($reference)) {
$returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
} else {
@@ -4483,4 +4795,26 @@ class Calculation
return $args;
}
private function getUnusedBranchStoreKey()
{
$storeKeyValue = 'storeKey-' . $this->branchStoreKeyCounter;
++$this->branchStoreKeyCounter;
return $storeKeyValue;
}
private function getTokensAsString($tokens)
{
$tokensStr = array_map(function ($token) {
$value = $token['value'] ?? 'no value';
while (is_array($value)) {
$value = array_pop($value);
}
return $value;
}, $tokens);
return '[ ' . implode(' | ', $tokensStr) . ' ]';
}
}

View File

@@ -147,7 +147,7 @@ class Database
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function DAVERAGE($database, $field, $criteria)
{
@@ -452,7 +452,7 @@ class Database
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function DSTDEV($database, $field, $criteria)
{
@@ -493,7 +493,7 @@ class Database
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function DSTDEVP($database, $field, $criteria)
{

View File

@@ -16,7 +16,7 @@ class DateTime
*/
public static function isLeapYear($year)
{
return (($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0);
return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0);
}
/**
@@ -156,11 +156,11 @@ class DateTime
$retValue = (float) Date::PHPToExcel(time());
break;
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
$retValue = (int) time();
break;
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
$retValue = new \DateTime();
break;
@@ -200,11 +200,11 @@ class DateTime
$retValue = (float) $excelDateTime;
break;
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
$retValue = (int) Date::excelToTimestamp($excelDateTime);
break;
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
$retValue = Date::excelToDateTimeObject($excelDateTime);
break;
@@ -325,9 +325,9 @@ class DateTime
switch (Functions::getReturnDateType()) {
case Functions::RETURNDATE_EXCEL:
return (float) $excelDateValue;
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) Date::excelToTimestamp($excelDateValue);
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
return Date::excelToDateTimeObject($excelDateValue);
}
}
@@ -420,9 +420,9 @@ class DateTime
}
return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
$dayAdjust = 0;
if ($hour < 0) {
$dayAdjust = floor($hour / 24);
@@ -472,7 +472,6 @@ class DateTime
*/
public static function DATEVALUE($dateValue = 1)
{
$dateValueOrig = $dateValue;
$dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
// Strip any ordinals because they're allowed in Excel (English only)
$dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
@@ -492,7 +491,7 @@ class DateTime
$yearFound = true;
}
}
if ((count($t1) == 1) && (strpos($t, ':') != false)) {
if ((count($t1) == 1) && (strpos($t, ':') !== false)) {
// We've been fed a time value without any date
return 0.0;
} elseif (count($t1) == 2) {
@@ -569,9 +568,9 @@ class DateTime
switch (Functions::getReturnDateType()) {
case Functions::RETURNDATE_EXCEL:
return (float) $excelDateValue;
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) Date::excelToTimestamp($excelDateValue);
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
return new \DateTime($PHPDateArray['year'] . '-' . $PHPDateArray['month'] . '-' . $PHPDateArray['day'] . ' 00:00:00');
}
}
@@ -631,9 +630,9 @@ class DateTime
switch (Functions::getReturnDateType()) {
case Functions::RETURNDATE_EXCEL:
return (float) $excelDateValue;
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600;
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
return new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']);
}
}
@@ -683,7 +682,6 @@ class DateTime
$endMonths = $PHPEndDateObject->format('n');
$endYears = $PHPEndDateObject->format('Y');
$retVal = Functions::NAN();
switch ($unit) {
case 'D':
$retVal = (int) $difference;
@@ -880,6 +878,8 @@ class DateTime
*
* Excel Function:
* YEARFRAC(startDate,endDate[,method])
* See https://lists.oasis-open.org/archives/office-formula/200806/msg00039.html
* for description of algorithm used in Excel
*
* @category Date/Time Functions
*
@@ -894,7 +894,7 @@ class DateTime
* 3 Actual/365
* 4 European 30/360
*
* @return float fraction of the year
* @return float|string fraction of the year, or a string containing an error
*/
public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
{
@@ -908,6 +908,11 @@ class DateTime
if (is_string($endDate = self::getDateValue($endDate))) {
return Functions::VALUE();
}
if ($startDate > $endDate) {
$temp = $startDate;
$startDate = $endDate;
$endDate = $temp;
}
if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
switch ($method) {
@@ -918,46 +923,43 @@ class DateTime
$startYear = self::YEAR($startDate);
$endYear = self::YEAR($endDate);
$years = $endYear - $startYear + 1;
$leapDays = 0;
$startMonth = self::MONTHOFYEAR($startDate);
$startDay = self::DAYOFMONTH($startDate);
$endMonth = self::MONTHOFYEAR($endDate);
$endDay = self::DAYOFMONTH($endDate);
$startMonthDay = 100 * $startMonth + $startDay;
$endMonthDay = 100 * $endMonth + $endDay;
if ($years == 1) {
if (self::isLeapYear($endYear)) {
$startMonth = self::MONTHOFYEAR($startDate);
$endMonth = self::MONTHOFYEAR($endDate);
$endDay = self::DAYOFMONTH($endDate);
if (($startMonth < 3) ||
(($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
$leapDays += 1;
$tmpCalcAnnualBasis = 366;
} else {
$tmpCalcAnnualBasis = 365;
}
} elseif ($years == 2 && $startMonthDay >= $endMonthDay) {
if (self::isLeapYear($startYear)) {
if ($startMonthDay <= 229) {
$tmpCalcAnnualBasis = 366;
} else {
$tmpCalcAnnualBasis = 365;
}
} elseif (self::isLeapYear($endYear)) {
if ($endMonthDay >= 229) {
$tmpCalcAnnualBasis = 366;
} else {
$tmpCalcAnnualBasis = 365;
}
} else {
$tmpCalcAnnualBasis = 365;
}
} else {
$tmpCalcAnnualBasis = 0;
for ($year = $startYear; $year <= $endYear; ++$year) {
if ($year == $startYear) {
$startMonth = self::MONTHOFYEAR($startDate);
$startDay = self::DAYOFMONTH($startDate);
if ($startMonth < 3) {
$leapDays += (self::isLeapYear($year)) ? 1 : 0;
}
} elseif ($year == $endYear) {
$endMonth = self::MONTHOFYEAR($endDate);
$endDay = self::DAYOFMONTH($endDate);
if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
$leapDays += (self::isLeapYear($year)) ? 1 : 0;
}
} else {
$leapDays += (self::isLeapYear($year)) ? 1 : 0;
}
$tmpCalcAnnualBasis += self::isLeapYear($year) ? 366 : 365;
}
if ($years == 2) {
if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
$leapDays = 1;
} elseif ($days < 366) {
$years = 1;
}
}
$leapDays /= $years;
$tmpCalcAnnualBasis /= $years;
}
return $days / (365 + $leapDays);
return $days / $tmpCalcAnnualBasis;
case 2:
return self::DATEDIF($startDate, $endDate) / 360;
case 3:
@@ -1154,9 +1156,9 @@ class DateTime
switch (Functions::getReturnDateType()) {
case Functions::RETURNDATE_EXCEL:
return (float) $endDate;
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) Date::excelToTimestamp($endDate);
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
return Date::excelToDateTimeObject($endDate);
}
}
@@ -1239,7 +1241,7 @@ class DateTime
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
$DoW = $PHPDateObject->format('w');
$DoW = (int) $PHPDateObject->format('w');
$firstDay = 1;
switch ($style) {
@@ -1248,13 +1250,13 @@ class DateTime
break;
case 2:
if ($DoW == 0) {
if ($DoW === 0) {
$DoW = 7;
}
break;
case 3:
if ($DoW == 0) {
if ($DoW === 0) {
$DoW = 7;
}
$firstDay = 0;
@@ -1272,9 +1274,39 @@ class DateTime
}
}
return (int) $DoW;
return $DoW;
}
const STARTWEEK_SUNDAY = 1;
const STARTWEEK_MONDAY = 2;
const STARTWEEK_MONDAY_ALT = 11;
const STARTWEEK_TUESDAY = 12;
const STARTWEEK_WEDNESDAY = 13;
const STARTWEEK_THURSDAY = 14;
const STARTWEEK_FRIDAY = 15;
const STARTWEEK_SATURDAY = 16;
const STARTWEEK_SUNDAY_ALT = 17;
const DOW_SUNDAY = 1;
const DOW_MONDAY = 2;
const DOW_TUESDAY = 3;
const DOW_WEDNESDAY = 4;
const DOW_THURSDAY = 5;
const DOW_FRIDAY = 6;
const DOW_SATURDAY = 7;
const STARTWEEK_MONDAY_ISO = 21;
const METHODARR = [
self::STARTWEEK_SUNDAY => self::DOW_SUNDAY,
self::DOW_MONDAY,
self::STARTWEEK_MONDAY_ALT => self::DOW_MONDAY,
self::DOW_TUESDAY,
self::DOW_WEDNESDAY,
self::DOW_THURSDAY,
self::DOW_FRIDAY,
self::DOW_SATURDAY,
self::DOW_SUNDAY,
self::STARTWEEK_MONDAY_ISO => self::STARTWEEK_MONDAY_ISO,
];
/**
* WEEKNUM.
*
@@ -1293,41 +1325,51 @@ class DateTime
* @param int $method Week begins on Sunday or Monday
* 1 or omitted Week begins on Sunday.
* 2 Week begins on Monday.
* 11 Week begins on Monday.
* 12 Week begins on Tuesday.
* 13 Week begins on Wednesday.
* 14 Week begins on Thursday.
* 15 Week begins on Friday.
* 16 Week begins on Saturday.
* 17 Week begins on Sunday.
* 21 ISO (Jan. 4 is week 1, begins on Monday).
*
* @return int|string Week Number
*/
public static function WEEKNUM($dateValue = 1, $method = 1)
public static function WEEKNUM($dateValue = 1, $method = self::STARTWEEK_SUNDAY)
{
$dateValue = Functions::flattenSingleValue($dateValue);
$method = Functions::flattenSingleValue($method);
if (!is_numeric($method)) {
return Functions::VALUE();
} elseif (($method < 1) || ($method > 2)) {
return Functions::NAN();
}
$method = floor($method);
$method = (int) $method;
if (!array_key_exists($method, self::METHODARR)) {
return Functions::NaN();
}
$method = self::METHODARR[$method];
if ($dateValue === null) {
$dateValue = 1;
} elseif (is_string($dateValue = self::getDateValue($dateValue))) {
$dateValue = self::getDateValue($dateValue);
if (is_string($dateValue)) {
return Functions::VALUE();
} elseif ($dateValue < 0.0) {
}
if ($dateValue < 0.0) {
return Functions::NAN();
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
if ($method == self::STARTWEEK_MONDAY_ISO) {
return (int) $PHPDateObject->format('W');
}
$dayOfYear = $PHPDateObject->format('z');
$PHPDateObject->modify('-' . $dayOfYear . ' days');
$firstDayOfFirstWeek = $PHPDateObject->format('w');
$daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
$interval = $dayOfYear - $daysInFirstWeek;
$weekOfYear = floor($interval / 7) + 1;
if ($daysInFirstWeek) {
++$weekOfYear;
}
$daysInFirstWeek += 7 * !$daysInFirstWeek;
$endFirstWeek = $daysInFirstWeek - 1;
$weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7);
return (int) $weekOfYear;
}
@@ -1591,9 +1633,9 @@ class DateTime
switch (Functions::getReturnDateType()) {
case Functions::RETURNDATE_EXCEL:
return (float) Date::PHPToExcel($PHPDateObject);
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
return $PHPDateObject;
}
}
@@ -1640,9 +1682,9 @@ class DateTime
switch (Functions::getReturnDateType()) {
case Functions::RETURNDATE_EXCEL:
return (float) Date::PHPToExcel($PHPDateObject);
case Functions::RETURNDATE_PHP_NUMERIC:
case Functions::RETURNDATE_UNIX_TIMESTAMP:
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
case Functions::RETURNDATE_PHP_OBJECT:
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
return $PHPDateObject;
}
}

View File

@@ -785,7 +785,7 @@ class Engineering
* If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
* If $ord < 0, BESSELI returns the #NUM! error value.
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function BESSELI($x, $ord)
{
@@ -839,7 +839,7 @@ class Engineering
* If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
* If $ord < 0, BESSELJ returns the #NUM! error value.
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function BESSELJ($x, $ord)
{
@@ -932,7 +932,7 @@ class Engineering
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
* If $ord < 0, BESSELK returns the #NUM! error value.
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function BESSELK($x, $ord)
{
@@ -1021,7 +1021,7 @@ class Engineering
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
* If $ord < 0, BESSELK returns the #NUM! error value.
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function BESSELY($x, $ord)
{
@@ -2713,7 +2713,7 @@ class Engineering
* @param string $fromUOM the units for value
* @param string $toUOM the units for the result
*
* @return float
* @return float|string
*/
public static function CONVERTUOM($value, $fromUOM, $toUOM)
{

View File

@@ -71,7 +71,7 @@ class Financial
* 3 365
* 4 European 360
*
* @return int
* @return int|string Result, or a string containing an error
*/
private static function daysPerYear($year, $basis = 0)
{
@@ -144,7 +144,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
{
@@ -197,7 +197,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
{
@@ -417,7 +417,7 @@ class Financial
return Functions::VALUE();
}
if (($settlement > $maturity) ||
if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) {
return Functions::NAN();
@@ -476,7 +476,7 @@ class Financial
return Functions::VALUE();
}
if (($settlement > $maturity) ||
if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) {
return Functions::NAN();
@@ -550,7 +550,7 @@ class Financial
return Functions::VALUE();
}
if (($settlement > $maturity) ||
if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) {
return Functions::NAN();
@@ -610,7 +610,7 @@ class Financial
return Functions::VALUE();
}
if (($settlement > $maturity) ||
if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) {
return Functions::NAN();
@@ -667,26 +667,22 @@ class Financial
return Functions::VALUE();
}
if (($settlement > $maturity) ||
if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) {
return Functions::NAN();
}
$settlement = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true);
$daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis) * 365;
$daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis);
$daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis) * $daysPerYear;
switch ($frequency) {
case 1: // annual payments
return ceil($daysBetweenSettlementAndMaturity / 360);
case 2: // half-yearly
return ceil($daysBetweenSettlementAndMaturity / 180);
case 4: // quarterly
return ceil($daysBetweenSettlementAndMaturity / 90);
case 6: // bimonthly
return ceil($daysBetweenSettlementAndMaturity / 60);
case 12: // monthly
return ceil($daysBetweenSettlementAndMaturity / 30);
return ceil($daysBetweenSettlementAndMaturity / $daysPerYear * $frequency);
}
return Functions::VALUE();
@@ -740,7 +736,7 @@ class Financial
return Functions::VALUE();
}
if (($settlement > $maturity) ||
if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) {
return Functions::NAN();
@@ -1428,7 +1424,7 @@ class Financial
* @param float $finance_rate The interest rate you pay on the money used in the cash flows
* @param float $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function MIRR($values, $finance_rate, $reinvestment_rate)
{
@@ -1470,7 +1466,7 @@ class Financial
* @param float $effect_rate Effective interest rate
* @param int $npery Number of compounding payments per year
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function NOMINAL($effect_rate = 0, $npery = 0)
{
@@ -1497,7 +1493,7 @@ class Financial
* @param float $fv Future Value
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0)
{
@@ -1565,7 +1561,7 @@ class Financial
* @param float $pv Present Value
* @param float $fv Future Value
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function PDURATION($rate = 0, $pv = 0, $fv = 0)
{
@@ -1594,7 +1590,7 @@ class Financial
* @param float $fv Future Value
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
{
@@ -1629,7 +1625,7 @@ class Financial
* @param float $fv Future Value
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
{
@@ -1713,7 +1709,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0)
{
@@ -1759,7 +1755,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0)
{
@@ -1817,7 +1813,7 @@ class Financial
* @param float $fv Future Value
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0)
{
@@ -1933,7 +1929,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis = 0)
{
@@ -1969,7 +1965,7 @@ class Financial
* @param float $pv Present Value
* @param float $fv Future Value
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function RRI($nper = 0, $pv = 0, $fv = 0)
{
@@ -1996,7 +1992,7 @@ class Financial
* @param mixed $salvage Value at the end of the depreciation
* @param mixed $life Number of periods over which the asset is depreciated
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function SLN($cost, $salvage, $life)
{
@@ -2026,7 +2022,7 @@ class Financial
* @param mixed $life Number of periods over which the asset is depreciated
* @param mixed $period Period
*
* @return float|string
* @return float|string Result, or a string containing an error
*/
public static function SYD($cost, $salvage, $life, $period)
{
@@ -2058,7 +2054,7 @@ class Financial
* The maturity date is the date when the Treasury bill expires.
* @param int $discount The Treasury bill's discount rate
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function TBILLEQ($settlement, $maturity, $discount)
{
@@ -2097,7 +2093,7 @@ class Financial
* The maturity date is the date when the Treasury bill expires.
* @param int $discount The Treasury bill's discount rate
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function TBILLPRICE($settlement, $maturity, $discount)
{
@@ -2152,7 +2148,7 @@ class Financial
* The maturity date is the date when the Treasury bill expires.
* @param int $price The Treasury bill's price per $100 face value
*
* @return float
* @return float|mixed|string
*/
public static function TBILLYIELD($settlement, $maturity, $price)
{
@@ -2187,6 +2183,23 @@ class Financial
return Functions::VALUE();
}
/**
* XIRR.
*
* Returns the internal rate of return for a schedule of cash flows that is not necessarily periodic.
*
* Excel Function:
* =XIRR(values,dates,guess)
*
* @param float[] $values A series of cash flow payments
* The series of values must contain at least one positive value & one negative value
* @param mixed[] $dates A series of payment dates
* The first payment date indicates the beginning of the schedule of payments
* All other dates must be later than this date, but they may occur in any order
* @param float $guess An optional guess at the expected answer
*
* @return float|mixed|string
*/
public static function XIRR($values, $dates, $guess = 0.1)
{
if ((!is_array($values)) && (!is_array($dates))) {
@@ -2199,11 +2212,28 @@ class Financial
return Functions::NAN();
}
$datesCount = count($dates);
for ($i = 0; $i < $datesCount; ++$i) {
$dates[$i] = DateTime::getDateValue($dates[$i]);
if (!is_numeric($dates[$i])) {
return Functions::VALUE();
}
}
if (min($dates) != $dates[0]) {
return Functions::NAN();
}
// create an initial range, with a root somewhere between 0 and guess
$x1 = 0.0;
$x2 = $guess;
$f1 = self::XNPV($x1, $values, $dates);
if (!is_numeric($f1)) {
return $f1;
}
$f2 = self::XNPV($x2, $values, $dates);
if (!is_numeric($f2)) {
return $f2;
}
for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) {
if (($f1 * $f2) < 0.0) {
break;
@@ -2214,7 +2244,7 @@ class Financial
}
}
if (($f1 * $f2) > 0.0) {
return Functions::VALUE();
return Functions::NAN();
}
$f = self::XNPV($x1, $values, $dates);
@@ -2251,15 +2281,15 @@ class Financial
* =XNPV(rate,values,dates)
*
* @param float $rate the discount rate to apply to the cash flows
* @param array of float $values A series of cash flows that corresponds to a schedule of payments in dates.
* @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates.
* The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment.
* If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year.
* The series of values must contain at least one positive value and one negative value.
* @param array of mixed $dates A schedule of payment dates that corresponds to the cash flow payments.
* @param mixed[] $dates A schedule of payment dates that corresponds to the cash flow payments.
* The first payment date indicates the beginning of the schedule of payments.
* All other dates must be later than this date, but they may occur in any order.
*
* @return float
* @return float|mixed|string
*/
public static function XNPV($rate, $values, $dates)
{
@@ -2277,7 +2307,7 @@ class Financial
return Functions::NAN();
}
if ((min($values) > 0) || (max($values) < 0)) {
return Functions::VALUE();
return Functions::NAN();
}
$xnpv = 0.0;
@@ -2309,7 +2339,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis = 0)
{
@@ -2360,7 +2390,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string Result, or a string containing an error
*/
public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis = 0)
{

View File

@@ -17,8 +17,11 @@ class Functions
const COMPATIBILITY_EXCEL = 'Excel';
const COMPATIBILITY_GNUMERIC = 'Gnumeric';
const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
const RETURNDATE_PHP_NUMERIC = 'P';
const RETURNDATE_UNIX_TIMESTAMP = 'P';
const RETURNDATE_PHP_OBJECT = 'O';
const RETURNDATE_PHP_DATETIME_OBJECT = 'O';
const RETURNDATE_EXCEL = 'E';
/**
@@ -101,16 +104,16 @@ class Functions
*
* @param string $returnDateType Return Date Format
* Permitted values are:
* Functions::RETURNDATE_PHP_NUMERIC 'P'
* Functions::RETURNDATE_PHP_OBJECT 'O'
* Functions::RETURNDATE_UNIX_TIMESTAMP 'P'
* Functions::RETURNDATE_PHP_DATETIME_OBJECT 'O'
* Functions::RETURNDATE_EXCEL 'E'
*
* @return bool Success or failure
*/
public static function setReturnDateType($returnDateType)
{
if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
if (($returnDateType == self::RETURNDATE_UNIX_TIMESTAMP) ||
($returnDateType == self::RETURNDATE_PHP_DATETIME_OBJECT) ||
($returnDateType == self::RETURNDATE_EXCEL)
) {
self::$returnDateType = $returnDateType;
@@ -128,8 +131,8 @@ class Functions
*
* @return string Return Date Format
* Possible Return values are:
* Functions::RETURNDATE_PHP_NUMERIC 'P'
* Functions::RETURNDATE_PHP_OBJECT 'O'
* Functions::RETURNDATE_UNIX_TIMESTAMP 'P'
* Functions::RETURNDATE_PHP_DATETIME_OBJECT 'O'
* Functions::RETURNDATE_EXCEL 'E'
*/
public static function getReturnDateType()
@@ -267,25 +270,29 @@ class Functions
public static function ifCondition($condition)
{
$condition = self::flattenSingleValue($condition);
if (!isset($condition[0]) && !is_numeric($condition)) {
if ($condition === '') {
$condition = '=""';
}
if (!in_array($condition[0], ['>', '<', '='])) {
if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='])) {
if (!is_numeric($condition)) {
$condition = Calculation::wrapResult(strtoupper($condition));
}
return '=' . $condition;
return str_replace('""""', '""', '=' . $condition);
}
preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches);
list(, $operator, $operand) = $matches;
[, $operator, $operand] = $matches;
if (!is_numeric($operand)) {
if (is_numeric(trim($operand, '"'))) {
$operand = trim($operand, '"');
} elseif (!is_numeric($operand)) {
$operand = str_replace('"', '""', $operand);
$operand = Calculation::wrapResult(strtoupper($operand));
}
return $operator . $operand;
return str_replace('""""', '""', $operator . $operand);
}
/**
@@ -639,7 +646,7 @@ class Functions
public static function flattenSingleValue($value = '')
{
while (is_array($value)) {
$value = array_pop($value);
$value = array_shift($value);
}
return $value;

View File

@@ -266,6 +266,10 @@ class Logical
*/
public static function statementIf($condition = true, $returnIfTrue = 0, $returnIfFalse = false)
{
if (Functions::isError($condition)) {
return $condition;
}
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
$returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
$returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
@@ -347,4 +351,25 @@ class Logical
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
}
/**
* IFNA.
*
* Excel Function:
* =IFNA(testValue,napart)
*
* @category Logical Functions
*
* @param mixed $testValue Value to check, is also the value returned when not an NA
* @param mixed $napart Value to return when testValue is an NA condition
*
* @return mixed The value of errorpart or testValue determined by error condition
*/
public static function IFNA($testValue = '', $napart = '')
{
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
$napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart);
return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
}
}

View File

@@ -98,9 +98,9 @@ class LookupRef
return (int) Coordinate::columnIndexFromString($columnKey);
}
} else {
list($sheet, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
[$sheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
if (strpos($cellAddress, ':') !== false) {
list($startAddress, $endAddress) = explode(':', $cellAddress);
[$startAddress, $endAddress] = explode(':', $cellAddress);
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
$endAddress = preg_replace('/[^a-z]/i', '', $endAddress);
$returnValue = [];
@@ -138,7 +138,7 @@ class LookupRef
reset($cellAddress);
$isMatrix = (is_numeric(key($cellAddress)));
list($columns, $rows) = Calculation::getMatrixDimensions($cellAddress);
[$columns, $rows] = Calculation::getMatrixDimensions($cellAddress);
if ($isMatrix) {
return $rows;
@@ -175,9 +175,9 @@ class LookupRef
}
}
} else {
list($sheet, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
[$sheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
if (strpos($cellAddress, ':') !== false) {
list($startAddress, $endAddress) = explode(':', $cellAddress);
[$startAddress, $endAddress] = explode(':', $cellAddress);
$startAddress = preg_replace('/\D/', '', $startAddress);
$endAddress = preg_replace('/\D/', '', $endAddress);
$returnValue = [];
@@ -187,7 +187,7 @@ class LookupRef
return $returnValue;
}
list($cellAddress) = explode(':', $cellAddress);
[$cellAddress] = explode(':', $cellAddress);
return (int) preg_replace('/\D/', '', $cellAddress);
}
@@ -215,7 +215,7 @@ class LookupRef
reset($cellAddress);
$isMatrix = (is_numeric(key($cellAddress)));
list($columns, $rows) = Calculation::getMatrixDimensions($cellAddress);
[$columns, $rows] = Calculation::getMatrixDimensions($cellAddress);
if ($isMatrix) {
return $columns;
@@ -285,7 +285,7 @@ class LookupRef
$cellAddress1 = $cellAddress;
$cellAddress2 = null;
if (strpos($cellAddress, ':') !== false) {
list($cellAddress1, $cellAddress2) = explode(':', $cellAddress);
[$cellAddress1, $cellAddress2] = explode(':', $cellAddress);
}
if ((!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress1, $matches)) ||
@@ -295,7 +295,7 @@ class LookupRef
}
if (strpos($cellAddress, '!') !== false) {
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
$sheetName = trim($sheetName, "'");
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
} else {
@@ -306,7 +306,7 @@ class LookupRef
}
if (strpos($cellAddress, '!') !== false) {
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
$sheetName = trim($sheetName, "'");
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
} else {
@@ -359,16 +359,16 @@ class LookupRef
$sheetName = null;
if (strpos($cellAddress, '!')) {
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
$sheetName = trim($sheetName, "'");
}
if (strpos($cellAddress, ':')) {
list($startCell, $endCell) = explode(':', $cellAddress);
[$startCell, $endCell] = explode(':', $cellAddress);
} else {
$startCell = $endCell = $cellAddress;
}
list($startCellColumn, $startCellRow) = Coordinate::coordinateFromString($startCell);
list($endCellColumn, $endCellRow) = Coordinate::coordinateFromString($endCell);
[$startCellColumn, $startCellRow] = Coordinate::coordinateFromString($startCell);
[$endCellColumn, $endCellRow] = Coordinate::coordinateFromString($endCell);
$startCellRow += $rows;
$startCellColumn = Coordinate::columnIndexFromString($startCellColumn) - 1;
@@ -464,9 +464,10 @@ class LookupRef
*
* @param mixed $lookupValue The value that you want to match in lookup_array
* @param mixed $lookupArray The range of cells being searched
* @param mixed $matchType The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered.
* @param mixed $matchType The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below.
* If match_type is 1 or -1, the list has to be ordered.
*
* @return int The relative position of the found item
* @return int|string The relative position of the found item
*/
public static function MATCH($lookupValue, $lookupArray, $matchType = 1)
{
@@ -474,9 +475,10 @@ class LookupRef
$lookupValue = Functions::flattenSingleValue($lookupValue);
$matchType = ($matchType === null) ? 1 : (int) Functions::flattenSingleValue($matchType);
$initialLookupValue = $lookupValue;
// MATCH is not case sensitive
$lookupValue = StringHelper::strToLower($lookupValue);
// MATCH is not case sensitive, so we convert lookup value to be lower cased in case it's string type.
if (is_string($lookupValue)) {
$lookupValue = StringHelper::strToLower($lookupValue);
}
// Lookup_value type has to be number, text, or logical values
if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) {
@@ -522,16 +524,54 @@ class LookupRef
// find the match
// **
if ($matchType == 0 || $matchType == 1) {
if ($matchType === 0 || $matchType === 1) {
foreach ($lookupArray as $i => $lookupArrayValue) {
$onlyNumeric = is_numeric($lookupArrayValue) && is_numeric($lookupValue);
$onlyNumericExactMatch = $onlyNumeric && $lookupArrayValue == $lookupValue;
$nonOnlyNumericExactMatch = !$onlyNumeric && $lookupArrayValue === $lookupValue;
$exactMatch = $onlyNumericExactMatch || $nonOnlyNumericExactMatch;
if (($matchType == 0) && $exactMatch) {
// exact match
return $i + 1;
} elseif (($matchType == 1) && ($lookupArrayValue <= $lookupValue)) {
$typeMatch = gettype($lookupValue) === gettype($lookupArrayValue);
$exactTypeMatch = $typeMatch && $lookupArrayValue === $lookupValue;
$nonOnlyNumericExactMatch = !$typeMatch && $lookupArrayValue === $lookupValue;
$exactMatch = $exactTypeMatch || $nonOnlyNumericExactMatch;
if ($matchType === 0) {
if ($typeMatch && is_string($lookupValue) && (bool) preg_match('/([\?\*])/', $lookupValue)) {
$splitString = $lookupValue;
$chars = array_map(function ($i) use ($splitString) {
return mb_substr($splitString, $i, 1);
}, range(0, mb_strlen($splitString) - 1));
$length = count($chars);
$pattern = '/^';
for ($j = 0; $j < $length; ++$j) {
if ($chars[$j] === '~') {
if (isset($chars[$j + 1])) {
if ($chars[$j + 1] === '*') {
$pattern .= preg_quote($chars[$j + 1], '/');
++$j;
} elseif ($chars[$j + 1] === '?') {
$pattern .= preg_quote($chars[$j + 1], '/');
++$j;
}
} else {
$pattern .= preg_quote($chars[$j], '/');
}
} elseif ($chars[$j] === '*') {
$pattern .= '.*';
} elseif ($chars[$j] === '?') {
$pattern .= '.{1}';
} else {
$pattern .= preg_quote($chars[$j], '/');
}
}
$pattern .= '$/';
if ((bool) preg_match($pattern, $lookupArrayValue)) {
// exact match
return $i + 1;
}
} elseif ($exactMatch) {
// exact match
return $i + 1;
}
} elseif (($matchType === 1) && $typeMatch && ($lookupArrayValue <= $lookupValue)) {
$i = array_search($i, $keySet);
// The current value is the (first) match
@@ -539,26 +579,26 @@ class LookupRef
}
}
} else {
// matchType = -1
// "Special" case: since the array it's supposed to be ordered in descending order, the
// Excel algorithm gives up immediately if the first element is smaller than the searched value
if ($lookupArray[0] < $lookupValue) {
return Functions::NA();
}
$maxValueKey = null;
// The basic algorithm is:
// Iterate and keep the highest match until the next element is smaller than the searched value.
// Return immediately if perfect match is found
foreach ($lookupArray as $i => $lookupArrayValue) {
if ($lookupArrayValue == $lookupValue) {
$typeMatch = gettype($lookupValue) === gettype($lookupArrayValue);
$exactTypeMatch = $typeMatch && $lookupArrayValue === $lookupValue;
$nonOnlyNumericExactMatch = !$typeMatch && $lookupArrayValue === $lookupValue;
$exactMatch = $exactTypeMatch || $nonOnlyNumericExactMatch;
if ($exactMatch) {
// Another "special" case. If a perfect match is found,
// the algorithm gives up immediately
return $i + 1;
} elseif ($lookupArrayValue >= $lookupValue) {
} elseif ($typeMatch & $lookupArrayValue >= $lookupValue) {
$maxValueKey = $i + 1;
} elseif ($typeMatch & $lookupArrayValue < $lookupValue) {
//Excel algorithm gives up immediately if the first element is smaller than the searched value
break;
}
}
@@ -794,8 +834,10 @@ class LookupRef
$lookupLower = StringHelper::strToLower($lookup_value);
$rowDataLower = StringHelper::strToLower($rowData);
if (($bothNumeric && $rowData > $lookup_value) ||
($bothNotNumeric && $rowDataLower > $lookupLower)) {
if ($not_exact_match && (
($bothNumeric && $rowData > $lookup_value) ||
($bothNotNumeric && $rowDataLower > $lookupLower)
)) {
break;
}

View File

@@ -38,6 +38,88 @@ class MathTrig
return ($num - ($num % $n)) / $n;
}
/**
* ARABIC.
*
* Converts a Roman numeral to an Arabic numeral.
*
* Excel Function:
* ARABIC(text)
*
* @category Mathematical and Trigonometric Functions
*
* @param string $roman
*
* @return int|string the arabic numberal contrived from the roman numeral
*/
public static function ARABIC($roman)
{
// An empty string should return 0
$roman = substr(trim(strtoupper((string) Functions::flattenSingleValue($roman))), 0, 255);
if ($roman === '') {
return 0;
}
// Convert the roman numeral to an arabic number
$negativeNumber = $roman[0] === '-';
if ($negativeNumber) {
$roman = substr($roman, 1);
}
try {
$arabic = self::calculateArabic(str_split($roman));
} catch (\Exception $e) {
return Functions::VALUE(); // Invalid character detected
}
if ($negativeNumber) {
$arabic *= -1; // The number should be negative
}
return $arabic;
}
/**
* Recursively calculate the arabic value of a roman numeral.
*
* @param array $roman
* @param int $sum
* @param int $subtract
*
* @return int
*/
protected static function calculateArabic(array $roman, &$sum = 0, $subtract = 0)
{
$lookup = [
'M' => 1000,
'D' => 500,
'C' => 100,
'L' => 50,
'X' => 10,
'V' => 5,
'I' => 1,
];
$numeral = array_shift($roman);
if (!isset($lookup[$numeral])) {
throw new \Exception('Invalid character detected');
}
$arabic = $lookup[$numeral];
if (count($roman) > 0 && isset($lookup[$roman[0]]) && $arabic < $lookup[$roman[0]]) {
$subtract += $arabic;
} else {
$sum += ($arabic - $subtract);
$subtract = 0;
}
if (count($roman) > 0) {
self::calculateArabic($roman, $sum, $subtract);
}
return $sum;
}
/**
* ATAN2.
*
@@ -59,7 +141,7 @@ class MathTrig
* @param float $xCoordinate the x-coordinate of the point
* @param float $yCoordinate the y-coordinate of the point
*
* @return float the inverse tangent of the specified x- and y-coordinates
* @return float|string the inverse tangent of the specified x- and y-coordinates, or a string containing an error
*/
public static function ATAN2($xCoordinate = null, $yCoordinate = null)
{
@@ -84,6 +166,49 @@ class MathTrig
return Functions::VALUE();
}
/**
* BASE.
*
* Converts a number into a text representation with the given radix (base).
*
* Excel Function:
* BASE(Number, Radix [Min_length])
*
* @category Mathematical and Trigonometric Functions
*
* @param float $number
* @param float $radix
* @param int $minLength
*
* @return string the text representation with the given radix (base)
*/
public static function BASE($number, $radix, $minLength = null)
{
$number = Functions::flattenSingleValue($number);
$radix = Functions::flattenSingleValue($radix);
$minLength = Functions::flattenSingleValue($minLength);
if (is_numeric($number) && is_numeric($radix) && ($minLength === null || is_numeric($minLength))) {
// Truncate to an integer
$number = (int) $number;
$radix = (int) $radix;
$minLength = (int) $minLength;
if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) {
return Functions::NAN(); // Numeric range constraints
}
$outcome = strtoupper((string) base_convert($number, 10, $radix));
if ($minLength !== null) {
$outcome = str_pad($outcome, $minLength, '0', STR_PAD_LEFT); // String padding
}
return $outcome;
}
return Functions::VALUE();
}
/**
* CEILING.
*
@@ -100,7 +225,7 @@ class MathTrig
* @param float $number the number you want to round
* @param float $significance the multiple to which you want to round
*
* @return float Rounded Number
* @return float|string Rounded Number, or a string containing an error
*/
public static function CEILING($number, $significance = null)
{
@@ -139,7 +264,7 @@ class MathTrig
* @param int $numObjs Number of different objects
* @param int $numInSet Number of objects in each combination
*
* @return int Number of combinations
* @return int|string Number of combinations, or a string containing an error
*/
public static function COMBIN($numObjs, $numInSet)
{
@@ -175,7 +300,7 @@ class MathTrig
*
* @param float $number Number to round
*
* @return int Rounded Number
* @return int|string Rounded Number, or a string containing an error
*/
public static function EVEN($number)
{
@@ -209,7 +334,7 @@ class MathTrig
*
* @param float $factVal Factorial Value
*
* @return int Factorial
* @return int|string Factorial, or a string containing an error
*/
public static function FACT($factVal)
{
@@ -220,10 +345,9 @@ class MathTrig
return Functions::NAN();
}
$factLoop = floor($factVal);
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
if ($factVal > $factLoop) {
return Functions::NAN();
}
if ((Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) &&
($factVal > $factLoop)) {
return Functions::NAN();
}
$factorial = 1;
@@ -249,7 +373,7 @@ class MathTrig
*
* @param float $factVal Factorial Value
*
* @return int Double Factorial
* @return int|string Double Factorial, or a string containing an error
*/
public static function FACTDOUBLE($factVal)
{
@@ -285,7 +409,7 @@ class MathTrig
* @param float $number Number to round
* @param float $significance Significance
*
* @return float Rounded Number
* @return float|string Rounded Number, or a string containing an error
*/
public static function FLOOR($number, $significance = null)
{
@@ -302,7 +426,9 @@ class MathTrig
return Functions::DIV0();
} elseif ($number == 0.0) {
return 0.0;
} elseif (self::SIGN($number) == self::SIGN($significance)) {
} elseif (self::SIGN($significance) == 1) {
return floor($number / $significance) * $significance;
} elseif (self::SIGN($number) == -1 && self::SIGN($significance) == -1) {
return floor($number / $significance) * $significance;
}
@@ -312,6 +438,80 @@ class MathTrig
return Functions::VALUE();
}
/**
* FLOOR.MATH.
*
* Round a number down to the nearest integer or to the nearest multiple of significance.
*
* Excel Function:
* FLOOR.MATH(number[,significance[,mode]])
*
* @category Mathematical and Trigonometric Functions
*
* @param float $number Number to round
* @param float $significance Significance
* @param int $mode direction to round negative numbers
*
* @return float|string Rounded Number, or a string containing an error
*/
public static function FLOORMATH($number, $significance = null, $mode = 0)
{
$number = Functions::flattenSingleValue($number);
$significance = Functions::flattenSingleValue($significance);
$mode = Functions::flattenSingleValue($mode);
if (is_numeric($number) && $significance === null) {
$significance = $number / abs($number);
}
if (is_numeric($number) && is_numeric($significance) && is_numeric($mode)) {
if ($significance == 0.0) {
return Functions::DIV0();
} elseif ($number == 0.0) {
return 0.0;
} elseif (self::SIGN($significance) == -1 || (self::SIGN($number) == -1 && !empty($mode))) {
return ceil($number / $significance) * $significance;
}
return floor($number / $significance) * $significance;
}
return Functions::VALUE();
}
/**
* FLOOR.PRECISE.
*
* Rounds number down, toward zero, to the nearest multiple of significance.
*
* Excel Function:
* FLOOR.PRECISE(number[,significance])
*
* @category Mathematical and Trigonometric Functions
*
* @param float $number Number to round
* @param float $significance Significance
*
* @return float|string Rounded Number, or a string containing an error
*/
public static function FLOORPRECISE($number, $significance = 1)
{
$number = Functions::flattenSingleValue($number);
$significance = Functions::flattenSingleValue($significance);
if ((is_numeric($number)) && (is_numeric($significance))) {
if ($significance == 0.0) {
return Functions::DIV0();
} elseif ($number == 0.0) {
return 0.0;
}
return floor($number / abs($significance)) * abs($significance);
}
return Functions::VALUE();
}
private static function evaluateGCD($a, $b)
{
return $b ? self::evaluateGCD($b, $a % $b) : $a;
@@ -331,7 +531,7 @@ class MathTrig
*
* @param mixed ...$args Data values
*
* @return int Greatest Common Divisor
* @return int|mixed|string Greatest Common Divisor, or a string containing an error
*/
public static function GCD(...$args)
{
@@ -365,7 +565,7 @@ class MathTrig
*
* @param float $number Number to cast to an integer
*
* @return int Integer value
* @return int|string Integer value, or a string containing an error
*/
public static function INT($number)
{
@@ -398,7 +598,7 @@ class MathTrig
*
* @param mixed ...$args Data values
*
* @return int Lowest Common Multiplier
* @return int|string Lowest Common Multiplier, or a string containing an error
*/
public static function LCM(...$args)
{
@@ -450,7 +650,7 @@ class MathTrig
* @param float $number The positive real number for which you want the logarithm
* @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10.
*
* @return float
* @return float|string The result, or a string containing an error
*/
public static function logBase($number = null, $base = 10)
{
@@ -479,7 +679,7 @@ class MathTrig
*
* @param array $matrixValues A matrix of values
*
* @return float
* @return float|string The result, or a string containing an error
*/
public static function MDETERM($matrixValues)
{
@@ -531,7 +731,7 @@ class MathTrig
*
* @param array $matrixValues A matrix of values
*
* @return array
* @return array|string The result, or a string containing an error
*/
public static function MINVERSE($matrixValues)
{
@@ -581,7 +781,7 @@ class MathTrig
* @param array $matrixData1 A matrix of values
* @param array $matrixData2 A matrix of values
*
* @return array
* @return array|string The result, or a string containing an error
*/
public static function MMULT($matrixData1, $matrixData2)
{
@@ -643,7 +843,7 @@ class MathTrig
* @param int $a Dividend
* @param int $b Divisor
*
* @return int Remainder
* @return int|string Remainder, or a string containing an error
*/
public static function MOD($a = 1, $b = 1)
{
@@ -669,7 +869,7 @@ class MathTrig
* @param float $number Number to round
* @param int $multiple Multiple to which you want to round $number
*
* @return float Rounded Number
* @return float|string Rounded Number, or a string containing an error
*/
public static function MROUND($number, $multiple)
{
@@ -699,7 +899,7 @@ class MathTrig
*
* @param array of mixed Data Series
*
* @return float
* @return float|string The result, or a string containing an error
*/
public static function MULTINOMIAL(...$args)
{
@@ -736,7 +936,7 @@ class MathTrig
*
* @param float $number Number to round
*
* @return int Rounded Number
* @return int|string Rounded Number, or a string containing an error
*/
public static function ODD($number)
{
@@ -771,7 +971,7 @@ class MathTrig
* @param float $x
* @param float $y
*
* @return float
* @return float|string The result, or a string containing an error
*/
public static function POWER($x = 0, $y = 2)
{
@@ -930,7 +1130,7 @@ class MathTrig
* @param float $number Number to round
* @param int $digits Number of digits to which you want to round $number
*
* @return float Rounded Number
* @return float|string Rounded Number, or a string containing an error
*/
public static function ROUNDUP($number, $digits)
{
@@ -938,12 +1138,11 @@ class MathTrig
$digits = Functions::flattenSingleValue($digits);
if ((is_numeric($number)) && (is_numeric($digits))) {
$significance = pow(10, (int) $digits);
if ($number < 0.0) {
return floor($number * $significance) / $significance;
return round($number - 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_DOWN);
}
return ceil($number * $significance) / $significance;
return round($number + 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_DOWN);
}
return Functions::VALUE();
@@ -957,7 +1156,7 @@ class MathTrig
* @param float $number Number to round
* @param int $digits Number of digits to which you want to round $number
*
* @return float Rounded Number
* @return float|string Rounded Number, or a string containing an error
*/
public static function ROUNDDOWN($number, $digits)
{
@@ -965,12 +1164,11 @@ class MathTrig
$digits = Functions::flattenSingleValue($digits);
if ((is_numeric($number)) && (is_numeric($digits))) {
$significance = pow(10, (int) $digits);
if ($number < 0.0) {
return ceil($number * $significance) / $significance;
return round($number + 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_UP);
}
return floor($number * $significance) / $significance;
return round($number - 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_UP);
}
return Functions::VALUE();
@@ -986,7 +1184,7 @@ class MathTrig
* @param float $m Step by which to increase $n for each term in the series
* @param array of mixed Data Series
*
* @return float
* @return float|string The result, or a string containing an error
*/
public static function SERIESSUM(...$args)
{
@@ -1025,7 +1223,7 @@ class MathTrig
*
* @param float $number Number to round
*
* @return int sign value
* @return int|string sign value, or a string containing an error
*/
public static function SIGN($number)
{
@@ -1052,7 +1250,7 @@ class MathTrig
*
* @param float $number Number
*
* @return float Square Root of Number * Pi
* @return float|string Square Root of Number * Pi, or a string containing an error
*/
public static function SQRTPI($number)
{
@@ -1074,7 +1272,7 @@ class MathTrig
return array_filter(
$args,
function ($index) use ($cellReference) {
list(, $row, $column) = explode('.', $index);
[, $row, $column] = explode('.', $index);
return $cellReference->getWorksheet()->getRowDimension($row)->getVisible() &&
$cellReference->getWorksheet()->getColumnDimension($column)->getVisible();
@@ -1088,7 +1286,7 @@ class MathTrig
return array_filter(
$args,
function ($index) use ($cellReference) {
list(, $row, $column) = explode('.', $index);
[, $row, $column] = explode('.', $index);
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
@@ -1116,7 +1314,7 @@ class MathTrig
* in hidden rows or columns
* @param array of mixed Data Series
*
* @return float
* @return float|string
*/
public static function SUBTOTAL(...$args)
{
@@ -1306,7 +1504,7 @@ class MathTrig
*
* @param mixed ...$args Data values
*
* @return float
* @return float|string The result, or a string containing an error
*/
public static function SUMPRODUCT(...$args)
{
@@ -1451,7 +1649,7 @@ class MathTrig
* @param float $value
* @param int $digits
*
* @return float Truncated value
* @return float|string Truncated value, or a string containing an error
*/
public static function TRUNC($value = 0, $digits = 0)
{

View File

@@ -52,7 +52,7 @@ class TextData
return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
}
if (self::$invalidChars == null) {
if (self::$invalidChars === null) {
self::$invalidChars = range(chr(0), chr(31));
}
@@ -84,6 +84,15 @@ class TextData
return null;
}
private static function convertBooleanValue($value)
{
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
return (int) $value;
}
return ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
}
/**
* ASCIICODE.
*
@@ -98,11 +107,7 @@ class TextData
}
$characters = Functions::flattenSingleValue($characters);
if (is_bool($characters)) {
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
$characters = (int) $characters;
} else {
$characters = ($characters) ? Calculation::getTRUE() : Calculation::getFALSE();
}
$characters = self::convertBooleanValue($characters);
}
$character = $characters;
@@ -126,11 +131,7 @@ class TextData
$aArgs = Functions::flattenArray($args);
foreach ($aArgs as $arg) {
if (is_bool($arg)) {
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
$arg = (int) $arg;
} else {
$arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
}
$arg = self::convertBooleanValue($arg);
}
$returnValue .= $arg;
}
@@ -197,7 +198,7 @@ class TextData
}
if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
if (StringHelper::countCharacters($needle) == 0) {
if (StringHelper::countCharacters($needle) === 0) {
return $offset;
}
@@ -232,7 +233,7 @@ class TextData
}
if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
if (StringHelper::countCharacters($needle) == 0) {
if (StringHelper::countCharacters($needle) === 0) {
return $offset;
}
@@ -265,14 +266,19 @@ class TextData
if (!is_numeric($value) || !is_numeric($decimals)) {
return Functions::NAN();
}
$decimals = floor($decimals);
$decimals = (int) floor($decimals);
$valueResult = round($value, $decimals);
if ($decimals < 0) {
$decimals = 0;
}
if (!$no_commas) {
$valueResult = number_format($valueResult, $decimals);
$valueResult = number_format(
$valueResult,
$decimals,
StringHelper::getDecimalSeparator(),
StringHelper::getThousandsSeparator()
);
}
return (string) $valueResult;
@@ -659,11 +665,7 @@ class TextData
if ($ignoreEmpty && trim($arg) == '') {
unset($aArgs[$key]);
} elseif (is_bool($arg)) {
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
$arg = (int) $arg;
} else {
$arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
}
$arg = self::convertBooleanValue($arg);
}
}

View File

@@ -36,14 +36,24 @@ class Stack
* @param mixed $type
* @param mixed $value
* @param mixed $reference
* @param null|string $storeKey will store the result under this alias
* @param null|string $onlyIf will only run computation if the matching
* store key is true
* @param null|string $onlyIfNot will only run computation if the matching
* store key is false
*/
public function push($type, $value, $reference = null)
{
$this->stack[$this->count++] = [
'type' => $type,
'value' => $value,
'reference' => $reference,
];
public function push(
$type,
$value,
$reference = null,
$storeKey = null,
$onlyIf = null,
$onlyIfNot = null
) {
$stackItem = $this->getStackItem($type, $value, $reference, $storeKey, $onlyIf, $onlyIfNot);
$this->stack[$this->count++] = $stackItem;
if ($type == 'Function') {
$localeFunction = Calculation::localeFunc($value);
if ($localeFunction != $value) {
@@ -52,6 +62,35 @@ class Stack
}
}
public function getStackItem(
$type,
$value,
$reference = null,
$storeKey = null,
$onlyIf = null,
$onlyIfNot = null
) {
$stackItem = [
'type' => $type,
'value' => $value,
'reference' => $reference,
];
if (isset($storeKey)) {
$stackItem['storeKey'] = $storeKey;
}
if (isset($onlyIf)) {
$stackItem['onlyIf'] = $onlyIf;
}
if (isset($onlyIfNot)) {
$stackItem['onlyIfNot'] = $onlyIfNot;
}
return $stackItem;
}
/**
* Pop the last entry from the stack.
*
@@ -90,4 +129,21 @@ class Stack
$this->stack = [];
$this->count = 0;
}
public function __toString()
{
$str = 'Stack: ';
foreach ($this->stack as $index => $item) {
if ($index > $this->count - 1) {
break;
}
$value = $item['value'] ?? 'no value';
while (is_array($value)) {
$value = array_pop($value);
}
$str .= $value . ' |> ';
}
return $str;
}
}

View File

@@ -9,6 +9,7 @@ ADDRESS
AMORDEGRC
AMORLINC
AND
ARABIC
AREAS
ASC
ASIN
@@ -22,6 +23,7 @@ AVERAGEA
AVERAGEIF
AVERAGEIFS
BAHTTEXT
BASE
BESSELI
BESSELJ
BESSELK
@@ -137,6 +139,8 @@ FISHER
FISHERINV
FIXED
FLOOR
FLOOR.MATH
FLOOR.PRECISE
FORECAST
FREQUENCY
FTEST
@@ -224,6 +228,7 @@ LOWER
MATCH
MAX
MAXA
MAXIFS
MDETERM
MDURATION
MEDIAN
@@ -231,6 +236,7 @@ MID
MIDB
MIN
MINA
MINIFS
MINUTE
MINVERSE
MIRR

View File

@@ -118,7 +118,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
// Check for time without seconds e.g. '9:45', '09:45'
if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
// Convert value to number
list($h, $m) = explode(':', $value);
[$h, $m] = explode(':', $value);
$days = $h / 24 + $m / 1440;
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC);
// Set style
@@ -131,7 +131,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
// Check for time with seconds '9:45:59', '09:45:59'
if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
// Convert value to number
list($h, $m, $s) = explode(':', $value);
[$h, $m, $s] = explode(':', $value);
$days = $h / 24 + $m / 1440 + $s / 86400;
// Convert value to number
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC);

View File

@@ -67,7 +67,7 @@ class Cell
/**
* Update the cell into the cell collection.
*
* @return self
* @return $this
*/
public function updateInCollection()
{
@@ -177,7 +177,7 @@ class Cell
*
* @throws Exception
*
* @return Cell
* @return $this
*/
public function setValue($pValue)
{
@@ -217,7 +217,10 @@ class Cell
break;
case DataType::TYPE_NUMERIC:
$this->value = (float) $pValue;
if (is_string($pValue) && !is_numeric($pValue)) {
throw new Exception('Invalid numeric value for datatype Numeric');
}
$this->value = 0 + $pValue;
break;
case DataType::TYPE_FORMULA:
@@ -263,7 +266,7 @@ class Cell
// We don't yet handle array returns
if (is_array($result)) {
while (is_array($result)) {
$result = array_pop($result);
$result = array_shift($result);
}
}
} catch (Exception $ex) {
@@ -511,7 +514,7 @@ class Cell
{
if ($mergeRange = $this->getMergeRange()) {
$mergeRange = Coordinate::splitRange($mergeRange);
list($startCell) = $mergeRange[0];
[$startCell] = $mergeRange[0];
if ($this->getCoordinate() === $startCell) {
return true;
}
@@ -569,7 +572,7 @@ class Cell
*/
public function isInRange($pRange)
{
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($pRange);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($pRange);
// Translate properties
$myColumn = Coordinate::columnIndexFromString($this->getColumn());
@@ -669,7 +672,7 @@ class Cell
*
* @param mixed $pAttributes
*
* @return Cell
* @return $this
*/
public function setFormulaAttributes($pAttributes)
{

View File

@@ -71,7 +71,7 @@ abstract class Coordinate
}
// Split out any worksheet name from the reference
list($worksheet, $pCoordinateString) = Worksheet::extractSheetTitle($pCoordinateString, true);
[$worksheet, $pCoordinateString] = Worksheet::extractSheetTitle($pCoordinateString, true);
if ($worksheet > '') {
$worksheet .= '!';
}
@@ -102,13 +102,13 @@ abstract class Coordinate
}
// Split out any worksheet name from the coordinate
list($worksheet, $pCoordinateString) = Worksheet::extractSheetTitle($pCoordinateString, true);
[$worksheet, $pCoordinateString] = Worksheet::extractSheetTitle($pCoordinateString, true);
if ($worksheet > '') {
$worksheet .= '!';
}
// Create absolute coordinate
list($column, $row) = self::coordinateFromString($pCoordinateString);
[$column, $row] = self::coordinateFromString($pCoordinateString);
$column = ltrim($column, '$');
$row = ltrim($row, '$');
@@ -187,7 +187,7 @@ abstract class Coordinate
if (strpos($pRange, ':') === false) {
$rangeA = $rangeB = $pRange;
} else {
list($rangeA, $rangeB) = explode(':', $pRange);
[$rangeA, $rangeB] = explode(':', $pRange);
}
// Calculate range outer borders
@@ -211,7 +211,7 @@ abstract class Coordinate
public static function rangeDimension($pRange)
{
// Calculate range outer borders
list($rangeStart, $rangeEnd) = self::rangeBoundaries($pRange);
[$rangeStart, $rangeEnd] = self::rangeBoundaries($pRange);
return [($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1)];
}
@@ -238,7 +238,7 @@ abstract class Coordinate
if (strpos($pRange, ':') === false) {
$rangeA = $rangeB = $pRange;
} else {
list($rangeA, $rangeB) = explode(':', $pRange);
[$rangeA, $rangeB] = explode(':', $pRange);
}
return [self::coordinateFromString($rangeA), self::coordinateFromString($rangeB)];
@@ -376,9 +376,9 @@ abstract class Coordinate
}
// Range...
list($rangeStart, $rangeEnd) = $range;
list($startColumn, $startRow) = self::coordinateFromString($rangeStart);
list($endColumn, $endRow) = self::coordinateFromString($rangeEnd);
[$rangeStart, $rangeEnd] = $range;
[$startColumn, $startRow] = self::coordinateFromString($rangeStart);
[$endColumn, $endRow] = self::coordinateFromString($rangeEnd);
$startColumnIndex = self::columnIndexFromString($startColumn);
$endColumnIndex = self::columnIndexFromString($endColumn);
++$endColumnIndex;
@@ -432,7 +432,7 @@ abstract class Coordinate
continue;
}
list($column, $row) = self::coordinateFromString($coord);
[$column, $row] = self::coordinateFromString($coord);
$row = (int) (ltrim($row, '$'));
$hashCode = $column . '-' . (is_object($value) ? $value->getHashCode() : $value);

View File

@@ -142,7 +142,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setFormula1($value)
{
@@ -166,7 +166,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setFormula2($value)
{
@@ -190,7 +190,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setType($value)
{
@@ -214,7 +214,7 @@ class DataValidation
*
* @param string $value see self::STYLE_*
*
* @return DataValidation
* @return $this
*/
public function setErrorStyle($value)
{
@@ -238,7 +238,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setOperator($value)
{
@@ -262,7 +262,7 @@ class DataValidation
*
* @param bool $value
*
* @return DataValidation
* @return $this
*/
public function setAllowBlank($value)
{
@@ -286,7 +286,7 @@ class DataValidation
*
* @param bool $value
*
* @return DataValidation
* @return $this
*/
public function setShowDropDown($value)
{
@@ -310,7 +310,7 @@ class DataValidation
*
* @param bool $value
*
* @return DataValidation
* @return $this
*/
public function setShowInputMessage($value)
{
@@ -334,7 +334,7 @@ class DataValidation
*
* @param bool $value
*
* @return DataValidation
* @return $this
*/
public function setShowErrorMessage($value)
{
@@ -358,7 +358,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setErrorTitle($value)
{
@@ -382,7 +382,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setError($value)
{
@@ -406,7 +406,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setPromptTitle($value)
{
@@ -430,7 +430,7 @@ class DataValidation
*
* @param string $value
*
* @return DataValidation
* @return $this
*/
public function setPrompt($value)
{

View File

@@ -51,16 +51,16 @@ class DefaultValueBinder implements IValueBinder
// Match the value against a few data types
if ($pValue === null) {
return DataType::TYPE_NULL;
} elseif (is_float($pValue) || is_int($pValue)) {
return DataType::TYPE_NUMERIC;
} elseif (is_bool($pValue)) {
return DataType::TYPE_BOOL;
} elseif ($pValue === '') {
return DataType::TYPE_STRING;
} elseif ($pValue instanceof RichText) {
return DataType::TYPE_INLINE;
} elseif ($pValue[0] === '=' && strlen($pValue) > 1) {
} elseif (is_string($pValue) && $pValue[0] === '=' && strlen($pValue) > 1) {
return DataType::TYPE_FORMULA;
} elseif (is_bool($pValue)) {
return DataType::TYPE_BOOL;
} elseif (is_float($pValue) || is_int($pValue)) {
return DataType::TYPE_NUMERIC;
} elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) {
$tValue = ltrim($pValue, '+-');
if (is_string($pValue) && $tValue[0] === '0' && strlen($tValue) > 1 && $tValue[1] !== '.') {

View File

@@ -46,7 +46,7 @@ class Hyperlink
*
* @param string $value
*
* @return Hyperlink
* @return $this
*/
public function setUrl($value)
{
@@ -70,7 +70,7 @@ class Hyperlink
*
* @param string $value
*
* @return Hyperlink
* @return $this
*/
public function setTooltip($value)
{

View File

@@ -354,7 +354,7 @@ class Axis extends Properties
*
* @param int $shadow_presets
*
* @return Axis
* @return $this
*/
private function setShadowPresetsProperties($shadow_presets)
{
@@ -370,7 +370,7 @@ class Axis extends Properties
* @param array $properties_map
* @param mixed &$reference
*
* @return Axis
* @return $this
*/
private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
{
@@ -402,7 +402,7 @@ class Axis extends Properties
* @param int $alpha
* @param string $type
*
* @return Axis
* @return $this
*/
private function setShadowColor($color, $alpha, $type)
{
@@ -416,7 +416,7 @@ class Axis extends Properties
*
* @param float $blur
*
* @return Axis
* @return $this
*/
private function setShadowBlur($blur)
{
@@ -432,7 +432,7 @@ class Axis extends Properties
*
* @param int $angle
*
* @return Axis
* @return $this
*/
private function setShadowAngle($angle)
{
@@ -448,7 +448,7 @@ class Axis extends Properties
*
* @param float $distance
*
* @return Axis
* @return $this
*/
private function setShadowDistance($distance)
{
@@ -506,7 +506,7 @@ class Axis extends Properties
*
* @param float $size
*
* @return Axis
* @return $this
*/
private function setGlowSize($size)
{
@@ -524,7 +524,7 @@ class Axis extends Properties
* @param int $alpha
* @param string $type
*
* @return Axis
* @return $this
*/
private function setGlowColor($color, $alpha, $type)
{

View File

@@ -156,7 +156,7 @@ class Chart
* @param null|GridLines $majorGridlines
* @param null|GridLines $minorGridlines
*/
public function __construct($name, Title $title = null, Legend $legend = null, PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = '0', Title $xAxisLabel = null, Title $yAxisLabel = null, Axis $xAxis = null, Axis $yAxis = null, GridLines $majorGridlines = null, GridLines $minorGridlines = null)
public function __construct($name, Title $title = null, Legend $legend = null, PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = 'gap', Title $xAxisLabel = null, Title $yAxisLabel = null, Axis $xAxis = null, Axis $yAxis = null, GridLines $majorGridlines = null, GridLines $minorGridlines = null)
{
$this->name = $name;
$this->title = $title;
@@ -197,7 +197,7 @@ class Chart
*
* @param Worksheet $pValue
*
* @return Chart
* @return $this
*/
public function setWorksheet(Worksheet $pValue = null)
{
@@ -221,7 +221,7 @@ class Chart
*
* @param Title $title
*
* @return Chart
* @return $this
*/
public function setTitle(Title $title)
{
@@ -245,7 +245,7 @@ class Chart
*
* @param Legend $legend
*
* @return Chart
* @return $this
*/
public function setLegend(Legend $legend)
{
@@ -269,7 +269,7 @@ class Chart
*
* @param Title $label
*
* @return Chart
* @return $this
*/
public function setXAxisLabel(Title $label)
{
@@ -293,7 +293,7 @@ class Chart
*
* @param Title $label
*
* @return Chart
* @return $this
*/
public function setYAxisLabel(Title $label)
{
@@ -327,7 +327,7 @@ class Chart
*
* @param bool $plotVisibleOnly
*
* @return Chart
* @return $this
*/
public function setPlotVisibleOnly($plotVisibleOnly)
{
@@ -351,7 +351,7 @@ class Chart
*
* @param string $displayBlanksAs
*
* @return Chart
* @return $this
*/
public function setDisplayBlanksAs($displayBlanksAs)
{
@@ -423,7 +423,7 @@ class Chart
* @param int $xOffset
* @param int $yOffset
*
* @return Chart
* @return $this
*/
public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
{
@@ -467,7 +467,7 @@ class Chart
*
* @param string $cell
*
* @return Chart
* @return $this
*/
public function setTopLeftCell($cell)
{
@@ -482,7 +482,7 @@ class Chart
* @param int $xOffset
* @param int $yOffset
*
* @return Chart
* @return $this
*/
public function setTopLeftOffset($xOffset, $yOffset)
{
@@ -541,7 +541,7 @@ class Chart
* @param int $xOffset
* @param int $yOffset
*
* @return Chart
* @return $this
*/
public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
{
@@ -593,7 +593,7 @@ class Chart
* @param int $xOffset
* @param int $yOffset
*
* @return Chart
* @return $this
*/
public function setBottomRightOffset($xOffset, $yOffset)
{

View File

@@ -157,7 +157,7 @@ class DataSeries
*
* @param string $plotType
*
* @return DataSeries
* @return $this
*/
public function setPlotType($plotType)
{
@@ -181,7 +181,7 @@ class DataSeries
*
* @param string $groupingType
*
* @return DataSeries
* @return $this
*/
public function setPlotGrouping($groupingType)
{
@@ -205,7 +205,7 @@ class DataSeries
*
* @param string $plotDirection
*
* @return DataSeries
* @return $this
*/
public function setPlotDirection($plotDirection)
{
@@ -297,7 +297,7 @@ class DataSeries
*
* @param null|string $plotStyle
*
* @return DataSeries
* @return $this
*/
public function setPlotStyle($plotStyle)
{
@@ -360,7 +360,7 @@ class DataSeries
*
* @param bool $smoothLine
*
* @return DataSeries
* @return $this
*/
public function setSmoothLine($smoothLine)
{

View File

@@ -117,7 +117,7 @@ class DataSeriesValues
*
* @throws Exception
*
* @return DataSeriesValues
* @return $this
*/
public function setDataType($dataType)
{
@@ -144,7 +144,7 @@ class DataSeriesValues
*
* @param string $dataSource
*
* @return DataSeriesValues
* @return $this
*/
public function setDataSource($dataSource)
{
@@ -168,7 +168,7 @@ class DataSeriesValues
*
* @param string $marker
*
* @return DataSeriesValues
* @return $this
*/
public function setPointMarker($marker)
{
@@ -192,7 +192,7 @@ class DataSeriesValues
*
* @param string $formatCode
*
* @return DataSeriesValues
* @return $this
*/
public function setFormatCode($formatCode)
{
@@ -275,7 +275,7 @@ class DataSeriesValues
*
* @param int $width
*
* @return DataSeriesValues
* @return $this
*/
public function setLineWidth($width)
{
@@ -346,7 +346,7 @@ class DataSeriesValues
*
* @param array $dataValues
*
* @return DataSeriesValues
* @return $this
*/
public function setDataValues($dataValues)
{
@@ -370,13 +370,13 @@ class DataSeriesValues
if ($flatten) {
$this->dataValues = Functions::flattenArray($newDataValues);
foreach ($this->dataValues as &$dataValue) {
if ((!empty($dataValue)) && ($dataValue[0] == '#')) {
if (is_string($dataValue) && !empty($dataValue) && $dataValue[0] == '#') {
$dataValue = 0.0;
}
}
unset($dataValue);
} else {
list($worksheet, $cellRange) = Worksheet::extractSheetTitle($this->dataSource, true);
[$worksheet, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
$dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange));
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
$this->dataValues = Functions::flattenArray($newDataValues);

View File

@@ -91,7 +91,7 @@ class GridLines extends Properties
/**
* Change Object State to True.
*
* @return GridLines
* @return $this
*/
private function activateObject()
{
@@ -229,7 +229,7 @@ class GridLines extends Properties
*
* @param float $size
*
* @return GridLines
* @return $this
*/
private function setGlowSize($size)
{
@@ -245,7 +245,7 @@ class GridLines extends Properties
* @param int $alpha
* @param string $type
*
* @return GridLines
* @return $this
*/
private function setGlowColor($color, $alpha, $type)
{
@@ -305,7 +305,7 @@ class GridLines extends Properties
*
* @param int $shadow_presets
*
* @return GridLines
* @return $this
*/
private function setShadowPresetsProperties($shadow_presets)
{
@@ -321,7 +321,7 @@ class GridLines extends Properties
* @param array $properties_map
* @param mixed &$reference
*
* @return GridLines
* @return $this
*/
private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
{
@@ -353,7 +353,7 @@ class GridLines extends Properties
* @param int $alpha
* @param string $type
*
* @return GridLines
* @return $this
*/
private function setShadowColor($color, $alpha, $type)
{
@@ -375,7 +375,7 @@ class GridLines extends Properties
*
* @param float $blur
*
* @return GridLines
* @return $this
*/
private function setShadowBlur($blur)
{
@@ -391,7 +391,7 @@ class GridLines extends Properties
*
* @param int $angle
*
* @return GridLines
* @return $this
*/
private function setShadowAngle($angle)
{
@@ -407,7 +407,7 @@ class GridLines extends Properties
*
* @param float $distance
*
* @return GridLines
* @return $this
*/
private function setShadowDistance($distance)
{

View File

@@ -153,7 +153,7 @@ class Layout
*
* @param string $value
*
* @return Layout
* @return $this
*/
public function setLayoutTarget($value)
{
@@ -177,7 +177,7 @@ class Layout
*
* @param string $value
*
* @return Layout
* @return $this
*/
public function setXMode($value)
{
@@ -201,7 +201,7 @@ class Layout
*
* @param string $value
*
* @return Layout
* @return $this
*/
public function setYMode($value)
{
@@ -225,7 +225,7 @@ class Layout
*
* @param float $value
*
* @return Layout
* @return $this
*/
public function setXPosition($value)
{
@@ -249,7 +249,7 @@ class Layout
*
* @param float $value
*
* @return Layout
* @return $this
*/
public function setYPosition($value)
{
@@ -273,7 +273,7 @@ class Layout
*
* @param float $value
*
* @return Layout
* @return $this
*/
public function setWidth($value)
{
@@ -297,7 +297,7 @@ class Layout
*
* @param float $value
*
* @return Layout
* @return $this
*/
public function setHeight($value)
{
@@ -322,7 +322,7 @@ class Layout
*
* @param bool $value Show legend key
*
* @return Layout
* @return $this
*/
public function setShowLegendKey($value)
{
@@ -347,7 +347,7 @@ class Layout
*
* @param bool $value Show val
*
* @return Layout
* @return $this
*/
public function setShowVal($value)
{
@@ -372,7 +372,7 @@ class Layout
*
* @param bool $value Show cat name
*
* @return Layout
* @return $this
*/
public function setShowCatName($value)
{
@@ -397,7 +397,7 @@ class Layout
*
* @param bool $value Show series name
*
* @return Layout
* @return $this
*/
public function setShowSerName($value)
{
@@ -422,7 +422,7 @@ class Layout
*
* @param bool $value Show percentage
*
* @return Layout
* @return $this
*/
public function setShowPercent($value)
{
@@ -447,7 +447,7 @@ class Layout
*
* @param bool $value Show bubble size
*
* @return Layout
* @return $this
*/
public function setShowBubbleSize($value)
{
@@ -472,7 +472,7 @@ class Layout
*
* @param bool $value Show leader lines
*
* @return Layout
* @return $this
*/
public function setShowLeaderLines($value)
{

View File

@@ -94,7 +94,7 @@ class PlotArea
*
* @param DataSeries[] $plotSeries
*
* @return PlotArea
* @return $this
*/
public function setPlotSeries(array $plotSeries)
{

View File

@@ -442,7 +442,7 @@ class JpGraph implements IRenderer
$seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
} elseif ($scatterStyle == 'smoothMarker') {
$spline = new \Spline($dataValuesY, $dataValuesX);
list($splineDataY, $splineDataX) = $spline->Get(count($dataValuesX) * self::$width / 20);
[$splineDataY, $splineDataX] = $spline->Get(count($dataValuesX) * self::$width / 20);
$lplot = new \LinePlot($splineDataX, $splineDataY);
$lplot->SetColor(self::$colourSet[self::$plotColour]);

View File

@@ -45,7 +45,7 @@ class Title
*
* @param string $caption
*
* @return Title
* @return $this
*/
public function setCaption($caption)
{

View File

@@ -16,8 +16,6 @@ abstract class CellsFactory
* */
public static function getInstance(Worksheet $parent)
{
$instance = new Cells($parent, Settings::getCache());
return $instance;
return new Cells($parent, Settings::getCache());
}
}

View File

@@ -96,7 +96,7 @@ class Comment implements IComparable
*
* @param string $author
*
* @return Comment
* @return $this
*/
public function setAuthor($author)
{
@@ -120,7 +120,7 @@ class Comment implements IComparable
*
* @param RichText $pValue
*
* @return Comment
* @return $this
*/
public function setText(RichText $pValue)
{
@@ -144,7 +144,7 @@ class Comment implements IComparable
*
* @param string $width
*
* @return Comment
* @return $this
*/
public function setWidth($width)
{
@@ -168,7 +168,7 @@ class Comment implements IComparable
*
* @param string $value
*
* @return Comment
* @return $this
*/
public function setHeight($value)
{
@@ -192,7 +192,7 @@ class Comment implements IComparable
*
* @param string $value
*
* @return Comment
* @return $this
*/
public function setMarginLeft($value)
{
@@ -216,7 +216,7 @@ class Comment implements IComparable
*
* @param string $value
*
* @return Comment
* @return $this
*/
public function setMarginTop($value)
{
@@ -240,7 +240,7 @@ class Comment implements IComparable
*
* @param bool $value
*
* @return Comment
* @return $this
*/
public function setVisible($value)
{
@@ -264,7 +264,7 @@ class Comment implements IComparable
*
* @param string $alignment see Style\Alignment::HORIZONTAL_*
*
* @return Comment
* @return $this
*/
public function setAlignment($alignment)
{

View File

@@ -122,7 +122,7 @@ class Properties
*
* @param string $creator
*
* @return Properties
* @return $this
*/
public function setCreator($creator)
{
@@ -146,7 +146,7 @@ class Properties
*
* @param string $pValue
*
* @return Properties
* @return $this
*/
public function setLastModifiedBy($pValue)
{
@@ -170,7 +170,7 @@ class Properties
*
* @param int|string $time
*
* @return Properties
* @return $this
*/
public function setCreated($time)
{
@@ -204,7 +204,7 @@ class Properties
*
* @param int|string $time
*
* @return Properties
* @return $this
*/
public function setModified($time)
{
@@ -238,7 +238,7 @@ class Properties
*
* @param string $title
*
* @return Properties
* @return $this
*/
public function setTitle($title)
{
@@ -262,7 +262,7 @@ class Properties
*
* @param string $description
*
* @return Properties
* @return $this
*/
public function setDescription($description)
{
@@ -286,7 +286,7 @@ class Properties
*
* @param string $subject
*
* @return Properties
* @return $this
*/
public function setSubject($subject)
{
@@ -310,7 +310,7 @@ class Properties
*
* @param string $keywords
*
* @return Properties
* @return $this
*/
public function setKeywords($keywords)
{
@@ -334,7 +334,7 @@ class Properties
*
* @param string $category
*
* @return Properties
* @return $this
*/
public function setCategory($category)
{
@@ -358,7 +358,7 @@ class Properties
*
* @param string $company
*
* @return Properties
* @return $this
*/
public function setCompany($company)
{
@@ -382,7 +382,7 @@ class Properties
*
* @param string $manager
*
* @return Properties
* @return $this
*/
public function setManager($manager)
{
@@ -453,7 +453,7 @@ class Properties
* 'd' : Date/Time
* 'b' : Boolean
*
* @return Properties
* @return $this
*/
public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
{

View File

@@ -75,7 +75,7 @@ class Security
*
* @param bool $pValue
*
* @return Security
* @return $this
*/
public function setLockRevision($pValue)
{
@@ -99,7 +99,7 @@ class Security
*
* @param bool $pValue
*
* @return Security
* @return $this
*/
public function setLockStructure($pValue)
{
@@ -123,7 +123,7 @@ class Security
*
* @param bool $pValue
*
* @return Security
* @return $this
*/
public function setLockWindows($pValue)
{
@@ -148,7 +148,7 @@ class Security
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return Security
* @return $this
*/
public function setRevisionsPassword($pValue, $pAlreadyHashed = false)
{
@@ -176,7 +176,7 @@ class Security
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return Security
* @return $this
*/
public function setWorkbookPassword($pValue, $pAlreadyHashed = false)
{

View File

@@ -0,0 +1,111 @@
<?php
namespace PhpOffice\PhpSpreadsheet;
use PhpOffice\PhpSpreadsheet\Calculation\Category;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use ReflectionClass;
use ReflectionException;
use UnexpectedValueException;
class DocumentGenerator
{
/**
* @param array[] $phpSpreadsheetFunctions
*
* @throws ReflectionException
*
* @return string
*/
public static function generateFunctionListByCategory(array $phpSpreadsheetFunctions): string
{
$result = "# Function list by category\n";
foreach (self::getCategories() as $categoryConstant => $category) {
$result .= "\n";
$result .= "## {$categoryConstant}\n";
$result .= "\n";
$lengths = [20, 42];
$result .= self::tableRow($lengths, ['Excel Function', 'PhpSpreadsheet Function']) . "\n";
$result .= self::tableRow($lengths, null) . "\n";
foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) {
if ($category === $functionInfo['category']) {
$phpFunction = self::getPhpSpreadsheetFunctionText($functionInfo['functionCall']);
$result .= self::tableRow($lengths, [$excelFunction, $phpFunction]) . "\n";
}
}
}
return $result;
}
/**
* @throws ReflectionException
*
* @return array
*/
private static function getCategories(): array
{
return (new ReflectionClass(Category::class))->getConstants();
}
private static function tableRow(array $lengths, array $values = null): string
{
$result = '';
foreach (array_map(null, $lengths, $values ?? []) as $i => [$length, $value]) {
$pad = $value === null ? '-' : ' ';
if ($i > 0) {
$result .= '|' . $pad;
}
$result .= str_pad($value ?? '', $length, $pad);
}
return rtrim($result, ' ');
}
private static function getPhpSpreadsheetFunctionText($functionCall): string
{
if (is_string($functionCall)) {
return $functionCall;
}
if ($functionCall === [Functions::class, 'DUMMY']) {
return '**Not yet Implemented**';
}
if (is_array($functionCall)) {
return "\\{$functionCall[0]}::{$functionCall[1]}";
}
throw new UnexpectedValueException(
'$functionCall is of type ' . gettype($functionCall) . '. string or array expected'
);
}
/**
* @param array[] $phpSpreadsheetFunctions
*
* @throws ReflectionException
*
* @return string
*/
public static function generateFunctionListByName(array $phpSpreadsheetFunctions): string
{
$categoryConstants = array_flip(self::getCategories());
$result = "# Function list by name\n";
$lastAlphabet = null;
foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) {
$lengths = [20, 31, 42];
if ($lastAlphabet !== $excelFunction[0]) {
$lastAlphabet = $excelFunction[0];
$result .= "\n";
$result .= "## {$lastAlphabet}\n";
$result .= "\n";
$result .= self::tableRow($lengths, ['Excel Function', 'Category', 'PhpSpreadsheet Function']) . "\n";
$result .= self::tableRow($lengths, null) . "\n";
}
$category = $categoryConstants[$functionInfo['category']];
$phpFunction = self::getPhpSpreadsheetFunctionText($functionInfo['functionCall']);
$result .= self::tableRow($lengths, [$excelFunction, $category, $phpFunction]) . "\n";
}
return $result;
}
}

View File

@@ -52,9 +52,8 @@ abstract class IOFactory
// Instantiate writer
$className = self::$writers[$writerType];
$writer = new $className($spreadsheet);
return $writer;
return new $className($spreadsheet);
}
/**
@@ -74,9 +73,8 @@ abstract class IOFactory
// Instantiate reader
$className = self::$readers[$readerType];
$reader = new $className();
return $reader;
return new $className();
}
/**

View File

@@ -82,7 +82,7 @@ class NamedRange
*
* @param string $value
*
* @return NamedRange
* @return $this
*/
public function setName($value)
{
@@ -123,7 +123,7 @@ class NamedRange
*
* @param Worksheet $value
*
* @return NamedRange
* @return $this
*/
public function setWorksheet(Worksheet $value = null)
{
@@ -149,7 +149,7 @@ class NamedRange
*
* @param string $value
*
* @return NamedRange
* @return $this
*/
public function setRange($value)
{
@@ -175,7 +175,7 @@ class NamedRange
*
* @param bool $value
*
* @return NamedRange
* @return $this
*/
public function setLocalOnly($value)
{
@@ -200,7 +200,7 @@ class NamedRange
*
* @param null|Worksheet $value
*
* @return NamedRange
* @return $this
*/
public function setScope(Worksheet $value = null)
{

View File

@@ -70,7 +70,7 @@ class Csv extends BaseReader
*
* @param string $pValue Input encoding, eg: 'UTF-8'
*
* @return Csv
* @return $this
*/
public function setInputEncoding($pValue)
{
@@ -175,9 +175,8 @@ class Csv extends BaseReader
}
}
foreach ($potentialDelimiters as $delimiter) {
$counts[$delimiter][] = isset($countLine[$delimiter])
? $countLine[$delimiter]
: 0;
$counts[$delimiter][] = $countLine[$delimiter]
?? 0;
}
}
@@ -416,7 +415,7 @@ class Csv extends BaseReader
*
* @param string $delimiter Delimiter, eg: ','
*
* @return CSV
* @return $this
*/
public function setDelimiter($delimiter)
{
@@ -440,7 +439,7 @@ class Csv extends BaseReader
*
* @param string $enclosure Enclosure, defaults to "
*
* @return CSV
* @return $this
*/
public function setEnclosure($enclosure)
{
@@ -467,7 +466,7 @@ class Csv extends BaseReader
*
* @param int $pValue Sheet index
*
* @return CSV
* @return $this
*/
public function setSheetIndex($pValue)
{
@@ -481,7 +480,7 @@ class Csv extends BaseReader
*
* @param bool $contiguous
*
* @return Csv
* @return $this
*/
public function setContiguous($contiguous)
{

View File

@@ -267,7 +267,7 @@ class Gnumeric extends BaseReader
break;
case 'user-defined':
list(, $attrName) = explode(':', $attributes['name']);
[, $attrName] = explode(':', $attributes['name']);
switch ($attrName) {
case 'publisher':
$docProps->setCompany(trim($propertyValue));
@@ -879,7 +879,7 @@ class Gnumeric extends BaseReader
private static function parseGnumericColour($gnmColour)
{
list($gnmR, $gnmG, $gnmB) = explode(':', $gnmColour);
[$gnmR, $gnmG, $gnmB] = explode(':', $gnmColour);
$gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
$gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
$gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);

View File

@@ -223,7 +223,7 @@ class Html extends BaseReader
*
* @param string $pValue Input encoding, eg: 'ANSI'
*
* @return Html
* @return $this
*/
public function setInputEncoding($pValue)
{
@@ -374,8 +374,9 @@ class Html extends BaseReader
// no break
case 'br':
if ($this->tableLevel > 0) {
// If we're inside a table, replace with a \n
// If we're inside a table, replace with a \n and set the cell to wrap
$cellContent .= "\n";
$sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
} else {
// Otherwise flush our existing content and move the row cursor on
$this->flushCell($sheet, $column, $row, $cellContent);
@@ -489,22 +490,22 @@ class Html extends BaseReader
case 'td':
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
// apply inline style
$this->applyInlineStyle($sheet, $row, $column, $attributeArray);
while (isset($this->rowspan[$column . $row])) {
++$column;
}
// apply inline style
$this->applyInlineStyle($sheet, $row, $column, $attributeArray);
$this->flushCell($sheet, $column, $row, $cellContent);
if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
//create merging rowspan and colspan
$columnTo = $column;
for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
++$columnTo;
}
$range = $column . $row . ':' . $columnTo . ($row + $attributeArray['rowspan'] - 1);
$range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1);
foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
$this->rowspan[$value] = true;
}
@@ -512,7 +513,7 @@ class Html extends BaseReader
$column = $columnTo;
} elseif (isset($attributeArray['rowspan'])) {
//create merging rowspan
$range = $column . $row . ':' . $column . ($row + $attributeArray['rowspan'] - 1);
$range = $column . $row . ':' . $column . ($row + (int) $attributeArray['rowspan'] - 1);
foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
$this->rowspan[$value] = true;
}
@@ -520,7 +521,7 @@ class Html extends BaseReader
} elseif (isset($attributeArray['colspan'])) {
//create merging colspan
$columnTo = $column;
for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
++$columnTo;
}
$sheet->mergeCells($column . $row . ':' . $columnTo . $row);
@@ -591,28 +592,63 @@ class Html extends BaseReader
throw new Exception($pFilename . ' is an Invalid HTML file.');
}
// Create new sheet
while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
$spreadsheet->createSheet();
}
$spreadsheet->setActiveSheetIndex($this->sheetIndex);
// Create a new DOM object
// Create a new DOM object
$dom = new DOMDocument();
// Reload the HTML file into the DOM object
// Reload the HTML file into the DOM object
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
if ($loaded === false) {
throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document');
}
// Discard white space
$dom->preserveWhiteSpace = false;
return $this->loadDocument($dom, $spreadsheet);
}
/**
* Spreadsheet from content.
*
* @param string $content
* @param null|Spreadsheet $spreadsheet
*
* @return Spreadsheet
*/
public function loadFromString($content, ?Spreadsheet $spreadsheet = null): Spreadsheet
{
// Create a new DOM object
$dom = new DOMDocument();
// Reload the HTML file into the DOM object
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scan($content), 'HTML-ENTITIES', 'UTF-8'));
if ($loaded === false) {
throw new Exception('Failed to load content as a DOM Document');
}
return $this->loadDocument($dom, $spreadsheet ?? new Spreadsheet());
}
/**
* Loads PhpSpreadsheet from DOMDocument into PhpSpreadsheet instance.
*
* @param DOMDocument $document
* @param Spreadsheet $spreadsheet
*
* @throws \PhpOffice\PhpSpreadsheet\Exception
*
* @return Spreadsheet
*/
private function loadDocument(DOMDocument $document, Spreadsheet $spreadsheet): Spreadsheet
{
while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
$spreadsheet->createSheet();
}
$spreadsheet->setActiveSheetIndex($this->sheetIndex);
// Discard white space
$document->preserveWhiteSpace = false;
$row = 0;
$column = 'A';
$content = '';
$this->rowspan = [];
$this->processDomElement($dom, $spreadsheet->getActiveSheet(), $row, $column, $content);
$this->processDomElement($document, $spreadsheet->getActiveSheet(), $row, $column, $content);
// Return
return $spreadsheet;
@@ -633,7 +669,7 @@ class Html extends BaseReader
*
* @param int $pValue Sheet index
*
* @return HTML
* @return $this
*/
public function setSheetIndex($pValue)
{
@@ -919,7 +955,7 @@ class Html extends BaseReader
*/
private function setBorderStyle(Style $cellStyle, $styleValue, $type)
{
list(, $borderStyle, $color) = explode(' ', $styleValue);
[, $borderStyle, $color] = explode(' ', $styleValue);
$cellStyle->applyFromArray([
'borders' => [

View File

@@ -490,7 +490,7 @@ class Ods extends BaseReader
$dateObj = new DateTime($value, $GMT);
$dateObj->setTimeZone($timezoneObj);
list($year, $month, $day, $hour, $minute, $second) = explode(
[$year, $month, $day, $hour, $minute, $second] = explode(
' ',
$dateObj->format('Y m d H i s')
);

View File

@@ -19,12 +19,11 @@ class Properties
$docProps = $this->spreadsheet->getProperties();
$officeProperty = $xml->children($namespacesMeta['office']);
foreach ($officeProperty as $officePropertyData) {
/** @var \SimpleXMLElement $officePropertyData */
$officePropertiesDC = (object) [];
// @var \SimpleXMLElement $officePropertyData
if (isset($namespacesMeta['dc'])) {
$officePropertiesDC = $officePropertyData->children($namespacesMeta['dc']);
$this->setCoreProperties($docProps, $officePropertiesDC);
}
$this->setCoreProperties($docProps, $officePropertiesDC);
$officePropertyMeta = (object) [];
if (isset($namespacesMeta['dc'])) {

View File

@@ -83,7 +83,7 @@ class Slk extends BaseReader
*
* @param string $pValue Input encoding, eg: 'ANSI'
*
* @return Slk
* @return $this
*/
public function setInputEncoding($pValue)
{
@@ -384,7 +384,7 @@ class Slk extends BaseReader
break;
case 'W':
list($startCol, $endCol, $columnWidth) = explode(' ', substr($rowDatum, 1));
[$startCol, $endCol, $columnWidth] = explode(' ', substr($rowDatum, 1));
break;
case 'S':
@@ -485,7 +485,7 @@ class Slk extends BaseReader
*
* @param int $pValue Sheet index
*
* @return Slk
* @return $this
*/
public function setSheetIndex($pValue)
{

View File

@@ -1089,8 +1089,8 @@ class Xls extends BaseReader
}
// calculate the width and height of the shape
list($startColumn, $startRow) = Coordinate::coordinateFromString($spContainer->getStartCoordinates());
list($endColumn, $endRow) = Coordinate::coordinateFromString($spContainer->getEndCoordinates());
[$startColumn, $startRow] = Coordinate::coordinateFromString($spContainer->getStartCoordinates());
[$endColumn, $endRow] = Coordinate::coordinateFromString($spContainer->getEndCoordinates());
$startOffsetX = $spContainer->getStartOffsetX();
$startOffsetY = $spContainer->getStartOffsetY();
@@ -1175,7 +1175,7 @@ class Xls extends BaseReader
// treat SHAREDFMLA records
if ($this->version == self::XLS_BIFF8) {
foreach ($this->sharedFormulaParts as $cell => $baseCell) {
list($column, $row) = Coordinate::coordinateFromString($cell);
[$column, $row] = Coordinate::coordinateFromString($cell);
if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($column, $row, $this->phpSheet->getTitle())) {
$formula = $this->getFormulaFromStructure($this->sharedFormulas[$baseCell], $cell);
$this->phpSheet->getCell($cell)->setValueExplicit('=' . $formula, DataType::TYPE_FORMULA);
@@ -1251,8 +1251,8 @@ class Xls extends BaseReader
$coordinateStrings = explode(':', $extractedRange);
if (count($coordinateStrings) == 2) {
list($firstColumn, $firstRow) = Coordinate::coordinateFromString($coordinateStrings[0]);
list($lastColumn, $lastRow) = Coordinate::coordinateFromString($coordinateStrings[1]);
[$firstColumn, $firstRow] = Coordinate::coordinateFromString($coordinateStrings[0]);
[$lastColumn, $lastRow] = Coordinate::coordinateFromString($coordinateStrings[1]);
if ($firstColumn == 'A' and $lastColumn == 'IV') {
// then we have repeating rows
@@ -3825,7 +3825,7 @@ class Xls extends BaseReader
}
}
if (!$this->readDataOnly && !$emptyCell) {
if (!$this->readDataOnly && !$emptyCell && isset($this->mapCellXfIndex[$xfIndex])) {
// add style information
$cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
}
@@ -5279,12 +5279,10 @@ class Xls extends BaseReader
$nextIdentifier = self::getUInt2d($this->data, $this->pos);
} while ($nextIdentifier == self::XLS_TYPE_CONTINUE);
$splicedData = [
return [
'recordData' => $data,
'spliceOffsets' => $spliceOffsets,
];
return $splicedData;
}
/**
@@ -5355,12 +5353,12 @@ class Xls extends BaseReader
$formulaStrings = [];
foreach ($tokens as $token) {
// initialize spaces
$space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
$space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
$space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
$space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
$space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
$space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
$space0 = $space0 ?? ''; // spaces before next token, not tParen
$space1 = $space1 ?? ''; // carriage returns before next token, not tParen
$space2 = $space2 ?? ''; // spaces before opening parenthesis
$space3 = $space3 ?? ''; // carriage returns before opening parenthesis
$space4 = $space4 ?? ''; // spaces before closing parenthesis
$space5 = $space5 ?? ''; // carriage returns before closing parenthesis
switch ($token['name']) {
case 'tAdd': // addition
@@ -7145,7 +7143,7 @@ class Xls extends BaseReader
*/
private function readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
{
list($baseCol, $baseRow) = Coordinate::coordinateFromString($baseCell);
[$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell);
$baseCol = Coordinate::columnIndexFromString($baseCol) - 1;
// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
@@ -7328,7 +7326,7 @@ class Xls extends BaseReader
*/
private function readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
{
list($baseCol, $baseRow) = Coordinate::coordinateFromString($baseCell);
[$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell);
$baseCol = Coordinate::columnIndexFromString($baseCol) - 1;
// TODO: if cell range is just a single cell, should this funciton

View File

@@ -77,34 +77,17 @@ class Xlsx extends BaseReader
{
File::assertFile($pFilename);
$xl = false;
// Load file
$result = false;
$zip = new ZipArchive();
if ($zip->open($pFilename) === true) {
// check if it is an OOXML archive
$rels = simplexml_load_string(
$this->securityScanner->scan(
$this->getFromZipArchive($zip, '_rels/.rels')
),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
if ($rels !== false) {
foreach ($rels->Relationship as $rel) {
switch ($rel['Type']) {
case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
if (basename($rel['Target']) == 'workbook.xml') {
$xl = true;
}
break;
}
}
}
if ($zip->open($pFilename) === true) {
$workbookBasename = $this->getWorkbookBaseName($zip);
$result = !empty($workbookBasename);
$zip->close();
}
return $xl;
return $result;
}
/**
@@ -357,8 +340,9 @@ class Xlsx extends BaseReader
// Read the theme first, because we need the colour scheme when reading the styles
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$workbookBasename = $this->getWorkbookBaseName($zip);
$wbRels = simplexml_load_string(
$this->securityScanner->scan($this->getFromZipArchive($zip, 'xl/_rels/workbook.xml.rels')),
$this->securityScanner->scan($this->getFromZipArchive($zip, "xl/_rels/${workbookBasename}.rels")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
@@ -445,18 +429,20 @@ class Xlsx extends BaseReader
$sharedStrings = [];
$xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlStrings = simplexml_load_string(
$this->securityScanner->scan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
if (isset($xmlStrings, $xmlStrings->si)) {
foreach ($xmlStrings->si as $val) {
if (isset($val->t)) {
$sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
} elseif (isset($val->r)) {
$sharedStrings[] = $this->parseRichText($val);
if ($xpath) {
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlStrings = simplexml_load_string(
$this->securityScanner->scan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
if (isset($xmlStrings, $xmlStrings->si)) {
foreach ($xmlStrings->si as $val) {
if (isset($val->t)) {
$sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
} elseif (isset($val->r)) {
$sharedStrings[] = $this->parseRichText($val);
}
}
}
}
@@ -743,15 +729,6 @@ class Xlsx extends BaseReader
// read empty cells or the cells are not empty
if ($this->readEmptyCells || ($value !== null && $value !== '')) {
// Check for numeric values
if (is_numeric($value) && $cellDataType != 's') {
if ($value == (int) $value) {
$value = (int) $value;
} elseif ($value == (float) $value) {
$value = (float) $value;
}
}
// Rich text?
if ($value instanceof RichText && $this->readDataOnly) {
$value = $value->getPlainText();
@@ -1352,7 +1329,7 @@ class Xlsx extends BaseReader
$rangeSets = preg_split("/('?(?:.*?)'?(?:![A-Z0-9]+:[A-Z0-9]+)),?/", $extractedRange, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$newRangeSets = [];
foreach ($rangeSets as $rangeSet) {
list($sheetName, $rangeSet) = Worksheet::extractSheetTitle($rangeSet, true);
[$sheetName, $rangeSet] = Worksheet::extractSheetTitle($rangeSet, true);
if (strpos($rangeSet, ':') === false) {
$rangeSet = $rangeSet . ':' . $rangeSet;
}
@@ -1426,7 +1403,7 @@ class Xlsx extends BaseReader
$locatedSheet = $excel->getSheetByName($extractedSheetName);
// Modify range
list($worksheetName, $extractedRange) = Worksheet::extractSheetTitle($extractedRange, true);
[$worksheetName, $extractedRange] = Worksheet::extractSheetTitle($extractedRange, true);
}
if ($locatedSheet !== null) {
@@ -1437,7 +1414,7 @@ class Xlsx extends BaseReader
}
}
if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
if ((!$this->readDataOnly || !empty($this->loadSheetsOnly)) && isset($xmlWorkbook->bookViews->workbookView)) {
$workbookView = $xmlWorkbook->bookViews->workbookView;
// active sheet index
@@ -1643,8 +1620,6 @@ class Xlsx extends BaseReader
$docStyle->getFill()->setFillType($patternType);
if ($style->fill->patternFill->fgColor) {
$docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
} else {
$docStyle->getFill()->getStartColor()->setARGB('FF000000');
}
if ($style->fill->patternFill->bgColor) {
$docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
@@ -1841,7 +1816,7 @@ class Xlsx extends BaseReader
private static function getArrayItem($array, $key = 0)
{
return isset($array[$key]) ? $array[$key] : null;
return $array[$key] ?? null;
}
private static function dirAdd($base, $add)
@@ -1851,7 +1826,7 @@ class Xlsx extends BaseReader
private static function toCSSArray($style)
{
$style = trim(str_replace(["\r", "\n"], '', $style), ';');
$style = self::stripWhiteSpaceFromStyleString($style);
$temp = explode(';', $style);
$style = [];
@@ -1880,6 +1855,11 @@ class Xlsx extends BaseReader
return $style;
}
public static function stripWhiteSpaceFromStyleString($string)
{
return trim(str_replace(["\r", "\n", ' '], '', $string), ';');
}
private static function boolean($value)
{
if (is_object($value)) {
@@ -2026,4 +2006,38 @@ class Xlsx extends BaseReader
return (bool) $xsdBoolean;
}
/**
* @param ZipArchive $zip Opened zip archive
*
* @return string basename of the used excel workbook
*/
private function getWorkbookBaseName(ZipArchive $zip)
{
$workbookBasename = '';
// check if it is an OOXML archive
$rels = simplexml_load_string(
$this->securityScanner->scan(
$this->getFromZipArchive($zip, '_rels/.rels')
),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
if ($rels !== false) {
foreach ($rels->Relationship as $rel) {
switch ($rel['Type']) {
case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
$basename = basename($rel['Target']);
if (preg_match('/workbook.*\.xml/', $basename)) {
$workbookBasename = $basename;
}
break;
}
}
}
return $workbookBasename;
}
}

View File

@@ -20,7 +20,8 @@ class AutoFilter
public function load()
{
$autoFilterRange = (string) $this->worksheetXml->autoFilter['ref'];
// Remove all "$" in the auto filter range
$autoFilterRange = preg_replace('/\$/', '', $this->worksheetXml->autoFilter['ref']);
if (strpos($autoFilterRange, ':') !== false) {
$this->readAutoFilter($autoFilterRange, $this->worksheetXml);
}

View File

@@ -36,6 +36,8 @@ class ConditionalStyles
if (((string) $cfRule['type'] == Conditional::CONDITION_NONE
|| (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS
|| (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS
|| (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
&& isset($this->dxfs[(int) ($cfRule['dxfId'])])) {
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;

View File

@@ -86,6 +86,6 @@ class Properties
private static function getArrayItem(array $array, $key = 0)
{
return isset($array[$key]) ? $array[$key] : null;
return $array[$key] ?? null;
}
}

View File

@@ -24,6 +24,7 @@ class SheetViews extends BaseParserClass
$this->gridLines();
$this->headers();
$this->direction();
$this->showZeros();
if (isset($this->sheetViewXml->pane)) {
$this->pane();
@@ -92,6 +93,15 @@ class SheetViews extends BaseParserClass
}
}
private function showZeros()
{
if (isset($this->sheetViewXml['showZeros'])) {
$this->worksheet->getSheetView()->setShowZeros(
self::boolean((string) $this->sheetViewXml['showZeros'])
);
}
}
private function pane()
{
$xSplit = 0;

View File

@@ -8,6 +8,7 @@ use PhpOffice\PhpSpreadsheet\Style\Borders;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Style\Protection;
use PhpOffice\PhpSpreadsheet\Style\Style;
@@ -71,6 +72,17 @@ class Styles extends BaseParserClass
}
}
private static function readNumberFormat(NumberFormat $numfmtStyle, \SimpleXMLElement $numfmtStyleXml)
{
if ($numfmtStyleXml->count() === 0) {
return;
}
$numfmt = $numfmtStyleXml->attributes();
if ($numfmt->count() > 0 && isset($numfmt['formatCode'])) {
$numfmtStyle->setFormatCode((string) $numfmt['formatCode']);
}
}
private static function readFillStyle(Fill $fillStyle, \SimpleXMLElement $fillStyleXml)
{
if ($fillStyleXml->gradientFill) {
@@ -149,7 +161,11 @@ class Styles extends BaseParserClass
private function readStyle(Style $docStyle, $style)
{
$docStyle->getNumberFormat()->setFormatCode($style->numFmt);
if ($style->numFmt instanceof \SimpleXMLElement) {
self::readNumberFormat($docStyle->getNumberFormat(), $style->numFmt);
} else {
$docStyle->getNumberFormat()->setFormatCode($style->numFmt);
}
if (isset($style->font)) {
self::readFontStyle($docStyle->getFont(), $style->font);
@@ -163,7 +179,7 @@ class Styles extends BaseParserClass
self::readBorderStyle($docStyle->getBorders(), $style->border);
}
if (isset($style->alignment)) {
if (isset($style->alignment->alignment)) {
self::readAlignmentStyle($docStyle->getAlignment(), $style->alignment);
}
@@ -260,6 +276,6 @@ class Styles extends BaseParserClass
private static function getArrayItem($array, $key = 0)
{
return isset($array[$key]) ? $array[$key] : null;
return $array[$key] ?? null;
}
}

View File

@@ -285,9 +285,8 @@ class Xml extends BaseReader
{
$pixels = ($widthUnits / 256) * 7;
$offsetWidthUnits = $widthUnits % 256;
$pixels += round($offsetWidthUnits / (256 / 7));
return $pixels;
return $pixels + round($offsetWidthUnits / (256 / 7));
}
protected static function hex2str($hex)

View File

@@ -82,11 +82,8 @@ class ReferenceHelper
*/
public static function cellSort($a, $b)
{
// TODO Scrutinizer doesn't like sscanf($a, '%[A-Z]%d', $ac, $ar), and we can't use short list() syntax
// [$ac, $ar] = sscanf($a, '%[A-Z]%d') while retaining PHP 5.6 support.
// Switch when we drop support for 5.6
list($ac, $ar) = sscanf($a, '%[A-Z]%d');
list($bc, $br) = sscanf($b, '%[A-Z]%d');
[$ac, $ar] = sscanf($a, '%[A-Z]%d');
[$bc, $br] = sscanf($b, '%[A-Z]%d');
if ($ar === $br) {
return strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
@@ -106,11 +103,8 @@ class ReferenceHelper
*/
public static function cellReverseSort($a, $b)
{
// TODO Scrutinizer doesn't like sscanf($a, '%[A-Z]%d', $ac, $ar), and we can't use short list() syntax
// [$ac, $ar] = sscanf($a, '%[A-Z]%d') while retaining PHP 5.6 support.
// Switch when we drop support for 5.6
list($ac, $ar) = sscanf($a, '%[A-Z]%d');
list($bc, $br) = sscanf($b, '%[A-Z]%d');
[$ac, $ar] = sscanf($a, '%[A-Z]%d');
[$bc, $br] = sscanf($b, '%[A-Z]%d');
if ($ar === $br) {
return 1 - strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
@@ -132,7 +126,7 @@ class ReferenceHelper
*/
private static function cellAddressInDeleteRange($cellAddress, $beforeRow, $pNumRows, $beforeColumnIndex, $pNumCols)
{
list($cellColumn, $cellRow) = Coordinate::coordinateFromString($cellAddress);
[$cellColumn, $cellRow] = Coordinate::coordinateFromString($cellAddress);
$cellColumnIndex = Coordinate::columnIndexFromString($cellColumn);
// Is cell within the range of rows/columns if we're deleting
if ($pNumRows < 0 &&
@@ -319,7 +313,7 @@ class ReferenceHelper
if (!empty($aColumnDimensions)) {
foreach ($aColumnDimensions as $objColumnDimension) {
$newReference = $this->updateCellReference($objColumnDimension->getColumnIndex() . '1', $pBefore, $pNumCols, $pNumRows);
list($newReference) = Coordinate::coordinateFromString($newReference);
[$newReference] = Coordinate::coordinateFromString($newReference);
if ($objColumnDimension->getColumnIndex() != $newReference) {
$objColumnDimension->setColumnIndex($newReference);
}
@@ -344,7 +338,7 @@ class ReferenceHelper
if (!empty($aRowDimensions)) {
foreach ($aRowDimensions as $objRowDimension) {
$newReference = $this->updateCellReference('A' . $objRowDimension->getRowIndex(), $pBefore, $pNumCols, $pNumRows);
list(, $newReference) = Coordinate::coordinateFromString($newReference);
[, $newReference] = Coordinate::coordinateFromString($newReference);
if ($objRowDimension->getRowIndex() != $newReference) {
$objRowDimension->setRowIndex($newReference);
}
@@ -378,7 +372,7 @@ class ReferenceHelper
$allCoordinates = $pSheet->getCoordinates();
// Get coordinate of $pBefore
list($beforeColumn, $beforeRow) = Coordinate::coordinateFromString($pBefore);
[$beforeColumn, $beforeRow] = Coordinate::coordinateFromString($pBefore);
$beforeColumnIndex = Coordinate::columnIndexFromString($beforeColumn);
// Clear cells if we are removing columns or rows
@@ -539,7 +533,7 @@ class ReferenceHelper
$row = 0;
sscanf($pBefore, '%[A-Z]%d', $column, $row);
$columnIndex = Coordinate::columnIndexFromString($column);
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($autoFilterRange);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($autoFilterRange);
if ($columnIndex <= $rangeEnd[0]) {
if ($pNumCols < 0) {
// If we're actually deleting any columns that fall within the autofilter range,
@@ -707,7 +701,7 @@ class ReferenceHelper
if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
$toString = ($match[2] > '') ? $match[2] . '!' : '';
$toString .= $modified3 . ':' . $modified4;
list($column, $row) = Coordinate::coordinateFromString($match[3]);
[$column, $row] = Coordinate::coordinateFromString($match[3]);
// Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
$column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000;
$row = trim($row, '$') + 10000000;
@@ -733,7 +727,7 @@ class ReferenceHelper
if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
$toString = ($match[2] > '') ? $match[2] . '!' : '';
$toString .= $modified3;
list($column, $row) = Coordinate::coordinateFromString($match[3]);
[$column, $row] = Coordinate::coordinateFromString($match[3]);
// Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
$column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000;
$row = trim($row, '$') + 10000000;
@@ -881,10 +875,10 @@ class ReferenceHelper
}
// Get coordinate of $pBefore
list($beforeColumn, $beforeRow) = Coordinate::coordinateFromString($pBefore);
[$beforeColumn, $beforeRow] = Coordinate::coordinateFromString($pBefore);
// Get coordinate of $pCellReference
list($newColumn, $newRow) = Coordinate::coordinateFromString($pCellReference);
[$newColumn, $newRow] = Coordinate::coordinateFromString($pCellReference);
// Verify which parts should be updated
$updateColumn = (($newColumn[0] != '$') && ($beforeColumn[0] != '$') && (Coordinate::columnIndexFromString($newColumn) >= Coordinate::columnIndexFromString($beforeColumn)));

View File

@@ -47,7 +47,7 @@ class RichText implements IComparable
*
* @param ITextElement $pText Rich text element
*
* @return RichText
* @return $this
*/
public function addText(ITextElement $pText)
{
@@ -133,7 +133,7 @@ class RichText implements IComparable
*
* @param ITextElement[] $textElements Array of elements
*
* @return RichText
* @return $this
*/
public function setRichTextElements(array $textElements)
{

View File

@@ -40,7 +40,7 @@ class Run extends TextElement implements ITextElement
*
* @param Font $pFont Font
*
* @return ITextElement
* @return $this
*/
public function setFont(Font $pFont = null)
{

View File

@@ -37,7 +37,7 @@ class TextElement implements ITextElement
*
* @param $text string Text
*
* @return ITextElement
* @return $this
*/
public function setText($text)
{

View File

@@ -30,7 +30,6 @@ class Settings
* 7.2 < 7.2.1
* 7.1 < 7.1.13
* 7.0 < 7.0.27
* 5.6 ANY
* then you may need to disable this check to prevent unwanted behaviour in other threads
* SECURITY WARNING: Changing this flag is not recommended.
*
@@ -122,7 +121,6 @@ class Settings
* 7.2 < 7.2.1
* 7.1 < 7.1.13
* 7.0 < 7.0.27
* 5.6 ANY
* then you may need to disable this check to prevent unwanted behaviour in other threads
* SECURITY WARNING: Changing this flag to false is not recommended.
*

View File

@@ -298,9 +298,7 @@ class Font
$upperLeftCornerX = $textBox[6];
// Consider the rotation when calculating the width
$textWidth = max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
return $textWidth;
return max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
}
/**

View File

@@ -174,7 +174,7 @@ class Matrix
switch ($match) {
//A($i0...; $j0...)
case 'integer,integer':
list($i0, $j0) = $args;
[$i0, $j0] = $args;
if ($i0 >= 0) {
$m = $this->m - $i0;
} else {
@@ -197,7 +197,7 @@ class Matrix
break;
//A($i0...$iF; $j0...$jF)
case 'integer,integer,integer,integer':
list($i0, $iF, $j0, $jF) = $args;
[$i0, $iF, $j0, $jF] = $args;
if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
$m = $iF - $i0;
} else {
@@ -220,7 +220,7 @@ class Matrix
break;
//$R = array of row indices; $C = array of column indices
case 'array,array':
list($RL, $CL) = $args;
[$RL, $CL] = $args;
if (count($RL) > 0) {
$m = count($RL);
} else {
@@ -243,7 +243,7 @@ class Matrix
break;
//A($i0...$iF); $CL = array of column indices
case 'integer,integer,array':
list($i0, $iF, $CL) = $args;
[$i0, $iF, $CL] = $args;
if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
$m = $iF - $i0;
} else {
@@ -266,7 +266,7 @@ class Matrix
break;
//$RL = array of row indices
case 'array,integer,integer':
list($RL, $j0, $jF) = $args;
[$RL, $j0, $jF] = $args;
if (count($RL) > 0) {
$m = count($RL);
} else {
@@ -524,7 +524,7 @@ class Matrix
*
* @param mixed $B Matrix/Array
*
* @return Matrix Sum
* @return $this
*/
public function plusEquals(...$args)
{
@@ -628,7 +628,7 @@ class Matrix
*
* @param mixed $B Matrix/Array
*
* @return Matrix Sum
* @return $this
*/
public function minusEquals(...$args)
{
@@ -734,7 +734,7 @@ class Matrix
*
* @param mixed $B Matrix/Array
*
* @return Matrix Matrix Aij
* @return $this
*/
public function arrayTimesEquals(...$args)
{
@@ -1091,7 +1091,7 @@ class Matrix
*
* @param mixed $B Matrix/Array
*
* @return Matrix Sum
* @return $this
*/
public function power(...$args)
{
@@ -1150,7 +1150,7 @@ class Matrix
*
* @param mixed $B Matrix/Array
*
* @return Matrix Sum
* @return $this
*/
public function concat(...$args)
{

View File

@@ -60,7 +60,7 @@ class QRDecomposition
{
if ($A instanceof Matrix) {
// Initialize.
$this->QR = $A->getArrayCopy();
$this->QR = $A->getArray();
$this->m = $A->getRowDimension();
$this->n = $A->getColumnDimension();
// Main loop.

View File

@@ -253,7 +253,7 @@ class OLE
*/
private static function _readInt1($fh)
{
list(, $tmp) = unpack('c', fread($fh, 1));
[, $tmp] = unpack('c', fread($fh, 1));
return $tmp;
}
@@ -267,7 +267,7 @@ class OLE
*/
private static function _readInt2($fh)
{
list(, $tmp) = unpack('v', fread($fh, 2));
[, $tmp] = unpack('v', fread($fh, 2));
return $tmp;
}
@@ -281,7 +281,7 @@ class OLE
*/
private static function _readInt4($fh)
{
list(, $tmp) = unpack('V', fread($fh, 4));
[, $tmp] = unpack('V', fread($fh, 4));
return $tmp;
}

View File

@@ -118,7 +118,7 @@ class Root extends PPS
$aList = [];
PPS::_savePpsSetPnt($aList, [$this]);
// calculate values for header
list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
[$iSBDcnt, $iBBcnt, $iPPScnt] = $this->_calcSize($aList); //, $rhInfo);
// Save Header
$this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
@@ -149,7 +149,7 @@ class Root extends PPS
public function _calcSize(&$raList)
{
// Calculate Basic Setting
list($iSBDcnt, $iBBcnt, $iPPScnt) = [0, 0, 0];
[$iSBDcnt, $iBBcnt, $iPPScnt] = [0, 0, 0];
$iSmallLen = 0;
$iSBcnt = 0;
$iCount = count($raList);

View File

@@ -430,9 +430,7 @@ class StringHelper
// characters
$chars = self::convertEncoding($value, 'UTF-16LE', 'UTF-8');
$data = pack('vC', $ln, 0x0001) . $chars;
return $data;
return pack('vC', $ln, 0x0001) . $chars;
}
/**

View File

@@ -211,7 +211,7 @@ class Xls
*/
public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height)
{
list($column, $row) = Coordinate::coordinateFromString($coordinates);
[$column, $row] = Coordinate::coordinateFromString($coordinates);
$col_start = Coordinate::columnIndexFromString($column);
$row_start = $row - 1;
@@ -269,7 +269,7 @@ class Xls
$startCoordinates = Coordinate::stringFromColumnIndex($col_start) . ($row_start + 1);
$endCoordinates = Coordinate::stringFromColumnIndex($col_end) . ($row_end + 1);
$twoAnchor = [
return [
'startCoordinates' => $startCoordinates,
'startOffsetX' => $x1,
'startOffsetY' => $y1,
@@ -277,7 +277,5 @@ class Xls
'endOffsetX' => $x2,
'endOffsetY' => $y2,
];
return $twoAnchor;
}
}

View File

@@ -721,7 +721,7 @@ class Spreadsheet
{
$worksheetCount = count($this->workSheetCollection);
for ($i = 0; $i < $worksheetCount; ++$i) {
if ($this->workSheetCollection[$i]->getTitle() === $pName) {
if ($this->workSheetCollection[$i]->getTitle() === trim($pName, "'")) {
return $this->workSheetCollection[$i];
}
}
@@ -955,7 +955,7 @@ class Spreadsheet
* @param string $namedRange
* @param null|Worksheet $pSheet scope: use null for global scope
*
* @return Spreadsheet
* @return $this
*/
public function removeNamedRange($namedRange, Worksheet $pSheet = null)
{

View File

@@ -140,7 +140,7 @@ class Alignment extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Alignment
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -193,7 +193,7 @@ class Alignment extends Supervisor
*
* @param string $pValue see self::HORIZONTAL_*
*
* @return Alignment
* @return $this
*/
public function setHorizontal($pValue)
{
@@ -230,7 +230,7 @@ class Alignment extends Supervisor
*
* @param string $pValue see self::VERTICAL_*
*
* @return Alignment
* @return $this
*/
public function setVertical($pValue)
{
@@ -269,7 +269,7 @@ class Alignment extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Alignment
* @return $this
*/
public function setTextRotation($pValue)
{
@@ -312,7 +312,7 @@ class Alignment extends Supervisor
*
* @param bool $pValue
*
* @return Alignment
* @return $this
*/
public function setWrapText($pValue)
{
@@ -348,7 +348,7 @@ class Alignment extends Supervisor
*
* @param bool $pValue
*
* @return Alignment
* @return $this
*/
public function setShrinkToFit($pValue)
{
@@ -384,7 +384,7 @@ class Alignment extends Supervisor
*
* @param int $pValue
*
* @return Alignment
* @return $this
*/
public function setIndent($pValue)
{
@@ -424,7 +424,7 @@ class Alignment extends Supervisor
*
* @param int $pValue
*
* @return Alignment
* @return $this
*/
public function setReadOrder($pValue)
{

View File

@@ -127,7 +127,7 @@ class Border extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Border
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -166,7 +166,7 @@ class Border extends Supervisor
* When passing a boolean, FALSE equates Border::BORDER_NONE
* and TRUE to Border::BORDER_MEDIUM
*
* @return Border
* @return $this
*/
public function setBorderStyle($pValue)
{
@@ -202,7 +202,7 @@ class Border extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Border
* @return $this
*/
public function setColor(Color $pValue)
{

View File

@@ -197,7 +197,7 @@ class Borders extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Borders
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -382,7 +382,7 @@ class Borders extends Supervisor
*
* @param int $pValue see self::DIAGONAL_*
*
* @return Borders
* @return $this
*/
public function setDiagonalDirection($pValue)
{

View File

@@ -6,6 +6,17 @@ use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
class Color extends Supervisor
{
const NAMED_COLORS = [
'Black',
'White',
'Red',
'Green',
'Blue',
'Yellow',
'Magenta',
'Cyan',
];
// Colors
const COLOR_BLACK = 'FF000000';
const COLOR_WHITE = 'FFFFFFFF';
@@ -95,7 +106,7 @@ class Color extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Color
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -132,7 +143,7 @@ class Color extends Supervisor
*
* @param string $pValue see self::COLOR_*
*
* @return Color
* @return $this
*/
public function setARGB($pValue)
{
@@ -168,7 +179,7 @@ class Color extends Supervisor
*
* @param string $pValue RGB value
*
* @return Color
* @return $this
*/
public function setRGB($pValue)
{
@@ -198,11 +209,8 @@ class Color extends Supervisor
private static function getColourComponent($RGB, $offset, $hex = true)
{
$colour = substr($RGB, $offset, 2);
if (!$hex) {
$colour = hexdec($colour);
}
return $colour;
return ($hex) ? $colour : hexdec($colour);
}
/**
@@ -257,7 +265,7 @@ class Color extends Supervisor
*/
public static function changeBrightness($hex, $adjustPercentage)
{
$rgba = (strlen($hex) == 8);
$rgba = (strlen($hex) === 8);
$red = self::getRed($hex, false);
$green = self::getGreen($hex, false);
@@ -289,9 +297,9 @@ class Color extends Supervisor
}
$rgb = strtoupper(
str_pad(dechex($red), 2, '0', 0) .
str_pad(dechex($green), 2, '0', 0) .
str_pad(dechex($blue), 2, '0', 0)
str_pad(dechex((int) $red), 2, '0', 0) .
str_pad(dechex((int) $green), 2, '0', 0) .
str_pad(dechex((int) $blue), 2, '0', 0)
);
return (($rgba) ? 'FF' : '') . $rgb;
@@ -304,7 +312,7 @@ class Color extends Supervisor
* @param bool $background Flag to indicate whether default background or foreground colour
* should be returned if the indexed colour doesn't exist
*
* @return Color
* @return self
*/
public static function indexedColor($pIndex, $background = false)
{

View File

@@ -12,6 +12,7 @@ class Conditional implements IComparable
const CONDITION_CONTAINSTEXT = 'containsText';
const CONDITION_EXPRESSION = 'expression';
const CONDITION_CONTAINSBLANKS = 'containsBlanks';
const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks';
// Operator types
const OPERATOR_NONE = '';
@@ -93,7 +94,7 @@ class Conditional implements IComparable
*
* @param string $pValue Condition type, see self::CONDITION_*
*
* @return Conditional
* @return $this
*/
public function setConditionType($pValue)
{
@@ -117,7 +118,7 @@ class Conditional implements IComparable
*
* @param string $pValue Conditional operator type, see self::OPERATOR_*
*
* @return Conditional
* @return $this
*/
public function setOperatorType($pValue)
{
@@ -141,7 +142,7 @@ class Conditional implements IComparable
*
* @param string $value
*
* @return Conditional
* @return $this
*/
public function setText($value)
{
@@ -165,7 +166,7 @@ class Conditional implements IComparable
*
* @param bool $value
*
* @return Conditional
* @return $this
*/
public function setStopIfTrue($value)
{
@@ -189,7 +190,7 @@ class Conditional implements IComparable
*
* @param string[] $pValue Condition
*
* @return Conditional
* @return $this
*/
public function setConditions($pValue)
{
@@ -206,7 +207,7 @@ class Conditional implements IComparable
*
* @param string $pValue Condition
*
* @return Conditional
* @return $this
*/
public function addCondition($pValue)
{
@@ -230,7 +231,7 @@ class Conditional implements IComparable
*
* @param Style $pValue
*
* @return Conditional
* @return $this
*/
public function setStyle(Style $pValue = null)
{

View File

@@ -141,7 +141,7 @@ class Fill extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Fill
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -188,7 +188,7 @@ class Fill extends Supervisor
*
* @param string $pValue Fill type, see self::FILL_*
*
* @return Fill
* @return $this
*/
public function setFillType($pValue)
{
@@ -221,7 +221,7 @@ class Fill extends Supervisor
*
* @param float $pValue
*
* @return Fill
* @return $this
*/
public function setRotation($pValue)
{
@@ -252,7 +252,7 @@ class Fill extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Fill
* @return $this
*/
public function setStartColor(Color $pValue)
{
@@ -286,7 +286,7 @@ class Fill extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Fill
* @return $this
*/
public function setEndColor(Color $pValue)
{
@@ -313,12 +313,13 @@ class Fill extends Supervisor
if ($this->isSupervisor) {
return $this->getSharedComponent()->getHashCode();
}
// Note that we don't care about colours for fill type NONE, but could have duplicate NONEs with
// different hashes if we don't explicitly prevent this
return md5(
$this->getFillType() .
$this->getRotation() .
$this->getStartColor()->getHashCode() .
$this->getEndColor()->getHashCode() .
($this->getFillType() !== self::FILL_NONE ? $this->getStartColor()->getHashCode() : '') .
($this->getFillType() !== self::FILL_NONE ? $this->getEndColor()->getHashCode() : '') .
__CLASS__
);
}

View File

@@ -161,7 +161,7 @@ class Font extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Font
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -219,7 +219,7 @@ class Font extends Supervisor
*
* @param string $pValue
*
* @return Font
* @return $this
*/
public function setName($pValue)
{
@@ -255,7 +255,7 @@ class Font extends Supervisor
*
* @param float $pValue
*
* @return Font
* @return $this
*/
public function setSize($pValue)
{
@@ -291,7 +291,7 @@ class Font extends Supervisor
*
* @param bool $pValue
*
* @return Font
* @return $this
*/
public function setBold($pValue)
{
@@ -327,7 +327,7 @@ class Font extends Supervisor
*
* @param bool $pValue
*
* @return Font
* @return $this
*/
public function setItalic($pValue)
{
@@ -363,7 +363,7 @@ class Font extends Supervisor
*
* @param bool $pValue
*
* @return Font
* @return $this
*/
public function setSuperscript($pValue)
{
@@ -400,7 +400,7 @@ class Font extends Supervisor
*
* @param bool $pValue
*
* @return Font
* @return $this
*/
public function setSubscript($pValue)
{
@@ -439,7 +439,7 @@ class Font extends Supervisor
* If a boolean is passed, then TRUE equates to UNDERLINE_SINGLE,
* false equates to UNDERLINE_NONE
*
* @return Font
* @return $this
*/
public function setUnderline($pValue)
{
@@ -477,7 +477,7 @@ class Font extends Supervisor
*
* @param bool $pValue
*
* @return Font
* @return $this
*/
public function setStrikethrough($pValue)
{
@@ -512,7 +512,7 @@ class Font extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Font
* @return $this
*/
public function setColor(Color $pValue)
{

View File

@@ -23,8 +23,8 @@ class NumberFormat extends Supervisor
const FORMAT_PERCENTAGE_00 = '0.00%';
const FORMAT_DATE_YYYYMMDD2 = 'yyyy-mm-dd';
const FORMAT_DATE_YYYYMMDD = 'yy-mm-dd';
const FORMAT_DATE_DDMMYYYY = 'dd/mm/yy';
const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd';
const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy';
const FORMAT_DATE_DMYSLASH = 'd/m/yy';
const FORMAT_DATE_DMYMINUS = 'd-m-yy';
const FORMAT_DATE_DMMINUS = 'd-m';
@@ -43,7 +43,7 @@ class NumberFormat extends Supervisor
const FORMAT_DATE_TIME6 = 'h:mm:ss';
const FORMAT_DATE_TIME7 = 'i:s.S';
const FORMAT_DATE_TIME8 = 'h:mm:ss;@';
const FORMAT_DATE_YYYYMMDDSLASH = 'yy/mm/dd;@';
const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@';
const FORMAT_CURRENCY_USD_SIMPLE = '"$"#,##0.00_-';
const FORMAT_CURRENCY_USD = '$#,##0_-';
@@ -139,7 +139,7 @@ class NumberFormat extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return NumberFormat
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -176,7 +176,7 @@ class NumberFormat extends Supervisor
*
* @param string $pValue see self::FORMAT_*
*
* @return NumberFormat
* @return $this
*/
public function setFormatCode($pValue)
{
@@ -213,7 +213,7 @@ class NumberFormat extends Supervisor
*
* @param int $pValue
*
* @return NumberFormat
* @return $this
*/
public function setBuiltInFormatCode($pValue)
{
@@ -367,7 +367,7 @@ class NumberFormat extends Supervisor
self::fillBuiltInFormatCodes();
// Lookup format code
if (isset(self::$flippedBuiltInFormats[$formatCode])) {
if (array_key_exists($formatCode, self::$flippedBuiltInFormats)) {
return self::$flippedBuiltInFormats[$formatCode];
}
@@ -551,24 +551,32 @@ class NumberFormat extends Supervisor
}
}
private static function complexNumberFormatMask($number, $mask)
private static function mergeComplexNumberFormatMasks($numbers, $masks)
{
$sign = ($number < 0.0);
$number = abs($number);
if (strpos($mask, '.') !== false) {
$numbers = explode('.', $number . '.0');
$masks = explode('.', $mask . '.0');
$result1 = self::complexNumberFormatMask($numbers[0], $masks[0]);
$result2 = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1])));
$decimalCount = strlen($numbers[1]);
$postDecimalMasks = [];
return (($sign) ? '-' : '') . $result1 . '.' . $result2;
}
do {
$tempMask = array_pop($masks);
$postDecimalMasks[] = $tempMask;
$decimalCount -= strlen($tempMask);
} while ($decimalCount > 0);
$r = preg_match_all('/0+/', $mask, $result, PREG_OFFSET_CAPTURE);
if ($r > 1) {
$result = array_reverse($result[0]);
return [
implode('.', $masks),
implode('.', array_reverse($postDecimalMasks)),
];
}
foreach ($result as $block) {
private static function processComplexNumberFormatMask($number, $mask)
{
$result = $number;
$maskingBlockCount = preg_match_all('/0+/', $mask, $maskingBlocks, PREG_OFFSET_CAPTURE);
if ($maskingBlockCount > 1) {
$maskingBlocks = array_reverse($maskingBlocks[0]);
foreach ($maskingBlocks as $block) {
$divisor = 1 . $block[0];
$size = strlen($block[0]);
$offset = $block[1];
@@ -584,13 +592,134 @@ class NumberFormat extends Supervisor
$mask = substr_replace($mask, $number, $offset, 0);
}
$result = $mask;
} else {
$result = $number;
}
return $result;
}
private static function complexNumberFormatMask($number, $mask, $splitOnPoint = true)
{
$sign = ($number < 0.0);
$number = abs($number);
if ($splitOnPoint && strpos($mask, '.') !== false && strpos($number, '.') !== false) {
$numbers = explode('.', $number);
$masks = explode('.', $mask);
if (count($masks) > 2) {
$masks = self::mergeComplexNumberFormatMasks($numbers, $masks);
}
$result1 = self::complexNumberFormatMask($numbers[0], $masks[0], false);
$result2 = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1]), false));
return (($sign) ? '-' : '') . $result1 . '.' . $result2;
}
$result = self::processComplexNumberFormatMask($number, $mask);
return (($sign) ? '-' : '') . $result;
}
private static function formatStraightNumericValue($value, $format, array $matches, $useThousands, $number_regex)
{
$left = $matches[1];
$dec = $matches[2];
$right = $matches[3];
// minimun width of formatted number (including dot)
$minWidth = strlen($left) + strlen($dec) + strlen($right);
if ($useThousands) {
$value = number_format(
$value,
strlen($right),
StringHelper::getDecimalSeparator(),
StringHelper::getThousandsSeparator()
);
$value = preg_replace($number_regex, $value, $format);
} else {
if (preg_match('/[0#]E[+-]0/i', $format)) {
// Scientific format
$value = sprintf('%5.2E', $value);
} elseif (preg_match('/0([^\d\.]+)0/', $format) || substr_count($format, '.') > 1) {
if ($value == (int) $value && substr_count($format, '.') === 1) {
$value *= 10 ** strlen(explode('.', $format)[1]);
}
$value = self::complexNumberFormatMask($value, $format);
} else {
$sprintf_pattern = "%0$minWidth." . strlen($right) . 'f';
$value = sprintf($sprintf_pattern, $value);
$value = preg_replace($number_regex, $value, $format);
}
}
return $value;
}
private static function formatAsNumber($value, $format)
{
if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) {
return 'EUR ' . sprintf('%1.2f', $value);
}
// Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols
$format = str_replace(['"', '*'], '', $format);
// Find out if we need thousands separator
// This is indicated by a comma enclosed by a digit placeholder:
// #,# or 0,0
$useThousands = preg_match('/(#,#|0,0)/', $format);
if ($useThousands) {
$format = preg_replace('/0,0/', '00', $format);
$format = preg_replace('/#,#/', '##', $format);
}
// Scale thousands, millions,...
// This is indicated by a number of commas after a digit placeholder:
// #, or 0.0,,
$scale = 1; // same as no scale
$matches = [];
if (preg_match('/(#|0)(,+)/', $format, $matches)) {
$scale = pow(1000, strlen($matches[2]));
// strip the commas
$format = preg_replace('/0,+/', '0', $format);
$format = preg_replace('/#,+/', '#', $format);
}
if (preg_match('/#?.*\?\/\?/', $format, $m)) {
if ($value != (int) $value) {
self::formatAsFraction($value, $format);
}
} else {
// Handle the number itself
// scale number
$value = $value / $scale;
// Strip #
$format = preg_replace('/\\#/', '0', $format);
// Remove locale code [$-###]
$format = preg_replace('/\[\$\-.*\]/', '', $format);
$n = '/\\[[^\\]]+\\]/';
$m = preg_replace($n, '', $format);
$number_regex = '/(0+)(\\.?)(0*)/';
if (preg_match($number_regex, $m, $matches)) {
$value = self::formatStraightNumericValue($value, $format, $matches, $useThousands, $number_regex);
}
}
if (preg_match('/\[\$(.*)\]/u', $format, $m)) {
// Currency or Accounting
$currencyCode = $m[1];
[$currencyCode] = explode('-', $currencyCode);
if ($currencyCode == '') {
$currencyCode = StringHelper::getCurrencyCode();
}
$value = preg_replace('/\[\$([^\]]*)\]/u', $currencyCode, $value);
}
return $value;
}
/**
* Convert a value in a pre-defined format to a PHP string.
*
@@ -660,7 +789,9 @@ class NumberFormat extends Supervisor
// Save format with color information for later use below
$formatColor = $format;
// Strip colour information
$color_regex = '/\[(' . implode('|', Color::NAMED_COLORS) . ')\]/';
$format = preg_replace($color_regex, '', $format);
// Let's begin inspecting the format and converting the value to a formatted string
// Check for date/time characters (not inside quotes)
@@ -668,105 +799,19 @@ class NumberFormat extends Supervisor
// datetime format
self::formatAsDate($value, $format);
} else {
// Strip color information
$color_regex = '/^\\[[a-zA-Z]+\\]/';
$format = preg_replace($color_regex, '', $format);
if (preg_match('/%$/', $format)) {
if (substr($format, 0, 1) === '"' && substr($format, -1, 1) === '"') {
$value = substr($format, 1, -1);
} elseif (preg_match('/%$/', $format)) {
// % number format
self::formatAsPercentage($value, $format);
} else {
if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) {
$value = 'EUR ' . sprintf('%1.2f', $value);
} else {
// Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols
$format = str_replace(['"', '*'], '', $format);
// Find out if we need thousands separator
// This is indicated by a comma enclosed by a digit placeholder:
// #,# or 0,0
$useThousands = preg_match('/(#,#|0,0)/', $format);
if ($useThousands) {
$format = preg_replace('/0,0/', '00', $format);
$format = preg_replace('/#,#/', '##', $format);
}
// Scale thousands, millions,...
// This is indicated by a number of commas after a digit placeholder:
// #, or 0.0,,
$scale = 1; // same as no scale
$matches = [];
if (preg_match('/(#|0)(,+)/', $format, $matches)) {
$scale = pow(1000, strlen($matches[2]));
// strip the commas
$format = preg_replace('/0,+/', '0', $format);
$format = preg_replace('/#,+/', '#', $format);
}
if (preg_match('/#?.*\?\/\?/', $format, $m)) {
if ($value != (int) $value) {
self::formatAsFraction($value, $format);
}
} else {
// Handle the number itself
// scale number
$value = $value / $scale;
// Strip #
$format = preg_replace('/\\#/', '0', $format);
// Remove locale code [$-###]
$format = preg_replace('/\[\$\-.*\]/', '', $format);
$n = '/\\[[^\\]]+\\]/';
$m = preg_replace($n, '', $format);
$number_regex = '/(0+)(\\.?)(0*)/';
if (preg_match($number_regex, $m, $matches)) {
$left = $matches[1];
$dec = $matches[2];
$right = $matches[3];
// minimun width of formatted number (including dot)
$minWidth = strlen($left) + strlen($dec) + strlen($right);
if ($useThousands) {
$value = number_format(
$value,
strlen($right),
StringHelper::getDecimalSeparator(),
StringHelper::getThousandsSeparator()
);
$value = preg_replace($number_regex, $value, $format);
} else {
if (preg_match('/[0#]E[+-]0/i', $format)) {
// Scientific format
$value = sprintf('%5.2E', $value);
} elseif (preg_match('/0([^\d\.]+)0/', $format)) {
$value = self::complexNumberFormatMask($value, $format);
} else {
$sprintf_pattern = "%0$minWidth." . strlen($right) . 'f';
$value = sprintf($sprintf_pattern, $value);
$value = preg_replace($number_regex, $value, $format);
}
}
}
}
if (preg_match('/\[\$(.*)\]/u', $format, $m)) {
// Currency or Accounting
$currencyCode = $m[1];
list($currencyCode) = explode('-', $currencyCode);
if ($currencyCode == '') {
$currencyCode = StringHelper::getCurrencyCode();
}
$value = preg_replace('/\[\$([^\]]*)\]/u', $currencyCode, $value);
}
}
$value = self::formatAsNumber($value, $format);
}
}
// Additional formatting provided by callback function
if ($callBack !== null) {
list($writerInstance, $function) = $callBack;
[$writerInstance, $function] = $callBack;
$value = $writerInstance->$function($value, $formatColor);
}

View File

@@ -86,7 +86,7 @@ class Protection extends Supervisor
*
* @throws PhpSpreadsheetException
*
* @return Protection
* @return $this
*/
public function applyFromArray(array $pStyles)
{
@@ -123,7 +123,7 @@ class Protection extends Supervisor
*
* @param string $pValue see self::PROTECTION_*
*
* @return Protection
* @return $this
*/
public function setLocked($pValue)
{
@@ -156,7 +156,7 @@ class Protection extends Supervisor
*
* @param string $pValue see self::PROTECTION_*
*
* @return Protection
* @return $this
*/
public function setHidden($pValue)
{

View File

@@ -189,7 +189,7 @@ class Style extends Supervisor
* @param array $pStyles Array containing style information
* @param bool $pAdvanced advanced mode for setting borders
*
* @return Style
* @return $this
*/
public function applyFromArray(array $pStyles, $pAdvanced = true)
{
@@ -204,7 +204,7 @@ class Style extends Supervisor
$rangeA = $pRange;
$rangeB = $pRange;
} else {
list($rangeA, $rangeB) = explode(':', $pRange);
[$rangeA, $rangeB] = explode(':', $pRange);
}
// Calculate range outer borders
@@ -485,7 +485,7 @@ class Style extends Supervisor
*
* @param Font $font
*
* @return Style
* @return $this
*/
public function setFont(Font $font)
{
@@ -539,7 +539,7 @@ class Style extends Supervisor
*
* @param Conditional[] $pValue Array of conditional styles
*
* @return Style
* @return $this
*/
public function setConditionalStyles(array $pValue)
{
@@ -577,7 +577,7 @@ class Style extends Supervisor
*
* @param bool $pValue
*
* @return Style
* @return $this
*/
public function setQuotePrefix($pValue)
{

View File

@@ -48,7 +48,7 @@ abstract class Supervisor implements IComparable
* @param Spreadsheet|Style $parent
* @param null|string $parentPropertyName
*
* @return Supervisor
* @return $this
*/
public function bindParent($parent, $parentPropertyName = null)
{

View File

@@ -59,7 +59,7 @@ class AutoFilter
*
* @param Worksheet $pSheet
*
* @return AutoFilter
* @return $this
*/
public function setParent(Worksheet $pSheet = null)
{
@@ -85,12 +85,12 @@ class AutoFilter
*
* @throws PhpSpreadsheetException
*
* @return AutoFilter
* @return $this
*/
public function setRange($pRange)
{
// extract coordinate
list($worksheet, $pRange) = Worksheet::extractSheetTitle($pRange, true);
[$worksheet, $pRange] = Worksheet::extractSheetTitle($pRange, true);
if (strpos($pRange, ':') !== false) {
$this->range = $pRange;
@@ -105,7 +105,7 @@ class AutoFilter
$this->columns = [];
} else {
// Discard any column rules that are no longer valid within this range
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
foreach ($this->columns as $key => $value) {
$colIndex = Coordinate::columnIndexFromString($key);
if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) {
@@ -143,7 +143,7 @@ class AutoFilter
}
$columnIndex = Coordinate::columnIndexFromString($column);
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
if (($rangeStart[0] > $columnIndex) || ($rangeEnd[0] < $columnIndex)) {
throw new PhpSpreadsheetException('Column is outside of current autofilter range.');
}
@@ -196,7 +196,7 @@ class AutoFilter
*/
public function getColumnByOffset($pColumnOffset)
{
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
$pColumn = Coordinate::stringFromColumnIndex($rangeStart[0] + $pColumnOffset);
return $this->getColumn($pColumn);
@@ -210,7 +210,7 @@ class AutoFilter
*
* @throws PhpSpreadsheetException
*
* @return AutoFilter
* @return $this
*/
public function setColumn($pColumn)
{
@@ -241,7 +241,7 @@ class AutoFilter
*
* @throws PhpSpreadsheetException
*
* @return AutoFilter
* @return $this
*/
public function clearColumn($pColumn)
{
@@ -264,7 +264,7 @@ class AutoFilter
* @param string $fromColumn Column name (e.g. A)
* @param string $toColumn Column name (e.g. B)
*
* @return AutoFilter
* @return $this
*/
public function shiftColumn($fromColumn, $toColumn)
{
@@ -357,7 +357,7 @@ class AutoFilter
{
$dataSet = $ruleSet['filterRules'];
$join = $ruleSet['join'];
$customRuleForBlanks = isset($ruleSet['customRuleForBlanks']) ? $ruleSet['customRuleForBlanks'] : false;
$customRuleForBlanks = $ruleSet['customRuleForBlanks'] ?? false;
if (!$customRuleForBlanks) {
// Blank cells are always ignored, so return a FALSE
@@ -617,11 +617,11 @@ class AutoFilter
*
* @throws PhpSpreadsheetException
*
* @return AutoFilter
* @return $this
*/
public function showHideRows()
{
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
// The heading row should always be visible
$this->workSheet->getRowDimension($rangeStart[1])->setVisible(true);

View File

@@ -101,7 +101,7 @@ class Column
}
/**
* Get AutoFilter Column Index.
* Get AutoFilter column index as string eg: 'A'.
*
* @return string
*/
@@ -111,13 +111,13 @@ class Column
}
/**
* Set AutoFilter Column Index.
* Set AutoFilter column index as string eg: 'A'.
*
* @param string $pColumn Column (e.g. A)
*
* @throws PhpSpreadsheetException
*
* @return Column
* @return $this
*/
public function setColumnIndex($pColumn)
{
@@ -147,7 +147,7 @@ class Column
*
* @param AutoFilter $pParent
*
* @return Column
* @return $this
*/
public function setParent(AutoFilter $pParent = null)
{
@@ -173,7 +173,7 @@ class Column
*
* @throws PhpSpreadsheetException
*
* @return Column
* @return $this
*/
public function setFilterType($pFilterType)
{
@@ -203,7 +203,7 @@ class Column
*
* @throws PhpSpreadsheetException
*
* @return Column
* @return $this
*/
public function setJoin($pJoin)
{
@@ -223,7 +223,7 @@ class Column
*
* @param string[] $attributes
*
* @return Column
* @return $this
*/
public function setAttributes(array $attributes)
{
@@ -238,7 +238,7 @@ class Column
* @param string $pName Attribute Name
* @param string $pValue Attribute Value
*
* @return Column
* @return $this
*/
public function setAttribute($pName, $pValue)
{
@@ -316,7 +316,7 @@ class Column
*
* @param Column\Rule $pRule
*
* @return Column
* @return $this
*/
public function addRule(Column\Rule $pRule)
{
@@ -332,7 +332,7 @@ class Column
*
* @param int $pIndex Rule index in the ruleset array
*
* @return Column
* @return $this
*/
public function deleteRule($pIndex)
{
@@ -350,7 +350,7 @@ class Column
/**
* Delete all AutoFilter Column Rules.
*
* @return Column
* @return $this
*/
public function clearRules()
{

View File

@@ -262,7 +262,7 @@ class Rule
*
* @throws PhpSpreadsheetException
*
* @return Rule
* @return $this
*/
public function setRuleType($pRuleType)
{
@@ -292,7 +292,7 @@ class Rule
*
* @throws PhpSpreadsheetException
*
* @return Rule
* @return $this
*/
public function setValue($pValue)
{
@@ -336,7 +336,7 @@ class Rule
*
* @throws PhpSpreadsheetException
*
* @return Rule
* @return $this
*/
public function setOperator($pOperator)
{
@@ -369,7 +369,7 @@ class Rule
*
* @throws PhpSpreadsheetException
*
* @return Rule
* @return $this
*/
public function setGrouping($pGrouping)
{
@@ -393,7 +393,7 @@ class Rule
*
* @throws PhpSpreadsheetException
*
* @return Rule
* @return $this
*/
public function setRule($pOperator, $pValue, $pGrouping = null)
{
@@ -424,7 +424,7 @@ class Rule
*
* @param Column $pParent
*
* @return Rule
* @return $this
*/
public function setParent(Column $pParent = null)
{

View File

@@ -154,7 +154,7 @@ class BaseDrawing implements IComparable
*
* @param string $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setName($pValue)
{
@@ -178,7 +178,7 @@ class BaseDrawing implements IComparable
*
* @param string $description
*
* @return BaseDrawing
* @return $this
*/
public function setDescription($description)
{
@@ -205,7 +205,7 @@ class BaseDrawing implements IComparable
*
* @throws PhpSpreadsheetException
*
* @return BaseDrawing
* @return $this
*/
public function setWorksheet(Worksheet $pValue = null, $pOverrideOld = false)
{
@@ -253,7 +253,7 @@ class BaseDrawing implements IComparable
*
* @param string $pValue eg: 'A1'
*
* @return BaseDrawing
* @return $this
*/
public function setCoordinates($pValue)
{
@@ -277,7 +277,7 @@ class BaseDrawing implements IComparable
*
* @param int $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setOffsetX($pValue)
{
@@ -301,7 +301,7 @@ class BaseDrawing implements IComparable
*
* @param int $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setOffsetY($pValue)
{
@@ -325,7 +325,7 @@ class BaseDrawing implements IComparable
*
* @param int $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setWidth($pValue)
{
@@ -356,7 +356,7 @@ class BaseDrawing implements IComparable
*
* @param int $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setHeight($pValue)
{
@@ -386,7 +386,7 @@ class BaseDrawing implements IComparable
* @param int $width
* @param int $height
*
* @return BaseDrawing
* @return $this
*/
public function setWidthAndHeight($width, $height)
{
@@ -423,7 +423,7 @@ class BaseDrawing implements IComparable
*
* @param bool $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setResizeProportional($pValue)
{
@@ -447,7 +447,7 @@ class BaseDrawing implements IComparable
*
* @param int $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setRotation($pValue)
{
@@ -471,7 +471,7 @@ class BaseDrawing implements IComparable
*
* @param Drawing\Shadow $pValue
*
* @return BaseDrawing
* @return $this
*/
public function setShadow(Drawing\Shadow $pValue = null)
{

View File

@@ -40,7 +40,7 @@ class Column
}
/**
* Get column index.
* Get column index as string eg: 'A'.
*
* @return string
*/

View File

@@ -59,7 +59,7 @@ class ColumnCellIterator extends CellIterator
*
* @throws PhpSpreadsheetException
*
* @return ColumnCellIterator
* @return $this
*/
public function resetStart($startRow = 1)
{
@@ -77,7 +77,7 @@ class ColumnCellIterator extends CellIterator
*
* @throws PhpSpreadsheetException
*
* @return ColumnCellIterator
* @return $this
*/
public function resetEnd($endRow = null)
{
@@ -94,7 +94,7 @@ class ColumnCellIterator extends CellIterator
*
* @throws PhpSpreadsheetException
*
* @return ColumnCellIterator
* @return $this
*/
public function seek($row = 1)
{

View File

@@ -42,7 +42,7 @@ class ColumnDimension extends Dimension
}
/**
* Get ColumnIndex.
* Get column index as string eg: 'A'.
*
* @return string
*/
@@ -52,11 +52,11 @@ class ColumnDimension extends Dimension
}
/**
* Set ColumnIndex.
* Set column index as string eg: 'A'.
*
* @param string $pValue
*
* @return ColumnDimension
* @return $this
*/
public function setColumnIndex($pValue)
{
@@ -80,7 +80,7 @@ class ColumnDimension extends Dimension
*
* @param float $pValue
*
* @return ColumnDimension
* @return $this
*/
public function setWidth($pValue)
{
@@ -104,7 +104,7 @@ class ColumnDimension extends Dimension
*
* @param bool $pValue
*
* @return ColumnDimension
* @return $this
*/
public function setAutoSize($pValue)
{

View File

@@ -66,7 +66,7 @@ class ColumnIterator implements \Iterator
*
* @throws Exception
*
* @return ColumnIterator
* @return $this
*/
public function resetStart($startColumn = 'A')
{
@@ -89,7 +89,7 @@ class ColumnIterator implements \Iterator
*
* @param string $endColumn The column address at which to stop iterating
*
* @return ColumnIterator
* @return $this
*/
public function resetEnd($endColumn = null)
{
@@ -106,7 +106,7 @@ class ColumnIterator implements \Iterator
*
* @throws PhpSpreadsheetException
*
* @return ColumnIterator
* @return $this
*/
public function seek($column = 'A')
{

View File

@@ -60,7 +60,7 @@ abstract class Dimension
*
* @param bool $pValue
*
* @return Dimension
* @return $this
*/
public function setVisible($pValue)
{
@@ -87,7 +87,7 @@ abstract class Dimension
*
* @throws PhpSpreadsheetException
*
* @return Dimension
* @return $this
*/
public function setOutlineLevel($pValue)
{
@@ -115,7 +115,7 @@ abstract class Dimension
*
* @param bool $pValue
*
* @return Dimension
* @return $this
*/
public function setCollapsed($pValue)
{
@@ -139,7 +139,7 @@ abstract class Dimension
*
* @param int $pValue
*
* @return Dimension
* @return $this
*/
public function setXfIndex($pValue)
{

View File

@@ -78,7 +78,7 @@ class Drawing extends BaseDrawing
*
* @throws PhpSpreadsheetException
*
* @return Drawing
* @return $this
*/
public function setPath($pValue, $pVerifyFile = true)
{
@@ -88,7 +88,7 @@ class Drawing extends BaseDrawing
if ($this->width == 0 && $this->height == 0) {
// Get width/height
list($this->width, $this->height) = getimagesize($pValue);
[$this->width, $this->height] = getimagesize($pValue);
}
} else {
throw new PhpSpreadsheetException("File $pValue not found!");

View File

@@ -100,7 +100,7 @@ class Shadow implements IComparable
*
* @param bool $pValue
*
* @return Shadow
* @return $this
*/
public function setVisible($pValue)
{
@@ -124,7 +124,7 @@ class Shadow implements IComparable
*
* @param int $pValue
*
* @return Shadow
* @return $this
*/
public function setBlurRadius($pValue)
{
@@ -148,7 +148,7 @@ class Shadow implements IComparable
*
* @param int $pValue
*
* @return Shadow
* @return $this
*/
public function setDistance($pValue)
{
@@ -172,7 +172,7 @@ class Shadow implements IComparable
*
* @param int $pValue
*
* @return Shadow
* @return $this
*/
public function setDirection($pValue)
{
@@ -196,7 +196,7 @@ class Shadow implements IComparable
*
* @param int $pValue
*
* @return Shadow
* @return $this
*/
public function setAlignment($pValue)
{
@@ -220,7 +220,7 @@ class Shadow implements IComparable
*
* @param Color $pValue
*
* @return Shadow
* @return $this
*/
public function setColor(Color $pValue = null)
{
@@ -244,7 +244,7 @@ class Shadow implements IComparable
*
* @param int $pValue
*
* @return Shadow
* @return $this
*/
public function setAlpha($pValue)
{

View File

@@ -172,7 +172,7 @@ class HeaderFooter
*
* @param string $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setOddHeader($pValue)
{
@@ -196,7 +196,7 @@ class HeaderFooter
*
* @param string $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setOddFooter($pValue)
{
@@ -220,7 +220,7 @@ class HeaderFooter
*
* @param string $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setEvenHeader($pValue)
{
@@ -244,7 +244,7 @@ class HeaderFooter
*
* @param string $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setEvenFooter($pValue)
{
@@ -268,7 +268,7 @@ class HeaderFooter
*
* @param string $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setFirstHeader($pValue)
{
@@ -292,7 +292,7 @@ class HeaderFooter
*
* @param string $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setFirstFooter($pValue)
{
@@ -316,7 +316,7 @@ class HeaderFooter
*
* @param bool $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setDifferentOddEven($pValue)
{
@@ -340,7 +340,7 @@ class HeaderFooter
*
* @param bool $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setDifferentFirst($pValue)
{
@@ -364,7 +364,7 @@ class HeaderFooter
*
* @param bool $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setScaleWithDocument($pValue)
{
@@ -388,7 +388,7 @@ class HeaderFooter
*
* @param bool $pValue
*
* @return HeaderFooter
* @return $this
*/
public function setAlignWithMargins($pValue)
{
@@ -403,7 +403,7 @@ class HeaderFooter
* @param HeaderFooterDrawing $image
* @param string $location
*
* @return HeaderFooter
* @return $this
*/
public function addImage(HeaderFooterDrawing $image, $location = self::IMAGE_HEADER_LEFT)
{
@@ -417,7 +417,7 @@ class HeaderFooter
*
* @param string $location
*
* @return HeaderFooter
* @return $this
*/
public function removeImage($location = self::IMAGE_HEADER_LEFT)
{
@@ -433,7 +433,7 @@ class HeaderFooter
*
* @param HeaderFooterDrawing[] $images
*
* @return HeaderFooter
* @return $this
*/
public function setImages(array $images)
{

View File

@@ -74,7 +74,7 @@ class MemoryDrawing extends BaseDrawing
*
* @param resource $value
*
* @return MemoryDrawing
* @return $this
*/
public function setImageResource($value)
{
@@ -104,7 +104,7 @@ class MemoryDrawing extends BaseDrawing
*
* @param string $value see self::RENDERING_*
*
* @return MemoryDrawing
* @return $this
*/
public function setRenderingFunction($value)
{
@@ -128,7 +128,7 @@ class MemoryDrawing extends BaseDrawing
*
* @param string $value see self::MIMETYPE_*
*
* @return MemoryDrawing
* @return $this
*/
public function setMimeType($value)
{

View File

@@ -68,7 +68,7 @@ class PageMargins
*
* @param float $pValue
*
* @return PageMargins
* @return $this
*/
public function setLeft($pValue)
{
@@ -92,7 +92,7 @@ class PageMargins
*
* @param float $pValue
*
* @return PageMargins
* @return $this
*/
public function setRight($pValue)
{
@@ -116,7 +116,7 @@ class PageMargins
*
* @param float $pValue
*
* @return PageMargins
* @return $this
*/
public function setTop($pValue)
{
@@ -140,7 +140,7 @@ class PageMargins
*
* @param float $pValue
*
* @return PageMargins
* @return $this
*/
public function setBottom($pValue)
{
@@ -164,7 +164,7 @@ class PageMargins
*
* @param float $pValue
*
* @return PageMargins
* @return $this
*/
public function setHeader($pValue)
{
@@ -188,7 +188,7 @@ class PageMargins
*
* @param float $pValue
*
* @return PageMargins
* @return $this
*/
public function setFooter($pValue)
{

View File

@@ -180,7 +180,7 @@ class PageSetup
* Print scaling. Valid values range from 10 to 400
* This setting is overridden when fitToWidth and/or fitToHeight are in use
*
* @var int?
* @var null|int
*/
private $scale = 100;
@@ -196,7 +196,7 @@ class PageSetup
* Fit To Height
* Number of vertical pages to fit on.
*
* @var int?
* @var null|int
*/
private $fitToHeight = 1;
@@ -204,7 +204,7 @@ class PageSetup
* Fit To Width
* Number of horizontal pages to fit on.
*
* @var int?
* @var null|int
*/
private $fitToWidth = 1;
@@ -272,7 +272,7 @@ class PageSetup
*
* @param int $pValue see self::PAPERSIZE_*
*
* @return PageSetup
* @return $this
*/
public function setPaperSize($pValue)
{
@@ -296,7 +296,7 @@ class PageSetup
*
* @param string $pValue see self::ORIENTATION_*
*
* @return PageSetup
* @return $this
*/
public function setOrientation($pValue)
{
@@ -308,7 +308,7 @@ class PageSetup
/**
* Get Scale.
*
* @return int?
* @return null|int
*/
public function getScale()
{
@@ -325,7 +325,7 @@ class PageSetup
*
* @throws PhpSpreadsheetException
*
* @return PageSetup
* @return $this
*/
public function setScale($pValue, $pUpdate = true)
{
@@ -358,7 +358,7 @@ class PageSetup
*
* @param bool $pValue
*
* @return PageSetup
* @return $this
*/
public function setFitToPage($pValue)
{
@@ -370,7 +370,7 @@ class PageSetup
/**
* Get Fit To Height.
*
* @return int?
* @return null|int
*/
public function getFitToHeight()
{
@@ -383,7 +383,7 @@ class PageSetup
* @param null|int $pValue
* @param bool $pUpdate Update fitToPage so it applies rather than scaling
*
* @return PageSetup
* @return $this
*/
public function setFitToHeight($pValue, $pUpdate = true)
{
@@ -398,7 +398,7 @@ class PageSetup
/**
* Get Fit To Width.
*
* @return int?
* @return null|int
*/
public function getFitToWidth()
{
@@ -411,7 +411,7 @@ class PageSetup
* @param null|int $pValue
* @param bool $pUpdate Update fitToPage so it applies rather than scaling
*
* @return PageSetup
* @return $this
*/
public function setFitToWidth($pValue, $pUpdate = true)
{
@@ -454,7 +454,7 @@ class PageSetup
*
* @param array $pValue Containing start column and end column, empty array if option unset
*
* @return PageSetup
* @return $this
*/
public function setColumnsToRepeatAtLeft(array $pValue)
{
@@ -469,7 +469,7 @@ class PageSetup
* @param string $pStart eg: 'A'
* @param string $pEnd eg: 'B'
*
* @return PageSetup
* @return $this
*/
public function setColumnsToRepeatAtLeftByStartAndEnd($pStart, $pEnd)
{
@@ -509,7 +509,7 @@ class PageSetup
*
* @param array $pValue Containing start column and end column, empty array if option unset
*
* @return PageSetup
* @return $this
*/
public function setRowsToRepeatAtTop(array $pValue)
{
@@ -524,7 +524,7 @@ class PageSetup
* @param int $pStart eg: 1
* @param int $pEnd eg: 1
*
* @return PageSetup
* @return $this
*/
public function setRowsToRepeatAtTopByStartAndEnd($pStart, $pEnd)
{
@@ -548,7 +548,7 @@ class PageSetup
*
* @param bool $value
*
* @return PageSetup
* @return $this
*/
public function setHorizontalCentered($value)
{
@@ -572,7 +572,7 @@ class PageSetup
*
* @param bool $value
*
* @return PageSetup
* @return $this
*/
public function setVerticalCentered($value)
{
@@ -634,7 +634,7 @@ class PageSetup
* Otherwise, the range identified by the value of $index will be removed from the series
* Print areas are numbered from 1
*
* @return PageSetup
* @return $this
*/
public function clearPrintArea($index = 0)
{
@@ -671,7 +671,7 @@ class PageSetup
*
* @throws PhpSpreadsheetException
*
* @return PageSetup
* @return $this
*/
public function setPrintArea($value, $index = 0, $method = self::SETPRINTRANGE_OVERWRITE)
{
@@ -732,7 +732,7 @@ class PageSetup
*
* @throws PhpSpreadsheetException
*
* @return PageSetup
* @return $this
*/
public function addPrintArea($value, $index = -1)
{
@@ -762,7 +762,7 @@ class PageSetup
*
* @throws PhpSpreadsheetException
*
* @return PageSetup
* @return $this
*/
public function setPrintAreaByColumnAndRow($column1, $row1, $column2, $row2, $index = 0, $method = self::SETPRINTRANGE_OVERWRITE)
{
@@ -789,7 +789,7 @@ class PageSetup
*
* @throws PhpSpreadsheetException
*
* @return PageSetup
* @return $this
*/
public function addPrintAreaByColumnAndRow($column1, $row1, $column2, $row2, $index = -1)
{
@@ -815,7 +815,7 @@ class PageSetup
*
* @param int $value
*
* @return PageSetup
* @return $this
*/
public function setFirstPageNumber($value)
{
@@ -827,7 +827,7 @@ class PageSetup
/**
* Reset first page number.
*
* @return PageSetup
* @return $this
*/
public function resetFirstPageNumber()
{

View File

@@ -172,7 +172,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setSheet($pValue)
{
@@ -196,7 +196,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setObjects($pValue)
{
@@ -220,7 +220,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setScenarios($pValue)
{
@@ -244,7 +244,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setFormatCells($pValue)
{
@@ -268,7 +268,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setFormatColumns($pValue)
{
@@ -292,7 +292,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setFormatRows($pValue)
{
@@ -316,7 +316,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setInsertColumns($pValue)
{
@@ -340,7 +340,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setInsertRows($pValue)
{
@@ -364,7 +364,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setInsertHyperlinks($pValue)
{
@@ -388,7 +388,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setDeleteColumns($pValue)
{
@@ -412,7 +412,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setDeleteRows($pValue)
{
@@ -436,7 +436,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setSelectLockedCells($pValue)
{
@@ -460,7 +460,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setSort($pValue)
{
@@ -484,7 +484,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setAutoFilter($pValue)
{
@@ -508,7 +508,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setPivotTables($pValue)
{
@@ -532,7 +532,7 @@ class Protection
*
* @param bool $pValue
*
* @return Protection
* @return $this
*/
public function setSelectUnlockedCells($pValue)
{
@@ -557,7 +557,7 @@ class Protection
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return Protection
* @return $this
*/
public function setPassword($pValue, $pAlreadyHashed = false)
{

View File

@@ -59,7 +59,7 @@ class RowCellIterator extends CellIterator
*
* @throws PhpSpreadsheetException
*
* @return RowCellIterator
* @return $this
*/
public function resetStart($startColumn = 'A')
{
@@ -77,7 +77,7 @@ class RowCellIterator extends CellIterator
*
* @throws PhpSpreadsheetException
*
* @return RowCellIterator
* @return $this
*/
public function resetEnd($endColumn = null)
{
@@ -95,7 +95,7 @@ class RowCellIterator extends CellIterator
*
* @throws PhpSpreadsheetException
*
* @return RowCellIterator
* @return $this
*/
public function seek($column = 'A')
{

View File

@@ -56,7 +56,7 @@ class RowDimension extends Dimension
*
* @param int $pValue
*
* @return RowDimension
* @return $this
*/
public function setRowIndex($pValue)
{
@@ -80,7 +80,7 @@ class RowDimension extends Dimension
*
* @param float $pValue
*
* @return RowDimension
* @return $this
*/
public function setRowHeight($pValue)
{
@@ -104,7 +104,7 @@ class RowDimension extends Dimension
*
* @param bool $pValue
*
* @return RowDimension
* @return $this
*/
public function setZeroHeight($pValue)
{

View File

@@ -64,7 +64,7 @@ class RowIterator implements \Iterator
*
* @throws PhpSpreadsheetException
*
* @return RowIterator
* @return $this
*/
public function resetStart($startRow = 1)
{
@@ -86,7 +86,7 @@ class RowIterator implements \Iterator
*
* @param int $endRow The row number at which to stop iterating
*
* @return RowIterator
* @return $this
*/
public function resetEnd($endRow = null)
{
@@ -102,7 +102,7 @@ class RowIterator implements \Iterator
*
* @throws PhpSpreadsheetException
*
* @return RowIterator
* @return $this
*/
public function seek($row = 1)
{

View File

@@ -35,6 +35,16 @@ class SheetView
*/
private $zoomScaleNormal = 100;
/**
* ShowZeros.
*
* If true, "null" values from a calculation will be shown as "0". This is the default Excel behaviour and can be changed
* with the advanced worksheet option "Show a zero in cells that have zero value"
*
* @var bool
*/
private $showZeros = true;
/**
* View.
*
@@ -69,7 +79,7 @@ class SheetView
*
* @throws PhpSpreadsheetException
*
* @return SheetView
* @return $this
*/
public function setZoomScale($pValue)
{
@@ -102,7 +112,7 @@ class SheetView
*
* @throws PhpSpreadsheetException
*
* @return SheetView
* @return $this
*/
public function setZoomScaleNormal($pValue)
{
@@ -115,6 +125,24 @@ class SheetView
return $this;
}
/**
* Set ShowZeroes setting.
*
* @param bool $pValue
*/
public function setShowZeros($pValue)
{
$this->showZeros = $pValue;
}
/**
* @return bool
*/
public function getShowZeros()
{
return $this->showZeros;
}
/**
* Get View.
*
@@ -137,7 +165,7 @@ class SheetView
*
* @throws PhpSpreadsheetException
*
* @return SheetView
* @return $this
*/
public function setView($pValue)
{

View File

@@ -647,7 +647,7 @@ class Worksheet implements IComparable
/**
* Refresh column dimensions.
*
* @return Worksheet
* @return $this
*/
public function refreshColumnDimensions()
{
@@ -666,7 +666,7 @@ class Worksheet implements IComparable
/**
* Refresh row dimensions.
*
* @return Worksheet
* @return $this
*/
public function refreshRowDimensions()
{
@@ -690,7 +690,7 @@ class Worksheet implements IComparable
public function calculateWorksheetDimension()
{
// Return
return 'A1' . ':' . $this->getHighestColumn() . $this->getHighestRow();
return 'A1:' . $this->getHighestColumn() . $this->getHighestRow();
}
/**
@@ -701,13 +701,13 @@ class Worksheet implements IComparable
public function calculateWorksheetDataDimension()
{
// Return
return 'A1' . ':' . $this->getHighestDataColumn() . $this->getHighestDataRow();
return 'A1:' . $this->getHighestDataColumn() . $this->getHighestDataRow();
}
/**
* Calculate widths for auto-size columns.
*
* @return Worksheet;
* @return $this
*/
public function calculateColumnWidths()
{
@@ -797,7 +797,7 @@ class Worksheet implements IComparable
*
* @param Spreadsheet $parent
*
* @return Worksheet
* @return $this
*/
public function rebindParent(Spreadsheet $parent)
{
@@ -838,7 +838,7 @@ class Worksheet implements IComparable
* @param bool $validate False to skip validation of new title. WARNING: This should only be set
* at parse time (by Readers), where titles can be assumed to be valid.
*
* @return Worksheet
* @return $this
*/
public function setTitle($pValue, $updateFormulaCellReferences = true, $validate = true)
{
@@ -913,7 +913,7 @@ class Worksheet implements IComparable
*
* @param string $value Sheet state (visible, hidden, veryHidden)
*
* @return Worksheet
* @return $this
*/
public function setSheetState($value)
{
@@ -937,7 +937,7 @@ class Worksheet implements IComparable
*
* @param PageSetup $pValue
*
* @return Worksheet
* @return $this
*/
public function setPageSetup(PageSetup $pValue)
{
@@ -961,7 +961,7 @@ class Worksheet implements IComparable
*
* @param PageMargins $pValue
*
* @return Worksheet
* @return $this
*/
public function setPageMargins(PageMargins $pValue)
{
@@ -985,7 +985,7 @@ class Worksheet implements IComparable
*
* @param HeaderFooter $pValue
*
* @return Worksheet
* @return $this
*/
public function setHeaderFooter(HeaderFooter $pValue)
{
@@ -1009,7 +1009,7 @@ class Worksheet implements IComparable
*
* @param SheetView $pValue
*
* @return Worksheet
* @return $this
*/
public function setSheetView(SheetView $pValue)
{
@@ -1033,7 +1033,7 @@ class Worksheet implements IComparable
*
* @param Protection $pValue
*
* @return Worksheet
* @return $this
*/
public function setProtection(Protection $pValue)
{
@@ -1119,7 +1119,7 @@ class Worksheet implements IComparable
* @param string $pCoordinate Coordinate of the cell, eg: 'A1'
* @param mixed $pValue Value of the cell
*
* @return Worksheet
* @return $this
*/
public function setCellValue($pCoordinate, $pValue)
{
@@ -1135,7 +1135,7 @@ class Worksheet implements IComparable
* @param int $row Numeric row coordinate of the cell
* @param mixed $value Value of the cell
*
* @return Worksheet
* @return $this
*/
public function setCellValueByColumnAndRow($columnIndex, $row, $value)
{
@@ -1151,7 +1151,7 @@ class Worksheet implements IComparable
* @param mixed $pValue Value of the cell
* @param string $pDataType Explicit data type, see DataType::TYPE_*
*
* @return Worksheet
* @return $this
*/
public function setCellValueExplicit($pCoordinate, $pValue, $pDataType)
{
@@ -1169,7 +1169,7 @@ class Worksheet implements IComparable
* @param mixed $value Value of the cell
* @param string $dataType Explicit data type, see DataType::TYPE_*
*
* @return Worksheet
* @return $this
*/
public function setCellValueExplicitByColumnAndRow($columnIndex, $row, $value, $dataType)
{
@@ -1441,7 +1441,7 @@ class Worksheet implements IComparable
$this->parent->setActiveSheetIndex($this->parent->getIndex($this));
// set cell coordinate as active
$this->setSelectedCells(strtoupper($pCellCoordinate));
$this->setSelectedCells($pCellCoordinate);
return $this->parent->getCellXfSupervisor();
}
@@ -1480,7 +1480,7 @@ class Worksheet implements IComparable
*
* @param string $pCoordinate eg: 'A1'
*
* @return Worksheet
* @return $this
*/
public function removeConditionalStyles($pCoordinate)
{
@@ -1505,7 +1505,7 @@ class Worksheet implements IComparable
* @param string $pCoordinate eg: 'A1'
* @param $pValue Conditional[]
*
* @return Worksheet
* @return $this
*/
public function setConditionalStyles($pCoordinate, $pValue)
{
@@ -1545,7 +1545,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function duplicateStyle(Style $pCellStyle, $pRange)
{
@@ -1561,7 +1561,7 @@ class Worksheet implements IComparable
}
// Calculate range outer borders
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($pRange . ':' . $pRange);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($pRange . ':' . $pRange);
// Make sure we can loop upwards on rows and columns
if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) {
@@ -1590,7 +1590,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function duplicateConditionalStyle(array $pCellStyle, $pRange = '')
{
@@ -1601,7 +1601,7 @@ class Worksheet implements IComparable
}
// Calculate range outer borders
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($pRange . ':' . $pRange);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($pRange . ':' . $pRange);
// Make sure we can loop upwards on rows and columns
if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) {
@@ -1628,7 +1628,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function setBreak($pCoordinate, $pBreak)
{
@@ -1657,7 +1657,7 @@ class Worksheet implements IComparable
* @param int $row Numeric row coordinate of the cell
* @param int $break Break type (type of Worksheet::BREAK_*)
*
* @return Worksheet
* @return $this
*/
public function setBreakByColumnAndRow($columnIndex, $row, $break)
{
@@ -1681,7 +1681,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function mergeCells($pRange)
{
@@ -1726,7 +1726,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function mergeCellsByColumnAndRow($columnIndex1, $row1, $columnIndex2, $row2)
{
@@ -1742,7 +1742,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function unmergeCells($pRange)
{
@@ -1772,7 +1772,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function unmergeCellsByColumnAndRow($columnIndex1, $row1, $columnIndex2, $row2)
{
@@ -1797,7 +1797,7 @@ class Worksheet implements IComparable
*
* @param array $pValue
*
* @return Worksheet
* @return $this
*/
public function setMergeCells(array $pValue)
{
@@ -1813,7 +1813,7 @@ class Worksheet implements IComparable
* @param string $pPassword Password to unlock the protection
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return Worksheet
* @return $this
*/
public function protectCells($pRange, $pPassword, $pAlreadyHashed = false)
{
@@ -1838,7 +1838,7 @@ class Worksheet implements IComparable
* @param string $password Password to unlock the protection
* @param bool $alreadyHashed If the password has already been hashed, set this to true
*
* @return Worksheet
* @return $this
*/
public function protectCellsByColumnAndRow($columnIndex1, $row1, $columnIndex2, $row2, $password, $alreadyHashed = false)
{
@@ -1854,7 +1854,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function unprotectCells($pRange)
{
@@ -1880,7 +1880,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function unprotectCellsByColumnAndRow($columnIndex1, $row1, $columnIndex2, $row2)
{
@@ -1917,7 +1917,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function setAutoFilter($pValue)
{
@@ -1940,7 +1940,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function setAutoFilterByColumnAndRow($columnIndex1, $row1, $columnIndex2, $row2)
{
@@ -1954,7 +1954,7 @@ class Worksheet implements IComparable
/**
* Remove autofilter.
*
* @return Worksheet
* @return $this
*/
public function removeAutoFilter()
{
@@ -1987,7 +1987,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function freezePane($cell, $topLeftCell = null)
{
@@ -2012,7 +2012,7 @@ class Worksheet implements IComparable
* @param int $columnIndex Numeric column coordinate of the cell
* @param int $row Numeric row coordinate of the cell
*
* @return Worksheet
* @return $this
*/
public function freezePaneByColumnAndRow($columnIndex, $row)
{
@@ -2022,7 +2022,7 @@ class Worksheet implements IComparable
/**
* Unfreeze Pane.
*
* @return Worksheet
* @return $this
*/
public function unfreezePane()
{
@@ -2047,7 +2047,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function insertNewRowBefore($pBefore, $pNumRows = 1)
{
@@ -2069,7 +2069,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function insertNewColumnBefore($pBefore, $pNumCols = 1)
{
@@ -2091,7 +2091,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function insertNewColumnBeforeByIndex($beforeColumnIndex, $pNumCols = 1)
{
@@ -2110,22 +2110,31 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function removeRow($pRow, $pNumRows = 1)
{
if ($pRow >= 1) {
$highestRow = $this->getHighestDataRow();
$objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this);
for ($r = 0; $r < $pNumRows; ++$r) {
$this->getCellCollection()->removeRow($highestRow);
--$highestRow;
}
} else {
if ($pRow < 1) {
throw new Exception('Rows to be deleted should at least start from row 1.');
}
$highestRow = $this->getHighestDataRow();
$removedRowsCounter = 0;
for ($r = 0; $r < $pNumRows; ++$r) {
if ($pRow + $r <= $highestRow) {
$this->getCellCollection()->removeRow($pRow + $r);
++$removedRowsCounter;
}
}
$objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this);
for ($r = 0; $r < $removedRowsCounter; ++$r) {
$this->getCellCollection()->removeRow($highestRow);
--$highestRow;
}
return $this;
}
@@ -2137,23 +2146,35 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function removeColumn($pColumn, $pNumCols = 1)
{
if (!is_numeric($pColumn)) {
$highestColumn = $this->getHighestDataColumn();
$pColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($pColumn) + $pNumCols);
$objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this);
for ($c = 0; $c < $pNumCols; ++$c) {
$this->getCellCollection()->removeColumn($highestColumn);
$highestColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($highestColumn) - 1);
}
} else {
if (is_numeric($pColumn)) {
throw new Exception('Column references should not be numeric.');
}
$highestColumn = $this->getHighestDataColumn();
$highestColumnIndex = Coordinate::columnIndexFromString($highestColumn);
$pColumnIndex = Coordinate::columnIndexFromString($pColumn);
if ($pColumnIndex > $highestColumnIndex) {
return $this;
}
$pColumn = Coordinate::stringFromColumnIndex($pColumnIndex + $pNumCols);
$objReferenceHelper = ReferenceHelper::getInstance();
$objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this);
$maxPossibleColumnsToBeRemoved = $highestColumnIndex - $pColumnIndex + 1;
for ($c = 0, $n = min($maxPossibleColumnsToBeRemoved, $pNumCols); $c < $n; ++$c) {
$this->getCellCollection()->removeColumn($highestColumn);
$highestColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($highestColumn) - 1);
}
$this->garbageCollect();
return $this;
}
@@ -2165,7 +2186,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function removeColumnByIndex($columnIndex, $numColumns = 1)
{
@@ -2191,7 +2212,7 @@ class Worksheet implements IComparable
*
* @param bool $pValue Show gridlines (true/false)
*
* @return Worksheet
* @return $this
*/
public function setShowGridlines($pValue)
{
@@ -2215,7 +2236,7 @@ class Worksheet implements IComparable
*
* @param bool $pValue Print gridlines (true/false)
*
* @return Worksheet
* @return $this
*/
public function setPrintGridlines($pValue)
{
@@ -2239,7 +2260,7 @@ class Worksheet implements IComparable
*
* @param bool $pValue Show row and column headers (true/false)
*
* @return Worksheet
* @return $this
*/
public function setShowRowColHeaders($pValue)
{
@@ -2263,7 +2284,7 @@ class Worksheet implements IComparable
*
* @param bool $pValue Show summary below (true/false)
*
* @return Worksheet
* @return $this
*/
public function setShowSummaryBelow($pValue)
{
@@ -2287,7 +2308,7 @@ class Worksheet implements IComparable
*
* @param bool $pValue Show summary right (true/false)
*
* @return Worksheet
* @return $this
*/
public function setShowSummaryRight($pValue)
{
@@ -2311,7 +2332,7 @@ class Worksheet implements IComparable
*
* @param Comment[] $pValue
*
* @return Worksheet
* @return $this
*/
public function setComments(array $pValue)
{
@@ -2392,7 +2413,7 @@ class Worksheet implements IComparable
*
* @param string $pCoordinate Cell (i.e. A1)
*
* @return Worksheet
* @return $this
*/
public function setSelectedCell($pCoordinate)
{
@@ -2404,7 +2425,7 @@ class Worksheet implements IComparable
*
* @param string $pCoordinate Cell range, examples: 'A1', 'B2:G5', 'A:C', '3:6'
*
* @return Worksheet
* @return $this
*/
public function setSelectedCells($pCoordinate)
{
@@ -2424,7 +2445,7 @@ class Worksheet implements IComparable
$pCoordinate = preg_replace('/^(\d+):(\d+)$/', 'A${1}:XFD${2}', $pCoordinate);
if (Coordinate::coordinateIsRange($pCoordinate)) {
list($first) = Coordinate::splitRange($pCoordinate);
[$first] = Coordinate::splitRange($pCoordinate);
$this->activeCell = $first[0];
} else {
$this->activeCell = $pCoordinate;
@@ -2442,7 +2463,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function setSelectedCellByColumnAndRow($columnIndex, $row)
{
@@ -2464,7 +2485,7 @@ class Worksheet implements IComparable
*
* @param bool $value Right-to-left true/false
*
* @return Worksheet
* @return $this
*/
public function setRightToLeft($value)
{
@@ -2483,7 +2504,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function fromArray(array $source, $nullValue = null, $startCell = 'A1', $strictNullComparison = false)
{
@@ -2493,7 +2514,7 @@ class Worksheet implements IComparable
}
// start coordinate
list($startColumn, $startRow) = Coordinate::coordinateFromString($startCell);
[$startColumn, $startRow] = Coordinate::coordinateFromString($startCell);
// Loop through $source
foreach ($source as $rowData) {
@@ -2535,7 +2556,7 @@ class Worksheet implements IComparable
// Returnvalue
$returnValue = [];
// Identify the range that we need to extract from the worksheet
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($pRange);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($pRange);
$minCol = Coordinate::stringFromColumnIndex($rangeStart[0]);
$minRow = $rangeStart[1];
$maxCol = Coordinate::stringFromColumnIndex($rangeEnd[0]);
@@ -2545,11 +2566,11 @@ class Worksheet implements IComparable
// Loop through rows
$r = -1;
for ($row = $minRow; $row <= $maxRow; ++$row) {
$rRef = ($returnCellRef) ? $row : ++$r;
$rRef = $returnCellRef ? $row : ++$r;
$c = -1;
// Loop through columns in the current row
for ($col = $minCol; $col != $maxCol; ++$col) {
$cRef = ($returnCellRef) ? $col : ++$c;
$cRef = $returnCellRef ? $col : ++$c;
// Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen
// so we test and retrieve directly against cellCollection
if ($this->cellCollection->has($col . $row)) {
@@ -2668,7 +2689,7 @@ class Worksheet implements IComparable
/**
* Run PhpSpreadsheet garbage collector.
*
* @return Worksheet
* @return $this
*/
public function garbageCollect()
{
@@ -2768,7 +2789,7 @@ class Worksheet implements IComparable
* @param string $pCellCoordinate Cell coordinate to insert hyperlink, eg: 'A1'
* @param null|Hyperlink $pHyperlink
*
* @return Worksheet
* @return $this
*/
public function setHyperlink($pCellCoordinate, Hyperlink $pHyperlink = null)
{
@@ -2829,7 +2850,7 @@ class Worksheet implements IComparable
* @param string $pCellCoordinate Cell coordinate to insert data validation, eg: 'A1'
* @param null|DataValidation $pDataValidation
*
* @return Worksheet
* @return $this
*/
public function setDataValidation($pCellCoordinate, DataValidation $pDataValidation = null)
{
@@ -2896,9 +2917,8 @@ class Worksheet implements IComparable
$rangeSet = $rangeBoundaries[0][0] . $rangeBoundaries[0][1] . ':' . $rangeBoundaries[1][0] . $rangeBoundaries[1][1];
}
unset($rangeSet);
$stRange = implode(' ', $rangeBlocks);
return $stRange;
return implode(' ', $rangeBlocks);
}
/**
@@ -2918,7 +2938,7 @@ class Worksheet implements IComparable
/**
* Reset tab color.
*
* @return Worksheet
* @return $this
*/
public function resetTabColor()
{
@@ -2941,13 +2961,11 @@ class Worksheet implements IComparable
/**
* Copy worksheet (!= clone!).
*
* @return Worksheet
* @return static
*/
public function copy()
{
$copied = clone $this;
return $copied;
return clone $this;
}
/**
@@ -2994,7 +3012,7 @@ class Worksheet implements IComparable
*
* @throws Exception
*
* @return Worksheet
* @return $this
*/
public function setCodeName($pValue, $validate = true)
{
@@ -3034,7 +3052,7 @@ class Worksheet implements IComparable
}
}
$pValue = $pValue . '_' . $i; // ok, we have a valid name
$pValue .= '_' . $i; // ok, we have a valid name
}
}
}

View File

@@ -147,7 +147,7 @@ class Csv extends BaseWriter
*
* @param string $pValue Delimiter, defaults to ','
*
* @return CSV
* @return $this
*/
public function setDelimiter($pValue)
{
@@ -171,7 +171,7 @@ class Csv extends BaseWriter
*
* @param string $pValue Enclosure, defaults to "
*
* @return CSV
* @return $this
*/
public function setEnclosure($pValue)
{
@@ -198,7 +198,7 @@ class Csv extends BaseWriter
*
* @param string $pValue Line ending, defaults to OS line ending (PHP_EOL)
*
* @return CSV
* @return $this
*/
public function setLineEnding($pValue)
{
@@ -222,7 +222,7 @@ class Csv extends BaseWriter
*
* @param bool $pValue Use UTF-8 byte-order mark? Defaults to false
*
* @return CSV
* @return $this
*/
public function setUseBOM($pValue)
{
@@ -246,7 +246,7 @@ class Csv extends BaseWriter
*
* @param bool $pValue Use separator line? Defaults to false
*
* @return CSV
* @return $this
*/
public function setIncludeSeparatorLine($pValue)
{
@@ -271,7 +271,7 @@ class Csv extends BaseWriter
* @param bool $pValue Set the file to be written as a fully Excel compatible csv file
* Note that this overrides other settings such as useBOM, enclosure and delimiter
*
* @return CSV
* @return $this
*/
public function setExcelCompatibility($pValue)
{
@@ -295,7 +295,7 @@ class Csv extends BaseWriter
*
* @param int $pValue Sheet index
*
* @return CSV
* @return $this
*/
public function setSheetIndex($pValue)
{

View File

@@ -62,6 +62,13 @@ class Html extends BaseWriter
*/
private $useInlineCss = false;
/**
* Use embedded CSS?
*
* @var bool
*/
private $useEmbeddedCSS = true;
/**
* Array of CSS styles.
*
@@ -290,7 +297,7 @@ class Html extends BaseWriter
*
* @param int $pValue Sheet index
*
* @return HTML
* @return $this
*/
public function setSheetIndex($pValue)
{
@@ -314,7 +321,7 @@ class Html extends BaseWriter
*
* @param bool $pValue Flag indicating whether the sheet navigation block should be generated or not
*
* @return HTML
* @return $this
*/
public function setGenerateSheetNavigationBlock($pValue)
{
@@ -325,6 +332,8 @@ class Html extends BaseWriter
/**
* Write all sheets (resets sheetIndex to NULL).
*
* @return $this
*/
public function writeAllSheets()
{
@@ -643,7 +652,10 @@ class Html extends BaseWriter
} else {
$imageDetails = getimagesize($filename);
if ($fp = fopen($filename, 'rb', 0)) {
$picture = fread($fp, filesize($filename));
$picture = '';
while (!feof($fp)) {
$picture .= fread($fp, 1024);
}
fclose($fp);
// base64 encode the binary data, then break it
// into chunks according to RFC 2045 semantics
@@ -888,8 +900,8 @@ class Html extends BaseWriter
$css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = $width . 'pt';
if ($columnDimension->getVisible() === false) {
$css['table.sheet' . $sheetIndex . ' col.col' . $column]['visibility'] = 'collapse';
$css['table.sheet' . $sheetIndex . ' col.col' . $column]['*display'] = 'none'; // target IE6+7
$css['table.sheet' . $sheetIndex . ' .column' . $column]['visibility'] = 'collapse';
$css['table.sheet' . $sheetIndex . ' .column' . $column]['display'] = 'none'; // target IE6+7
}
}
}
@@ -950,15 +962,12 @@ class Html extends BaseWriter
private function createCSSStyle(Style $pStyle)
{
// Create CSS
$css = array_merge(
return array_merge(
$this->createCSSStyleAlignment($pStyle->getAlignment()),
$this->createCSSStyleBorders($pStyle->getBorders()),
$this->createCSSStyleFont($pStyle->getFont()),
$this->createCSSStyleFill($pStyle->getFill())
);
// Return
return $css;
}
/**
@@ -1051,9 +1060,8 @@ class Html extends BaseWriter
{
// Create CSS - add !important to non-none border styles for merged cells
$borderStyle = $this->mapBorderStyle($pStyle->getBorderStyle());
$css = $borderStyle . ' #' . $pStyle->getColor()->getRGB() . (($borderStyle == 'none') ? '' : ' !important');
return $css;
return $borderStyle . ' #' . $pStyle->getColor()->getRGB() . (($borderStyle == 'none') ? '' : ' !important');
}
/**
@@ -1102,7 +1110,9 @@ class Html extends BaseWriter
// Construct HTML
$html = '';
$html .= $this->setMargins($pSheet);
if ($this->useEmbeddedCSS) {
$html .= $this->setMargins($pSheet);
}
if (!$this->useInlineCss) {
$gridlines = $pSheet->getShowGridlines() ? ' gridlines' : '';
@@ -1141,9 +1151,7 @@ class Html extends BaseWriter
*/
private function generateTableFooter()
{
$html = ' </table>' . PHP_EOL;
return $html;
return ' </table>' . PHP_EOL;
}
/**
@@ -1432,7 +1440,7 @@ class Html extends BaseWriter
*
* @param string $pValue
*
* @return HTML
* @return $this
*/
public function setImagesRoot($pValue)
{
@@ -1456,7 +1464,7 @@ class Html extends BaseWriter
*
* @param bool $pValue
*
* @return HTML
* @return $this
*/
public function setEmbedImages($pValue)
{
@@ -1480,7 +1488,7 @@ class Html extends BaseWriter
*
* @param bool $pValue
*
* @return HTML
* @return $this
*/
public function setUseInlineCss($pValue)
{
@@ -1489,6 +1497,30 @@ class Html extends BaseWriter
return $this;
}
/**
* Get use embedded CSS?
*
* @return bool
*/
public function getUseEmbeddedCSS()
{
return $this->useEmbeddedCSS;
}
/**
* Set use embedded CSS?
*
* @param bool $pValue
*
* @return $this
*/
public function setUseEmbeddedCSS($pValue)
{
$this->useEmbeddedCSS = $pValue;
return $this;
}
/**
* Add color to formatted string as inline style.
*
@@ -1538,14 +1570,14 @@ class Html extends BaseWriter
// loop through all Excel merged cells
foreach ($sheet->getMergeCells() as $cells) {
list($cells) = Coordinate::splitRange($cells);
[$cells] = Coordinate::splitRange($cells);
$first = $cells[0];
$last = $cells[1];
list($fc, $fr) = Coordinate::coordinateFromString($first);
[$fc, $fr] = Coordinate::coordinateFromString($first);
$fc = Coordinate::columnIndexFromString($fc) - 1;
list($lc, $lr) = Coordinate::coordinateFromString($last);
[$lc, $lr] = Coordinate::coordinateFromString($last);
$lc = Coordinate::columnIndexFromString($lc) - 1;
// loop through the individual cells in the individual merge

View File

@@ -167,7 +167,7 @@ class Ods extends BaseWriter
*
* @param Spreadsheet $spreadsheet PhpSpreadsheet object
*
* @return self
* @return $this
*/
public function setSpreadsheet(Spreadsheet $spreadsheet)
{

View File

@@ -314,7 +314,7 @@ class Content extends WriterPart
}
if ($size = $font->getSize()) {
$writer->writeAttribute('fo:font-size', sprintf('%.1fpt', $size));
$writer->writeAttribute('fo:font-size', sprintf('%.1Fpt', $size));
}
if ($font->getUnderline() && $font->getUnderline() != Font::UNDERLINE_NONE) {
@@ -383,7 +383,7 @@ class Content extends WriterPart
}
$mergeRange = Coordinate::splitRange($cell->getMergeRange());
list($startCell, $endCell) = $mergeRange[0];
[$startCell, $endCell] = $mergeRange[0];
$start = Coordinate::coordinateFromString($startCell);
$end = Coordinate::coordinateFromString($endCell);
$columnSpan = Coordinate::columnIndexFromString($end[0]) - Coordinate::columnIndexFromString($start[0]) + 1;

View File

@@ -150,7 +150,7 @@ abstract class Pdf extends Html
*
* @param string $fontName
*
* @return Pdf
* @return $this
*/
public function setFont($fontName)
{

Some files were not shown because too many files have changed in this diff Show More